之前写过一篇文字溢出添加气泡效果的文章:《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!