zoukankan      html  css  js  c++  java
  • element notification源码

    index.js

    import Notification from './src/main.js';
    export default Notification;

    src/main.js  

    import Vue from 'vue';
    import Main from './main.vue';
    import { PopupManager } from 'element-ui/src/utils/popup';
    import { isVNode } from 'element-ui/src/utils/vdom';
    const NotificationConstructor = Vue.extend(Main);
    
    let instance;
    let instances = [];
    let seed = 1;
    
    const Notification = function (options) {
      if (Vue.prototype.$isServer) return;
      options = options || {};
      // 自定义关闭
      const userOnClose = options.onClose;
      const id = 'notification_' + seed++;
      // 位置
      const position = options.position || 'top-right';
      // 关闭事件
      options.onClose = function () {
        Notification.close(id, userOnClose);
      };
      // 创建notification实例
      instance = new NotificationConstructor({
        data: options
      });
    
      if (isVNode(options.message)) {
        instance.$slots.default = [options.message];
        options.message = 'REPLACED_BY_VNODE';
      }
      instance.id = id;
      // 挂载
      instance.$mount();
      // 添加到body
      document.body.appendChild(instance.$el);
      // 显示
      instance.visible = true;
      // 设置dom
      instance.dom = instance.$el;
      // 设置z-index
      instance.dom.style.zIndex = PopupManager.nextZIndex();
      // 偏移量
      let verticalOffset = options.offset || 0;
      // 过滤查找,相同位置的notification,每次增加(自身高度+16),避免覆盖
      instances.filter(item => item.position === position).forEach(item => {
        verticalOffset += item.$el.offsetHeight + 16;
      });
      // 最后一个也加16
      verticalOffset += 16;
      // 设置为当前的偏移量
      instance.verticalOffset = verticalOffset;
      // 放入数组
      instances.push(instance);
      // 返回
      return instance;
    };
    // 循环类型为这4个中类型
    ['success', 'warning', 'info', 'error'].forEach(type => {
      // 给Notification增加这几种类型函数
      Notification[type] = options => {
        // 如果是字符串,转变为对象
        if (typeof options === 'string' || isVNode(options)) {
          options = {
            message: options
          };
        }
        // 设置type类型
        options.type = type;
        return Notification(options);
      };
    });
    // 关闭
    Notification.close = function (id, userOnClose) {
      let index = -1;
      const len = instances.length;
      // 过滤,查找id
      const instance = instances.filter((instance, i) => {
        if (instance.id === id) {
          index = i;
          return true;
        }
        return false;
      })[0];
      // 不存在,返回
      if (!instance) return;
      // 找到后有自定义关闭,执行
      if (typeof userOnClose === 'function') {
        userOnClose(instance);
      }
      // 删除
      instances.splice(index, 1);
    
      if (len <= 1) return;
      // 记录instance位置
      const position = instance.position;
      // 记录instance高度
      const removedHeight = instance.dom.offsetHeight;
      // 循环查找位置
      for (let i = index; i < len - 1; i++) {
        if (instances[i].position === position) {
          // 对应的位置减去(本身高度+16)
          instances[i].dom.style[instance.verticalProperty] =
            parseInt(instances[i].dom.style[instance.verticalProperty], 10) - removedHeight - 16 + 'px';
        }
      }
    };
    // 全部关闭
    Notification.closeAll = function () {
      for (let i = instances.length - 1; i >= 0; i--) {
        instances[i].close();
      }
    };
    
    export default Notification;

    src/main.vue

    <template>
      <transition name="el-notification-fade">
        <div
          :class="['el-notification', customClass, horizontalClass]"
          v-show="visible"
          :style="positionStyle"
          @mouseenter="clearTimer()"
          @mouseleave="startTimer()"
          @click="click"
          role="alert"
        >
          <i
            class="el-notification__icon"
            :class="[ typeClass, iconClass ]"
            v-if="type || iconClass">
          </i>
          <div class="el-notification__group" :class="{ 'is-with-icon': typeClass || iconClass }">
            <h2 class="el-notification__title" v-text="title"></h2>
            <div class="el-notification__content" v-show="message">
              <slot>
                <p v-if="!dangerouslyUseHTMLString">{{ message }}</p>
                <p v-else v-html="message"></p>
              </slot>
            </div>
            <div
              class="el-notification__closeBtn el-icon-close"
              v-if="showClose"
              @click.stop="close"></div>
          </div>
        </div>
      </transition>
    </template>
    
    <script type="text/babel">
      let typeMap = {
        success: 'success',
        info: 'info',
        warning: 'warning',
        error: 'error'
      };
    
      export default {
        data() {
          return {
            visible: false,//是否显示
            title: '',//    标题
            message: '',//说明文字
            duration: 4500,//显示时间, 毫秒。设为 0 则不会自动关闭
            type: '',// 主题样式,如果不在可选值内将被忽略
            showClose: true,//是否显示关闭按钮
            customClass: '',//自定义类名
            iconClass: '',//自定义图标的类名。若设置了 type,则 iconClass 会被覆盖
            onClose: null,//关闭时的回调函数
            onClick: null,//点击 Notification 时的回调函数
            closed: false,//是否关闭
            verticalOffset: 0,//偏移的距离,在同一时刻,所有的 Notification 实例应当具有一个相同的偏移量
            timer: null,//定时器
            dangerouslyUseHTMLString: false,//是否将 message 属性作为 HTML 片段处理
            position: 'top-right'//位置
          };
        },
    
        computed: {
          // type类
          typeClass() {
            return this.type && typeMap[this.type] ? `el-icon-${ typeMap[this.type] }` : '';
          },
          // 水平方向上的类
          horizontalClass() {
            return this.position.indexOf('right') > -1 ? 'right' : 'left';
          },
          // 垂直方向上的类名
          verticalProperty() {
            return /^top-/.test(this.position) ? 'top' : 'bottom';
          },
          // 上下的偏移量
          positionStyle() {
            return {
              [this.verticalProperty]: `${ this.verticalOffset }px`
            };
          }
        },
    
        watch: {
          // 监听是否关闭
          closed(newVal) {
            // 关闭
            if (newVal) {
              this.visible = false;
              // 添加transitionend事件
              this.$el.addEventListener('transitionend', this.destroyElement);
            }
          }
        },
    
        methods: {
          destroyElement() {
            // 移除transitionend事件
            this.$el.removeEventListener('transitionend', this.destroyElement);
            this.$destroy(true);
            this.$el.parentNode.removeChild(this.$el);
          },
          // 点击事件
          click() {
            // 如果设置了点击的回调,则执行
            if (typeof this.onClick === 'function') {
              this.onClick();
            }
          },
          // 关闭事件
          close() {
            this.closed = true;
            // 如果设置了点击关闭的回调,则执行
            if (typeof this.onClose === 'function') {
              this.onClose();
            }
          },
          // 清除定时器
          clearTimer() {
            clearTimeout(this.timer);
          },
          // 开启定时器
          startTimer() {
            if (this.duration > 0) {
              this.timer = setTimeout(() => {
                if (!this.closed) {
                  this.close();
                }
              }, this.duration);
            }
          },
          // 键盘按下事件
          keydown(e) {
            if (e.keyCode === 46 || e.keyCode === 8) {
              this.clearTimer(); // detele 取消倒计时
            } else if (e.keyCode === 27) { // esc关闭消息
              if (!this.closed) {
                this.close();
              }
            } else {
              this.startTimer(); // 恢复倒计时
            }
          }
        },
        mounted() {
          // 默认开启定时器
          if (this.duration > 0) {
            this.timer = setTimeout(() => {
              if (!this.closed) {
                this.close();
              }
            }, this.duration);
          }
          // 增加监听
          document.addEventListener('keydown', this.keydown);
        },
        beforeDestroy() {
          // 移除
          document.removeEventListener('keydown', this.keydown);
        }
      };
    </script>
  • 相关阅读:
    HDU1372,BFS象棋马走日
    看完一本小的算法书一个总结吧
    最小生成树Prim
    Junit单元测试的简单使用(主要是在spring框架下的项目)
    并查集
    最新最实用的公式技巧大汇总!
    这款Office密码破解工具,无坚不摧!
    有了它,友谊的船说不翻就不翻!
    Word公式装逼技巧,你绝对不会!
    为什么MathType窗口变灰色
  • 原文地址:https://www.cnblogs.com/wsk1576025821/p/10969447.html
Copyright © 2011-2022 走看看