Vue实现文字自动打点自动添加title气泡效果
需求场景
需求是这样的,表格中有一列信息,字符长度有短有长,最大宽度限制在300px
,溢出自动打点,但是又不想因此导致用户看不全信息,就想在文字溢出打点的时候出现一个悬浮效果,展示出全部的字段,同时对已经展示完全的字段不进行此操作,原本想通过bubble
气泡组件来实现,但是在大量数据面前,这种组件的性能开销过大,最后决定利用html
当中现有的title 属性进行悬浮内容的展示.
实现方式
使用Vue
的自定义指令完成字段是否溢出打点的判断,关键语句在于:
el.offsetWidth < (el.scrollWidth)
其中 offsetWidth
代表的是元素所占据的真实物理像素宽度,这个物理像素在box-sizing: border-box;
样式下就是等于元素的width
属性,在content-box
下 等于 width
+ border-width
请注意你所使用的样式,避免计算误差.scrollWidth
这个只读属性是元素内容宽度的一种度量,包括由于 overflow 溢出而在屏幕上不可见的内容,注意的是,它会对值进行四舍五入取整操作.对比二者的值即可判断出元素是否进行了溢出打点操作.
在指令的inserted
周期调用该判断,同时创建一个**ResizeObserver
**监听器监听元素的resize
事件(比全局监听性能要好),这样可实现动态的title属性增删.
directives: {
tooltip: {
// 指令的定义
inserted: (el, binding) => {
if (el.offsetWidth < (el.scrollWidth)) {
el.title = binding.value.title
}
// 创建一个ResizeObserver监听器监听元素的resize事件
const resizeObserver = new ResizeObserver((entries) => {
entries.forEach(({ target }) => {
if (target.offsetWidth < (target.scrollWidth)) {
target.title = binding.value.title
}else {
target.title = ''
}
})
})
resizeObserver.observe(el)
}
}
},
// use
<p v-tooltip="{'title': message}">{{message}}</p>
效果演示
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#app {
margin-top: 500px;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
p {
font-size: 20px;
max-width: 300px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
}
</style>
</head>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<body>
<div id="app">
<p v-tooltip="{'title': message}" :style="{'maxWidth': num + 'px'}">{{message}}</p>
<button @click="handeChange">change</button>
</div>
<script>
let example1 = new Vue({
el: '#app',
data() {
return {
message: "测试溢出打点出气泡title功能",
num: 500,
}
},
computed: {
title() {
return this.message
}
},
directives: {
tooltip: {
// 指令的定义
inserted: (el, binding) => {
if (el.offsetWidth < (el.scrollWidth)) {
el.title = binding.value.title
}
const resizeObserver = new ResizeObserver((entries) => {
entries.forEach(({ target }) => {
if (target.offsetWidth < (target.scrollWidth)) {
target.title = binding.value.title
} else {
target.title = ''
}
})
})
resizeObserver.observe(el)
}
}
},
methods: {
handeChange() {
if (this.num === 200) {
this.num = 300
} else {
this.num = 200
}
}
}
})
</script>
</body>
</html>