123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- /*
- 文档来源 https://blog.csdn.net/weixin_41277748/article/details/138855857
- 代码来源 https://github.com/DearWQ/wq-admin-system/blob/main/src/directive/toolTip/MyToolTip.vue
- */
- // 引入组件
- import {createApp, nextTick} from "vue";
- import MyToolTip from './index.vue'
- function getViewportSize() {
- return {
- windowWidth: window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,
- windowHeight: window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
- };
- }
- let windowWidth = getViewportSize().windowWidth
- let windowHeight = getViewportSize().windowHeight
- // 位置定位
- function calculationLocation(el, target, placements) {
- if (!el || !target) return;
- el.tooltipPosition.y = 0;
- el.tooltipPosition.x = 0;
- // @ts-ignore
- let el_dom = target.w_tooltip.firstElementChild.getBoundingClientRect()
- let target_dom = target.getBoundingClientRect()
- if (placements === "left") {
- el.tooltipPosition.x = 0
- el.tooltipPosition.y = target_dom.y - target_dom.height / 2 + 14
- el.tooltipPosition.right = windowWidth - target_dom.left + target_dom.height / 2 - 22
- } else if (placements === "left-right") {
- el.tooltipPosition.x = 0
- el.tooltipPosition.y = target_dom.y - (el_dom?.height || 0) / 2 + target_dom.height / 2
- el.tooltipPosition.left = target_dom.left + target_dom.width + 10
- } else if (placements === "bottom") {
- el.tooltipPosition.x = target_dom.x + target_dom.width / 2 - (el_dom?.width || 0) / 2
- el.tooltipPosition.y = target_dom.y + target_dom.height + 10
- if (el.tooltipPosition.x > (windowWidth-el_dom.width) && target_dom.left + el_dom.width > windowWidth) {
- el.tooltipPosition.x = windowWidth - el_dom.width
- el.arrowPosition.left = (el_dom.width / 10) * 8
- }
- if (el.tooltipPosition.x < 0) {
- el.arrowPosition.left = (el_dom.width / 10) * 2
- }
- } else if (placements === "right") {
- el.tooltipPosition.x = 0
- el.tooltipPosition.y = target_dom.y - (el_dom?.height || 0) / 2 + target_dom.height / 2
- el.tooltipPosition.left = target_dom.left + target_dom.width + 10
- } else if (placements === "right-left") {
- //提示文字的位置
- el.tooltipPosition.x = 0;
- el.tooltipPosition.y = target_dom.y - target_dom.height / 2;
- el.tooltipPosition.right = windowWidth - target_dom.left + target_dom.height / 2
- //三角形的位置
- el.arrowPosition.top = target_dom.height
- } else if (placements === "top") {
- el.tooltipPosition.x = target_dom.x + target_dom.width / 2 - (el_dom?.width || 0) / 2
- el.tooltipPosition.y = target_dom.y - target_dom.height - 11
- if (el.tooltipPosition.x > (windowWidth-el_dom.width) && target_dom.left + el_dom.width > windowWidth) {
- el.tooltipPosition.x = windowWidth - el_dom.width
- el.arrowPosition.left = (el_dom.width / 10) * 9
- }
- if (el.tooltipPosition.x < 0) {
- el.arrowPosition.left = (el_dom.width / 10) * 2
- }
- }
- el.tooltipPosition.x = el.tooltipPosition.x < 0 ? 0 : el.tooltipPosition.x
- el.tooltipPosition.y = el.tooltipPosition.y < 0 ? 0 : el.tooltipPosition.y
- }
- /**
- * 处理边界情况
- * @param {HTMLElement} el
- * @param direction
- * return {string} props
- */
- function dealDomBoundary(el, direction) {
- let target_dom = el.getBoundingClientRect()
- //处理上下左右边界情况
- if (target_dom.left < 150 && direction === 'left') {
- direction = 'left-right'
- }
- if (target_dom.right > (windowWidth - 150) && direction === 'right') {
- direction = 'right-left'
- }
- if (target_dom.top > windowHeight / 100 * 90 && direction === 'bottom') {
- direction = 'top'
- }
- if (target_dom.top < windowHeight / 100 * 10 && direction === 'top') {
- direction = 'bottom'
- }
- return direction
- }
- // 方向
- const allPlacements = ['left', 'bottom', 'right', 'top']
- function getElStyleAttr(element, attr) {
- const styles = window.getComputedStyle(element)
- // @ts-ignore
- return styles[attr]
- }
- const isOverflow = (target) => {
- const scrollWidth = target.scrollWidth
- const offsetWidth = target.offsetWidth
- const range = document.createRange()
- range.setStart(target, 0)
- range.setEnd(target, target.childNodes.length)
- const rangeWidth = range.getBoundingClientRect().width
- const padding = (parseInt(getElStyleAttr(target, 'paddingLeft'), 10) || 0) + (parseInt(getElStyleAttr(target, 'paddingRight'), 10) || 0)
- return (rangeWidth + padding > target.offsetWidth) || scrollWidth > offsetWidth
- }
- export const ellipsisTooltip = localStorage.getItem('useEllipseTooltip') ? {
- mounted(el, binding) {
- //获取指令的参数
- const {
- value: {
- placement, content, destroyOnLeave
- } = {}
- } = binding;
- // 加上超出...样式
- el.style.overflow = "hidden";
- el.style.textOverflow = "ellipsis";
- el.style.whiteSpace = "nowrap";
- windowWidth = getViewportSize().windowWidth
- windowHeight = getViewportSize().windowHeight
- //鼠标移开时 清除元素
- const onMouseLeave = () => {
- if (el.w_tipInstance) {
- el.w_tipInstance.hiddenTip()
- el.w_tooltip.remove()
- el.w_tipInstance = null
- el.w_tooltip = null
- }
- };
- const onMouseEnter = () => {
- // 判断内容长度 需要展示
- if (isOverflow(el)) {
- // @ts-ignore
- const directiveList = allPlacements.filter(placement => binding.modifiers[placement])
- const placements = directiveList.length ? directiveList : allPlacements
- if (!el.w_tooltip) {
- // 创建tooltip实例
- const vm = createApp(MyToolTip)
- // 创建根元素
- el.w_tooltip = document.createElement('div')
- // 挂载到页面
- document.body.appendChild(el.w_tooltip)
- el.w_tooltip.id = `tooltip_${Math.floor(Math.random() * 10000)}`
- el.w_tipInstance = vm.mount(el.w_tooltip)
- }
- // 设置 tooltip 显示方向 处理边界情况
- let direction = dealDomBoundary(el, placement || placements[0] || 'top')
- el.w_tipInstance.placements = direction;
- // 设置显示内容
- el.w_tipInstance.setContent(content || el.innerText)
- // 使 tooltip 显示
- el.w_tipInstance.showTip()
- nextTick(() => {
- // 计算 tooltip 在页面中的位置
- calculationLocation(el.w_tipInstance, el, direction)
- })
- el._scrollHandler = () => {
- // 重新定位位置
- if (el.w_tipInstance) calculationLocation(el.w_tipInstance, el, placements[0])
- }
- window.addEventListener('scroll', el._scrollHandler)
- const _destroyOnLeave = destroyOnLeave || true
- if (_destroyOnLeave) el.addEventListener("mouseleave", onMouseLeave);
- }
- };
- el.addEventListener("mouseenter", onMouseEnter);
- },
- unmounted(el) {
- if (el.w_tooltip) {
- document.body.removeChild(el.w_tooltip)
- }
- window.removeEventListener('scroll', el._scrollHandler)
- }
- } : {}
|