[Element Plus 源码解析] Overlay 覆盖层

3,885 阅读1分钟

一、组件介绍

el-overlayelement-plus内部使用的组件,官方文档没有给出此组件的相关描述。

该组件用于弹出一个覆盖层,被用于el-dialogel-messagebox等组件中。

二、源码分析

export default defineComponent({
  name: 'ElOverlay',
  props: {
    // 是否展示掩盖层
    mask: {
      type: Boolean,
      default: true,
    },
    overlayClass: {
      type: [String, Array, Object],
    },
    // 指定覆盖层的Index
    zIndex: {
      type: Number,
    },
  },
  emits: ['click'],
  setup(props, { slots, emit }) {
    // 标识符,当鼠标事件在弹出的mask上触发时置为true
    let mousedownTarget = false
    let mouseupTarget = false

    // 点击事件的触发顺序: mousedown -> mouseup -> click
    // mask点击事件
    const onMaskClick = (e: MouseEvent) => {
      // 当mousedown及mouseup都是在mask元素上触发时,向外抛出click事件
      // 是为了保证点击的行为是在Mask元素上触发的
      //(为什么不直接在这里判断 e.target === e.currentTarget呢?)
      if (mousedownTarget && mouseupTarget) {
        emit('click', e)
      }
      // 重置标识符状态
      mousedownTarget = mouseupTarget = false
    }

    // init here
    return () => {
      return props.mask
        ? createVNode(
          // 展示mask时
          'div',
          {
            class: ['el-overlay', props.overlayClass],
            style: {
              zIndex: props.zIndex,
            },
            // 绑定点击事件
            onClick: onMaskClick,
            onMousedown: (e: MouseEvent) => {
              // props.mask的判断似乎可以去掉,上面已经判断过了
              if (props.mask) {
                // e.currentTarget指的是绑定该事件的元素
                // 当事件触发对象是当前元素时,标识符置为true
                mousedownTarget = e.target === e.currentTarget
              }
            },
            onMouseup: (e: MouseEvent) => {
              if (props.mask) {
                // 同上
                mouseupTarget = e.target === e.currentTarget
              }
            },
          },
          [renderSlot(slots, 'default')],
          PatchFlags.STYLE | PatchFlags.CLASS | PatchFlags.PROPS,
          ['onClick', 'onMouseup', 'onMousedown'],
        )
        // 不展示mask
        : h(
          'div',
          {
            class: props.overlayClass,
            style: {
              zIndex: props.zIndex,
              position: 'fixed',
              top: '0px',
              right: '0px',
              bottom: '0px',
              left: '0px',
            },
          },
          [renderSlot(slots, 'default')],
        )
    }
  },
})

三、总结

  1. 通过mask属性控制是否展示一个mask层;
  2. event.currentTarget表示的是事件绑定的元素,可以使用event.target === event.currentTarget判断事件是否是由注册该事件响应函数的元素触发;
  3. 鼠标点击的事件响应顺序是:mouseDown -> mouseUp-> click;
  4. 这里为啥不在click事件中判断event.target === event.currentTarget呢,而是通过mouseDown和mouseUp事件中设置标志位来做??