toolTip很常见,其实就是一个方框,为了更好的显示自己的内容。
- 并且写这个的方式有很多,可以使用
css伪类来实现,也可以使用自己创建一个div绝对定位来实现。
- 后来因为在写项目中遇到
一些bug: 自己写的绝对定位的div充当的tooltip,把自己的box盒子撑大了(因为你的绝对定位虽然针对你的父级,不占用你的父级的空间,但是你的父级的内容却也会变大,撑开他的父级的空间),然后就变得很尴尬,
- 后来参考
elementUI等一些UI框架的写法,发现他们制作的tooltip, select等等,都是创作在body里的,这样就可以规避,所有空间被撑大的问题都被规避了。
- 但是当时不知道怎么做到的,后来随着不断的学习,发现其实很简单,就是使用
slot和 directives实现的。现在我们就简单做一个 超出box宽度,文字显示...,并且toolTip 显示完整文字。
toolTip.vue
<template>
<div class="tooltip-container" v-tooltipShow="contentStr">
<slot></slot>
<div>
<template/>
<script>
export default {
name:'tooltip',
props: {
content: {
type:String,
required:true
}
},
computed: {
contentStr() {
return this.content;
}
},
directives: {
tooltipShow: {
inserted (el,binding) {
// 创建一个tootip Dom
const tooltipDom = document.createElement('div');
toolTipDom.innerText = binding.value;
toolTipDom.setAttribute('class', 'tool-tip-cus');
toolTipDom.display = 'none';
toolTipDom.position = 'absolute';
toolTipDom['z-index'] = '10000';
toolTipDom.style[''max-width'] = '500px';
toolTipDom.style['background-color'] = '#fff';
toolTipDom.style['word-break'] = 'break-all';
toolTipDom.style.border = '1px solid #eee';
toolTipDom.style['border-radius'] = '8px';
toolTipDom.style.padding = '4px';
toolTipDom.style['font-size'] = '12px';
toolTipDom.style.color = '#616161';
toolTipDom.style.boxShadow = '0px 3px 10px rgba(0,0,0,0.1)';
el.___Mouseover__ = () => {
const {bottom,left,width} = el.getBoundingClientRect();
if(width > el.scrollWidth) return;
toolTipDom.style.display = 'block';
const { width: tooltipWidth } = toolTipDom.getBoundingClientRect();
toolTipDom.style.left = left + width / 2 - (tooltipWidth / 2) + 'px';
toolTipDom.style.top = bottom + 4 + 'px';
};
el.__Mouseout__ = () => {
toolTipDom.style.display = 'none';
};
el.__tooltipDom = toolTipDom;
el.addEventListener('mouseover', el.__Mouseover__);
el.addEventListener('mouseout', el.__Mouseout__);
document.body.appendChild(el.__tooltipDom);
},
unbind (el) {
// 解绑时,去除监听事件和dom
el.removeEventListener('mouseover', el.__Mouseover__);
el.removeEventListener('mouseout', el.__Mouseout__);
document.body.removeChild(el.__tooltipDom);
}
}
}
}
<script/>
view.vue 使用
...
<tool-tip :content="contentText">
<div class="file-box">
{{contentText}}
</div>
</tool-tip>
...
export defualt {
components: {
tooltip: () => import('./tooltip.vue')
}
}
<style scoped lang="scss">
.file-box {
width: 100px;
display:block;
overflow:hidden;
text-overflow:ellipsis;
white-space: nowrap;
}
<style/>
- 需要注意的点:我们为了图省事,使用
el.scrollWidth来判断是否box内容超出了box的width。但是el.scrollWidth是精确到整数位的,但是css判断是否出现...是精确到小数位的,所以存在一些误差,最精准的做法是,模拟一个和[file-box]一摸一样的dom, 添加完文字使其完全撑开后,使用dom.getBoundingClientRect().width(精确到小数位的dom宽度)与原先的[file-box]的clientWidth来对比,就可以精准的计算文字是否超出了box的宽度。