当前位置:   article > 正文

el-table溢出隐藏 鼠标移入显示tooltip逻辑_el-table tooltip

el-table tooltip

el-table溢出隐藏 鼠标移入显示tooltip 逻辑

el-table

文件 element-ui/packages/table/src/table-body.js 截取部分代码

export default {
  render(h) {
    return (
      <table>
        <tbody>
          {/* 表格内容 ... */}
          {/* 一个表格 只渲染一个 tooltip */}
          <el-tooltip effect={this.table.tooltipEffect} placement="top" ref="tooltip" content={this.tooltipContent}></el-tooltip>
        </tbody>
      </table>
    );
  },
  created() {
    this.activateTooltip = debounce(50, tooltip => tooltip.handleShowPopper());
  },
  methods: {
    handleCellMouseEnter(event, row) {  // 鼠标移入表格项 触发事件
      const table = this.table;
      const cell = getCell(event);

      if (cell) {
        const column = getColumnByCell(table, cell);
        const hoverState = table.hoverState = { cell, column, row };
        table.$emit('cell-mouse-enter', hoverState.row, hoverState.column, hoverState.cell, event);
      }
      // 判断是否text-overflow, 如果是就显示tooltip
      const cellChild = event.target.querySelector('.cell');
      if (!(hasClass(cellChild, 'el-tooltip') && cellChild.childNodes.length)) {
        return;
      }
      // use range width instead of scrollWidth to determine whether the text is overflowing
      // to address a potential FireFox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1074543#c3
      const range = document.createRange();
      range.setStart(cellChild, 0);
      range.setEnd(cellChild, cellChild.childNodes.length);
      const rangeWidth = range.getBoundingClientRect().width;
      const padding = (parseInt(getStyle(cellChild, 'paddingLeft'), 10) || 0) +
        (parseInt(getStyle(cellChild, 'paddingRight'), 10) || 0);
      if ((rangeWidth + padding > cellChild.offsetWidth || cellChild.scrollWidth > cellChild.offsetWidth) && this.$refs.tooltip) {
        // 1. 判断: 如果宽度溢出
        const tooltip = this.$refs.tooltip;
        // TODO 会引起整个 Table 的重新渲染,需要优化
        this.tooltipContent = cell.innerText || cell.textContent; // 2. 表格项内容 赋值给 tooltip显示
        tooltip.referenceElm = cell;  // 3. 替换referenceElm, tooltip通过Popper.js 计算显示的tooltip和referenceElm的相对位置
        tooltip.$refs.popper && (tooltip.$refs.popper.style.display = 'none');
        tooltip.doDestroy();	// 取消tooltip上一系列绑定事件
        tooltip.setExpectedState(true);
        this.activateTooltip(tooltip);  // 4. 显示tooltip
      }
    },
    handleCellMouseLeave(event) { // 鼠标溢出表格项 触发事件
      const tooltip = this.$refs.tooltip;
      if (tooltip) {
        tooltip.setExpectedState(false);
        tooltip.handleClosePopper();  // 隐藏tooltip
      }
      const cell = getCell(event);
      if (!cell) return;

      const oldHoverState = this.table.hoverState || {};
      this.table.$emit('cell-mouse-leave', oldHoverState.row, oldHoverState.column, oldHoverState.cell, event);
    },
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

记录点

  1. 鼠标事件
    mouseenter/mouseleave(新),mouseover/mouseout(旧)
    新的鼠标移入移出事件,去掉了冒泡和捕获的特性
    • mouseenter:鼠标第一次移动到元素区域时触发 (新)
    • mouseleave:移出时触发(新)
    • mousemove:在元素上移动时触发(一直触发)
    • mouseover:鼠标移动到元素上时触发(旧)
    • mouseout:从元素上移开时触发(旧)
  2. 步骤
    • el-tooltiptbody的子节点,一个表格,只渲染一个 el-tooltip
    • 监听鼠标移入事件 mouseenter,判断表格项内容是否溢出
    • 如果溢出
      • 表格项内容赋值给 tooltipContent 显示隐藏内容
      • 替换referenceElm, tooltip通过 Popper.js 计算显示的 tooltipreferenceElm 的相对位置
      • 显示 tooltip
    • 监听鼠标移开事件 mouseleave,隐藏 tooltip

el-tooltip

文件 element-ui/packages/tooltip/src/main.js 截取部分代码

const PopperJS = require('element-ui/src/utils/popper.js');
export default {
  beforeCreate() {
    this.popperVM = new Vue({
      data: { node: '' },
      render(h) {
        return this.node;
      }
    }).$mount();
    this.debounceClose = debounce(200, () => this.handleClosePopper());
  },
  render(h) {
    if (this.popperVM) {
      this.popperVM.node = (
        <transition
          name={ this.transition }
          onAfterLeave={ this.doDestroy }>
          <div
            onMouseleave={ () => { this.setExpectedState(false); this.debounceClose(); } }
            onMouseenter= { () => { this.setExpectedState(true); } }
            ref="popper"
            role="tooltip"
            id={this.tooltipId}
            aria-hidden={ (this.disabled || !this.showPopper) ? 'true' : 'false' }
            v-show={!this.disabled && this.showPopper}
            class={
              ['el-tooltip__popper', 'is-' + this.effect, this.popperClass]
            }>
            {/* 具名插槽 content 渲染在tooltip */}
            { this.$slots.content || this.content }
          </div>
        </transition>);
    }

    const firstElement = this.getFirstElement();  
    if (!firstElement) return null;

    const data = firstElement.data = firstElement.data || {};
    data.staticClass = this.addTooltipClass(data.staticClass);

    return firstElement;  // 找到默认插槽 default 显示在组件位置
  },
  mounted() {
    this.referenceElm = this.$el;
    // 给 referenceElm 绑定一系列事件, 包括: mouseenter mouseleave
    // ...
    
    if (this.value && this.popperVM) {
      this.popperVM.$nextTick(() => {
        if (this.value) {
          this.updatePopper();
        }
      });
    }
  },
  methods: {
    updatePopper() {
      const popperJS = this.popperJS;
      if (popperJS) {
        popperJS.update();
        if (popperJS._popper) {
          popperJS._popper.style.zIndex = PopupManager.nextZIndex();
        }
      } else {
        this.createPopper();
      }
    },
    createPopper() { // 省略...只剩下需要的逻辑
      let reference = this.referenceElm = this.referenceElm || this.reference || this.$refs.reference;
      const popper = this.popperElm = this.popperElm || this.popper || this.$refs.popper; // 提示信息ref 对应的DOM
      const options = this.popperOptions;

      if (!popper || !reference) return;
      if (this.appendToBody) document.body.appendChild(this.popperElm); // 渲染在body节点下
      /**
       * reference: 默认插槽/鼠标移入移出显示tooltip相对的元素
       * popper: 提示信息ref 对应的DOM (tooltip)
       * option: 一些配置
       */
      this.popperJS = new PopperJS(reference, popper, options);
      // ...
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84

记录点:

  1. render
    1. 找到默认插槽 default 显示在组件位置
    2. 提示信息:transition + 具名插槽 content,鼠标移入referenceElm,显示提示信息
  2. mounted:给 referenceElm 绑定一系列事件, 包括: mouseentermouseleave,调用 updatePopper
  3. 调用 createPopper
    1. 通过 Popper.js 计算显示的 提示信息 和 referenceElm 的相对位置
    2. 关键代码:this.popperJS = new PopperJS(reference, popper, options);
      • reference: 默认插槽/referenceElm,鼠标移入移出显示 提示信息 相对的元素
      • popper: 提示信息ref 对应的DOM (tooltip)
      • option: 一些配置
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/91874
推荐阅读
相关标签
  

闽ICP备14008679号