文章目录
- 1. 思路及原理概述
- 2. 引入依赖
- 3. 组件实现
- 4. 使用示例
- 5. 说明
组件基于的
element ui
实现;
el-tooltip
本身不支持按照文本长度进行自适应显示; 因此在文本长度较短时弹出tip会显得怪怪的;
el-tooltip
1. 思路及原理概述
在
element ui
中,
el-table
是实现了单元格的长度自适应的, 使用过程中也比较流畅; 因此, 根据
el-table
的源码进行改造;
源码路径:
\element-ui\packages\table\src\table-body.js
方法:
handleCellMouseEnter(event, row)
以及
handleCellMouseLeave(event)
原理: 通过
mouseEnter
和
mouseLeave
事件监听元素宽度, 从而计算是否显示
tooltip
2. 引入依赖
import { getStyle } from '@/utils/dom'
import { debounce } from 'throttle-debounce'
说明:
-
从dom.js
中提取, 源码路径:element ui
, (看他写得挺复杂的, 就不自己造轮子了)\element-ui\src\utils\dom.js
-
直接安装即可:throttle-debounce
npm install throttle-debounce --save
3. 组件实现
<template>
<div class="self-popover-main">
<div
class="self-popover-content"
@mouseenter="handleMouseEnter"
@mouseleave="handleMouseLeave"
>
<slot />
</div>
<el-tooltip
v-show="popText !== ''"
ref="tooltip"
:content="popText"
:effect="effect"
:placement="placement"
:visible-arrow="visibleArrow"
:popper-class="popperClass"
/>
</div>
</template>
<script>
import { getStyle } from '@/utils/dom'
import { debounce } from 'throttle-debounce'
// 兼容子节点样式, 参见 controlledClazzList;
// 当子节点样式不存在时, 使用 self-popover-content来进行判断
export default {
name: 'SelfTooltip',
props: {
placement: {
type: String,
default: 'top'
},
visibleArrow: {
type: Boolean,
default: false
},
popperClass: {
type: String,
default: ''
},
effect: {
type: String,
default: 'light'
}
},
data() {
return {
popText: '',
controlledClazzList: ['self-tooltip', 'with-popover']
}
},
created() {
this.activateTooltip = debounce(50, tooltip => tooltip.handleShowPopper())
},
methods: {
handleMouseEnter: function(event) {
const target = event.target
// 判断是否text-overflow, 如果是就显示tooltip
let child = target
for (const clazz of this.controlledClazzList) {
const tmp = target.querySelector(`.${clazz}`)
if (tmp) {
child = tmp
break
}
}
let heightFlag = false
if (child.scrollHeight > child.offsetHeight) {
heightFlag = true
}
// use range width instead of scrollWidth to determine whether the text is overflowing
// to address a potential FireFox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1074543#c3
const range = document.createRange()
range.setStart(child, 0)
range.setEnd(child, child.childNodes.length)
const rangeWidth = range.getBoundingClientRect().width // 文本区域宽度
const padding = (parseInt(getStyle(target, 'paddingLeft'), 10) || 0) +
(parseInt(getStyle(target, 'paddingRight'), 10) || 0)
if ((rangeWidth + padding > target.offsetWidth || child.scrollWidth > child.offsetWidth) || heightFlag && this.$refs.tooltip) {
const tooltip = this.$refs.tooltip
// TODO 会引起整个 Table 的重新渲染,需要优化
this.popText = target.innerText || target.textContent
tooltip.referenceElm = target
tooltip.$refs.popper && (tooltip.$refs.popper.style.display = 'none')
tooltip.doDestroy()
tooltip.setExpectedState(true)
this.activateTooltip(tooltip)
}
},
handleMouseLeave: function(event) {
const tooltip = this.$refs.tooltip
if (tooltip) {
tooltip.setExpectedState(false)
tooltip.handleClosePopper()
this.popText = ''
}
}
}
}
</script>
<style lang="scss" scoped>
@mixin overflow-hide {
overflow: hidden;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
word-break: break-word;
white-space: nowrap;
}
.self-popover-content {
@include overflow-hide;
div {
@include overflow-hide;
}
}
</style>
4. 使用示例
<self-tooltip placement="top" effect="light" :visible-arrow="false" popper-class="upload-file-pop">
<div class="file_name">{{ uploadProcess.name }}</div>
</self-tooltip>
5. 说明
- 组件支持自定义适配样式, 只需要在
中配置即可;controlledClazzList
- 组件支持无样式匹配(即插槽中的根元素可以不配置
中的样式), 同时 插槽支持controlledClazzList
;div
- 样式使用了
, 可自行翻译成标准scss
;css