基于el-tooltip二次封装的tool-tip-ellipsis全局气泡提示
输出背景
el-select下拉组件中的el-option,通常有多个,需要遍历出来,也有做成滚动加载更多el-option的。这些el-option显示的内容可能会很长,如果不作处理,下拉框会拉的很长,这时候就可能需要实现缺省显示(超出长度的显示…),当鼠标移上去的时候就显示完整的内容。
一般的做法是el-option中先用css实现缺省显示,然后再给遍历出来的每一个el-option都加一个el-tooltip。这样的优点是快,且简单,缺点是每一个el-option,都会生成一个对应的el-tooltip,相当于一对一的关系。也就是说,如果你遍历了100个el-option,然后你又都用鼠标hover了一遍,那就会生成100个el-tooltip插入到文档中,看下图。
上图有6个元素加了el-tooltip,全都hover了一遍,控制台可以看到生成了6个div
优化方案
1、全局(vuex)共用一个el-tooltip实例globalTemplateToolTip,这是个容器。
2、再写一个触发globalTemplateToolTip显示的组件tool-tip-ellipsis,调用这个组件是,会把你想要显示的内容放到globalTemplateToolTip。用这个组件代替平时写的el-tooltip,而这个组件的工作就是在内部改变el-tooltip的触发方式,使其hover时不再额外生成新的dom。
3、只有文本溢出时才显示el-tooltip的hover内容。利用css样式并结合js来判断文本是否溢出。
话不多说,开始
1、el-tooltip容器
先全局挂在,比如放到APP.vue里,根据自己的项目结构做调整
APP.vue
<router-view v-if="isRouterAlive" />
<global-template-tool-tip></global-template-tool-tip>
import globalTemplateToolTip from '@/components/tool-tip'
Tool-tip.vue
<template>
<el-tooltip ref="globalTemplateTip" :content="toolTipContent" :placement="toolTipPlacement"></el-tooltip>
</template>
mounted() {
this.$store.commit(‘MOUNT_TOOL_TIP', this.$refs.globalTemplateTip)
}
MOUNT_TOOL_TIP(state, node) {
state.toolTip = node
},
2、封装el-tooltip组件(这个是直接在组件中使用的,上面的是容器,用来存放hover出来的气泡提示的)
tool-tip-ellipsis.vue
<template>
<div @mouseenter="tipBoxEnter($event)" @mouseleave="tipBoxLeave($event)">
<p :class="['too-tip-content-p', optionMaxWidth ? 'max-width-' + optionMaxWidth : '']">
<slot></slot>
</p>
</div>
</template>
<script>
export default {
props: {
// 最大宽度,可忽略
optionMaxWidth: {
type: Number
},
// 内容
toolTipContent: {
type: String,
default: ''
},
// 位置
placement: {
type: String,
default: 'bottom'
}
},
methods: {
tipBoxEnter(e) {
// 获取挂载的p标签
let p_Node = e.target.querySelector('.too-tip-content-p')
// 如果文本溢出
if (p_Node.scrollWidth > p_Node.offsetWidth) {
// 初始化全局toolTip
this.$store.commit('INIT_TOOL_TIP', {
node: p_Node,
content: this.toolTipContent,
placement: this.placement
})
}
},
tipBoxLeave(e) {
// 销毁toolTip
this.$store.commit('CLOSE_TOOL_TIP')
}
}
}
</script>
<style lang="scss" scoped>
.too-tip-content-p {
padding: 0;
margin: 0;
text-overflow: ellipsis;
overflow: hidden;
}
</style>
上面的max-width-xxx的类名是使用scss的循环、占位符等实现的。
请注意,这样写会生成大量的类名,打包出的css文件会变大,慎用。
// 最大宽度
$max_width_i: 1000;
$maxWidthList: ();
@while $max_width_i>0 {
$maxWidthList: append($maxWidthList, $max_width_i, comma);
$max_width_i: $max_width_i - 1;
}
@each $len in $maxWidthList {
%max-width-#{$len} {
max-width: #{$len}px;
}
.max-width-#{$len} {
@extend %max-width-#{$len};
}
}
vuex
// 初始化
INIT_TOOL_TIP(state, obj) {
state.toolTip.referenceElm = obj.node
// 先消掉之前的
state.toolTip.$refs.popper && (state.toolTip.$refs.popper.style.display = 'none')
state.toolTip.doDestroy()
// 设置组件内的条件变量为true,否则无法调用handleClosePopper
state.toolTip.setExpectedState(true)
// 展示新的tool-tip
activateTooltip(state.toolTip)
// 填入内容
state.toolTipContent = content
// 设置位置
state.toolTipPlacement = placement
},
// 关闭
CLOSE_TOOL_TIP(state) {
state.toolTip.setExpectedState(false)
state.toolTip.handleClosePopper()
}
toolTip源码
使用
<el-option
v-for="(option, optIndex) in self_list"
:key="optIndex + '-' + option.id"
:label="option[dictLabel] || '—'"
:value="option"
>
<toolTipEllipsis
:optionMaxWidth="200"
:toolTipContent="option.content
:placement="'top-start'"
>
{{ option.content }}
</toolTipEllipsis>
</el-option>
import toolTipEllipsis from '@/components/tool-tip-ellipsis/index’
效果
总结
挺有意思的一次尝试,希望能帮到有需要的人。为了不显得冗长,节省了很多代码,有不当之处,欢迎指出!
参考链接:
https://blog.csdn.net/sgabon/article/details/106426738