vue+element-Popover封装判别文字溢出添加气泡效果的自定义指令V2.0

1,037 阅读1分钟

之前写过一篇文字溢出添加气泡效果的文章:《vue+element-Popover封装判别文字溢出添加气泡效果的自定义指令》,随着实践的捶打,发现之前的实现方式对性能影响较大,特别是页面大量使用气泡指令,所以近期对指令做了一些优化更改,优化之后效果还是很明显的,图示示例是渲染1000个带气泡指令的标签,效果直接上图:

优化前:

优化后:

优化前我们对于所有添加指令的元素都统一apendchild气泡的dom元素,这显然是没有必要的,这么做的后果会导致页面渲染太多无用的dom元素,因此此次优化最大的工作就是减少无用的dom渲染。

本来是打算在update中做一些操作的,但是考虑到有些页面有定时器轮询调用接口,会一直触发update带来不必要的开销,最终选择在bind中绑定鼠标移入之间,动态判断是否增加气泡,开发过程还是耗了一些时间的,走了一些弯路,踩了一些坑,好在结果暂时是满意的。优化时逻辑梳理:

跟之前的气泡相比,主要改动了两个文件:popper.js、popper.vue,具体代码如下:

popper.js:

import Vue from "vue"
import Popper from "./popper.vue"

const PopperIcon = Vue.extend(Popper)

function trigger(params) {
    let {el, binding} = params;
    if((el.style["-webkit-line-clamp"] && el.scrollHeight > el.offsetHeight) || el.scrollWidth > el.offsetWidth) {
        if(!el.instance || (el.instance && el.instance._isDestoryed)) {
            const popper = new PopperIcon({
                el: document.createElement("div"),
                data(){}
            })
            el.innerText = "";
            el.appendChild(popper.$el);
            el.instance = popper;
            el.instance.content = binding.value.content || "";
            el.instance.popperText = binding.value.popperText || "";
            el.instance.title = binding.value.title || "";
            el.instance.width = binding.value.width || 200;
            el.instance.placement = binding.value.placement || "top-start";
            el.instance.trigger = binding.value.trigger || "hover";
            el.instance.style = {...el.style};
        }
    } else {
        el.innerText = binding.value.content || "";
        el.instance && el.instance.$destroy();
    }
}

export default {
    inserted: function(el, binding) {
        if(!el.innerText) {
            el.innerText = binding.value.content || "";
        }
    },
    bind: function(el,binding){
        el.onmouseover = function() {
            if(el.instance) {
                if(!el.instance._isDestoryed) {
                    let currentEl = el.querySelector("#popper-text");
                    if(currentEl.style["-webkit-line-clamp"] && !(currentEl.scrollHeight > currentEl.offsetHeight)) {
                        el.innerText = binding.value.content || "";
                        el.instance&&el.instance.$destroy();
                    }
                    if(!currentEl.style["-webkit-line-clamp"] && !(currentEl.scrollWidth > currentEl.offsetWidth)) {
                        el.innerText = binding.value.content || "";
                        el.instance && el.instance.$destroy();
                    }
                } else {
                    trigger({el, binding})
                }
                return;
            }
            trigger({el, binding})
        }
    },
    unbind: function(el){
        el.onmouseover = null;
        el.instance && el.instance.$destroy();
    }
}

popper.vue:

<template>
  <el-popover
    :placement="placement"
    :title="title"
    :width="width"
    :trigger="trigger"
    :content="content"
    :disabled="disabled"
  >
    <div
      slot="reference"
      id="popper-text"
      class="popper-text"
      :style="style"

    >
      {{ popperText }}
    </div>
  </el-popover>
</template>
<script>
export default {
  data() {
    return {
      content: "",
      popperText: "",
      title: "",
      width: 0,
      placement: "top-start",
      trigger: "hover",
      style: {},
      disabled: false,
    };
  },
};
</script>

指令入口文件index.js保持原样

import Popper from "./popper.js"
export default {
    install(Vue) {
        Vue.directive("popper", Popper)
    },
  }

后面如果还有优化会及时更新。

TIME!