import { h, render, nextTick } from 'vue';
import { ElTooltip } from 'element-plus';
import { ResizeObserverHelper } from '@/utils/resizeObserverHelper.js';
export default {
install (app) {
app.directive('ellipsis-tooltip', {
mounted (el, binding) {
function isTextOverflowedWithEllipsis (element) {
if (!element) return false;
const style = window.getComputedStyle(element);
const isEllipsis = style.textOverflow === 'ellipsis';
const isOverflowHidden = style.overflow === 'hidden';
const isNowrap = style.whiteSpace === 'nowrap';
return isEllipsis && isOverflowHidden && isNowrap &&
element.scrollWidth > element.clientWidth;
}
function updateTooltip () {
el.innerHTML = binding.value
if (isTextOverflowedWithEllipsis(el)) {
const vnode = h(ElTooltip, {
effect: 'dark',
content: binding.value,
placement: 'top-start'
}, {
default: () => h('div', { style: { whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' } }, el.textContent)
});
const container = document.createElement('div')
render(vnode, container)
el.innerHTML = ""
el.appendChild(container);
} else {
el.innerHTML = el.textContent;
}
}
let timer = null
el._resizeObserver = new ResizeObserverHelper(el, (width, height) => {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
updateTooltip();
clearTimeout(timer);
}, 200);
});
},
unmounted (el) {
el._resizeObserver?.disconnect();
}
});
}
};
export class ResizeObserverHelper {
constructor(target, callback, debounceDelay = 200) {
this.target = typeof target === 'string' ? document.querySelector(target) : target;
this.callback = callback;
this.debounceDelay = debounceDelay;
this.debounceTimer = null;
this.resizeObserver = null;
this.init();
}
init() {
if (this.target === window) {
this.handleWindowResize();
return;
}
if (this.target instanceof HTMLElement) {
this.handleElementResize();
return;
}
throw new Error('Invalid target: must be HTMLElement, window, or CSS selector');
}
handleWindowResize() {
const handler = () => {
this.debouncedCallback(window.innerWidth, window.innerHeight);
};
window.addEventListener('resize', handler);
this.disconnect = () => window.removeEventListener('resize', handler);
handler();
}
handleElementResize() {
this.resizeObserver = new ResizeObserver((entries) => {
const { width, height } = entries[0].contentRect;
this.debouncedCallback(width, height);
});
this.resizeObserver.observe(this.target);
this.disconnect = () => this.resizeObserver.disconnect();
}
debouncedCallback = (width, height) => {
clearTimeout(this.debounceTimer);
this.debounceTimer = setTimeout(() => {
this.callback(width, height);
}, this.debounceDelay);
};
disconnect() {
if (this.disconnect) this.disconnect();
clearTimeout(this.debounceTimer);
}
}