赞
踩
文件 element-ui/packages/table/src/table-body.js
截取部分代码
export default { render(h) { return ( <table> <tbody> {/* 表格内容 ... */} {/* 一个表格 只渲染一个 tooltip */} <el-tooltip effect={this.table.tooltipEffect} placement="top" ref="tooltip" content={this.tooltipContent}></el-tooltip> </tbody> </table> ); }, created() { this.activateTooltip = debounce(50, tooltip => tooltip.handleShowPopper()); }, methods: { handleCellMouseEnter(event, row) { // 鼠标移入表格项 触发事件 const table = this.table; const cell = getCell(event); if (cell) { const column = getColumnByCell(table, cell); const hoverState = table.hoverState = { cell, column, row }; table.$emit('cell-mouse-enter', hoverState.row, hoverState.column, hoverState.cell, event); } // 判断是否text-overflow, 如果是就显示tooltip const cellChild = event.target.querySelector('.cell'); if (!(hasClass(cellChild, 'el-tooltip') && cellChild.childNodes.length)) { return; } // 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(cellChild, 0); range.setEnd(cellChild, cellChild.childNodes.length); const rangeWidth = range.getBoundingClientRect().width; const padding = (parseInt(getStyle(cellChild, 'paddingLeft'), 10) || 0) + (parseInt(getStyle(cellChild, 'paddingRight'), 10) || 0); if ((rangeWidth + padding > cellChild.offsetWidth || cellChild.scrollWidth > cellChild.offsetWidth) && this.$refs.tooltip) { // 1. 判断: 如果宽度溢出 const tooltip = this.$refs.tooltip; // TODO 会引起整个 Table 的重新渲染,需要优化 this.tooltipContent = cell.innerText || cell.textContent; // 2. 表格项内容 赋值给 tooltip显示 tooltip.referenceElm = cell; // 3. 替换referenceElm, tooltip通过Popper.js 计算显示的tooltip和referenceElm的相对位置 tooltip.$refs.popper && (tooltip.$refs.popper.style.display = 'none'); tooltip.doDestroy(); // 取消tooltip上一系列绑定事件 tooltip.setExpectedState(true); this.activateTooltip(tooltip); // 4. 显示tooltip } }, handleCellMouseLeave(event) { // 鼠标溢出表格项 触发事件 const tooltip = this.$refs.tooltip; if (tooltip) { tooltip.setExpectedState(false); tooltip.handleClosePopper(); // 隐藏tooltip } const cell = getCell(event); if (!cell) return; const oldHoverState = this.table.hoverState || {}; this.table.$emit('cell-mouse-leave', oldHoverState.row, oldHoverState.column, oldHoverState.cell, event); }, } }
记录点
mouseenter
/mouseleave
(新),mouseover
/mouseout
(旧)el-tooltip
是 tbody
的子节点,一个表格,只渲染一个 el-tooltip
mouseenter
,判断表格项内容是否溢出referenceElm
, tooltip通过 Popper.js
计算显示的 tooltip
和 referenceElm
的相对位置mouseleave
,隐藏 tooltip文件 element-ui/packages/tooltip/src/main.js
截取部分代码
const PopperJS = require('element-ui/src/utils/popper.js'); export default { beforeCreate() { this.popperVM = new Vue({ data: { node: '' }, render(h) { return this.node; } }).$mount(); this.debounceClose = debounce(200, () => this.handleClosePopper()); }, render(h) { if (this.popperVM) { this.popperVM.node = ( <transition name={ this.transition } onAfterLeave={ this.doDestroy }> <div onMouseleave={ () => { this.setExpectedState(false); this.debounceClose(); } } onMouseenter= { () => { this.setExpectedState(true); } } ref="popper" role="tooltip" id={this.tooltipId} aria-hidden={ (this.disabled || !this.showPopper) ? 'true' : 'false' } v-show={!this.disabled && this.showPopper} class={ ['el-tooltip__popper', 'is-' + this.effect, this.popperClass] }> {/* 具名插槽 content 渲染在tooltip */} { this.$slots.content || this.content } </div> </transition>); } const firstElement = this.getFirstElement(); if (!firstElement) return null; const data = firstElement.data = firstElement.data || {}; data.staticClass = this.addTooltipClass(data.staticClass); return firstElement; // 找到默认插槽 default 显示在组件位置 }, mounted() { this.referenceElm = this.$el; // 给 referenceElm 绑定一系列事件, 包括: mouseenter mouseleave // ... if (this.value && this.popperVM) { this.popperVM.$nextTick(() => { if (this.value) { this.updatePopper(); } }); } }, methods: { updatePopper() { const popperJS = this.popperJS; if (popperJS) { popperJS.update(); if (popperJS._popper) { popperJS._popper.style.zIndex = PopupManager.nextZIndex(); } } else { this.createPopper(); } }, createPopper() { // 省略...只剩下需要的逻辑 let reference = this.referenceElm = this.referenceElm || this.reference || this.$refs.reference; const popper = this.popperElm = this.popperElm || this.popper || this.$refs.popper; // 提示信息ref 对应的DOM const options = this.popperOptions; if (!popper || !reference) return; if (this.appendToBody) document.body.appendChild(this.popperElm); // 渲染在body节点下 /** * reference: 默认插槽/鼠标移入移出显示tooltip相对的元素 * popper: 提示信息ref 对应的DOM (tooltip) * option: 一些配置 */ this.popperJS = new PopperJS(reference, popper, options); // ... } } }
记录点:
default
显示在组件位置transition
+ 具名插槽 content
,鼠标移入referenceElm
,显示提示信息mouseenter
、mouseleave
,调用 updatePopper
createPopper
Popper.js
计算显示的 提示信息 和 referenceElm 的相对位置this.popperJS = new PopperJS(reference, popper, options);
referenceElm
,鼠标移入移出显示 提示信息 相对的元素Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。