• 如何写一个全局的 Notice 组件?


    下面将会实现这样的效果:image

    1. 组件动态创建脚本:

      NotificationBanner.js

      import Vue from "vue";
      import Notice from "@/components/Noticer/Notice.vue";
      
      function create(Component, props) {
        // 先建立实例
        const vm = new Vue({
          render(h) {
            //h就是createElement,它返回VNode
            return h(Component, { props });
          },
        }).$mount();
        // 手动挂载
      
        // 判断是否存在container,如果不存在则先创建
        let container;
        container = document.querySelector(".noticer-container");
        if (container == null) {
          container = document.createElement("div");
          container.classList.add("noticer-container");
          container.style.position = "fixed";
          container.style.top = "50px";
          container.style.right = "0px";
          container.style.overflow = "hidden";
          container.style.zIndex = 9999;
      
          document.body.appendChild(container);
        }
      
        container.appendChild(vm.$el);
      
        //销毁方法
        const comp = vm.$children[0];
        comp.remove = function () {
          container.removeChild(comp["$el"]);
          vm.$destroy();
        };
        comp.show();
        return comp;
      }
      
      Vue.prototype.$notice = {
        error: function (props) {
          create(Notice, Object.assign(props, { type: "error" }));
        },
        info: function (props) {
          create(Notice, Object.assign(props, { type: "info" }));
        },
        success: function (props) {
          create(Notice, Object.assign(props, { type: "success" }));
        },
        warn: function (props) {
          create(Notice, Object.assign(props, { type: "warn" }));
        },
      };
      
      

      这里有一些值得注意的地方:

      1. container: 的作用是notice的容器,它可以用于定位notice在页面的哪里展示,注意notice不应该随页面卷动,因此其定位是fixed, 而之所以设定为 overflow:hidden 的原因则是,notice 在出现和移除的时候,发生的动画偏移,会让页面出现横向滚动条。为了避免重复创建container, 这里做了一个判断逻辑。然后所有动态生成的notice实例dom都会通过 appendChild 添加到这个容器。
      2. 在移除的时候, 移除的是 vm.$children[0]["$el"] , 原因是,Notice 模板的实现中,外层套了一个 transition , 而这个transition是并不会渲染dom的。
    2. 创建Notice组件模板:

      组件模板

      <template>
        <transition
          enter-active-class="animate__animated animate__slideInRight"
          leave-active-class="animate__animated animate__slideOutRight"
          @after-leave="afterLeave"
        >
          <div v-if="isShow" class="notice__root">
            <div :class="`notice-type-${type}`" class="noticer">
              {{
                type === "error"
                  ? "&#127827;"
                  : type === "success"
                  ? "&#127808;"
                  : type === "warn"
                  ? "&#127819;"
                  : "&#128051;"
              }}
              : {{ message }}
            </div>
          </div>
        </transition>
      </template>
      <script>
      export default {
        props: {
          title: {
            type: String,
            default: "",
          },
          message: {
            type: String,
            default: "",
          },
          time: {
            type: Number,
            default: 1000,
          },
          type: {
            type: String,
          },
        },
        data() {
          return {
            isShow: false,
          };
        },
        methods: {
          show() {
            this.isShow = true;
            setTimeout(this.hide, this.time);
          },
          hide() {
            this.isShow = false;
          },
          afterLeave() {
            this.remove();
          },
        },
      };
      </script>
      <style lang="less" scoped>
      @error: rgb(255, 30, 30);
      @warn: rgb(240, 192, 0);
      @success: rgb(0, 144, 74);
      @info: rgb(0, 80, 218);
      
      @errorBg: rgb(255, 208, 208);
      @warnBg: rgb(255, 245, 207);
      @successBg: rgb(210, 255, 233);
      @infoBg: rgb(203, 222, 255);
      
      .notice__root {
        user-select: none;
        padding: 5px 50px 5px 5px;
      }
      
      .noticer {
        padding: 5px 20px;
        margin: 10px 0px;
        // margin-right: 50px;
        border-radius: 8px;
        font-size: 16px;
         auto;
        min- 280px;
        max- 300px;
        word-break: break-all;
        text-align: center;
        box-sizing: border-box;
      }
      .notice-type-error {
        color: @error !important;
        border: 2px solid @error;
        box-shadow: 1px 1px 5px 2px @errorBg;
        background-color: @errorBg;
      
        // border: 1px solid red;
      }
      .notice-type-warn {
        color: @warn !important;
        border: 2px solid @warn;
        background-color: @warnBg;
        box-shadow: 1px 1px 5px 2px @warnBg;
      }
      .notice-type-success {
        color: @success !important;
        border: 2px solid @success;
        background-color: @successBg;
        box-shadow: 1px 1px 5px 2px @successBg;
      }
      .notice-type-info {
        color: @info !important;
        border: 2px solid @info;
        background-color: @infoBg;
        box-shadow: 1px 1px 5px 2px @infoBg;
      }
      </style>
      
    3. main.js 中引入执行该脚本即可

      import Vue from "vue";
      import App from "./App.vue";
      import "animate.css";
      import "@/components/Noticer/NotificationBanner.js";
      
      
      new Vue({
        render: (h) => h(App),
      }).$mount("#app");
      
    4. 代码中使用实例:

      if (!this.nickname) {
          this.$notice.error({
              message: "好汉!姓甚名谁?",
              time: 3000,
          });
      } else {
          this.showModal = false;
          this.$notice.info({
              message: this.nickname + "来了!!!",
              time: 3000,
          });
      }
      

    动态创建组件的执行逻辑:
    当在使用的时候:

    this.$notice.error({
        message: "好汉!姓甚名谁?",
        time: 3000,
    });
    

    上方代码触发,实际上会触发 NotificationBanner.js 中的 create函数,该函数创建了一个notice 的组件实例,并在实力上添加了一个remove 方法,然后直接触发组件中的 show 方法。

    notice 模板实例中:

    methods: {
        show() {
            this.isShow = true;
            setTimeout(this.hide, this.time);
        },
        hide() {
            this.isShow = false;
        },
        afterLeave() {
            this.remove();
        },
    },
    

    show 方法执行,除了展示 notice,立即设定一个延时函数执行 hide 方法。

    hide 方法执行, vue 提供的 transition 钩子 afterleave() 会在移除动画执行完毕后触发。 这时候,去触发 remove 方法,将该notice 组件实例移除。

  • 相关阅读:
    分布式系统简介
    java.lang.Object 之 clone() 深拷贝,浅拷贝
    粉丝裂变活动bug
    遇到的bug
    移动端fixed定位在底部,出现键盘后消失
    窗口关闭,打开新页面,刷新等总结
    input 手机数字键盘
    正则重温(学习笔记)
    input的表单验证(不断更新中~~)
    css 不大常见的属性(不断更新中...)
  • 原文地址:https://www.cnblogs.com/jaycethanks/p/16362907.html
Copyright © 2020-2023  润新知