vue3溢出文本tooltip或title展示解决方案—如何获取文本宽度
vue3溢出文本tooltip或title展示解决方案—如何获取文本宽度
Author:zhoulujun Date:2023-03-06
解决文本溢出,鼠标悬浮展示tooltips,要解决2大难题。第一个是解决文本宽度的问题。毕竟 若果text-overflow: ellipsis生效,那么其父容解决文本溢出,鼠标悬浮展示tooltips,要解决2大难题。
第一个是解决文本宽度的问题。毕竟 若果 text-overflow: ellipsis生效,那么其父容器就是文本,是无法直接获取宽度的。比如span元素是无法直接获取clienWidth。
第二个,就是文本编辑更改搞,需要重新计算。
文本宽度获取总结:
网上总结的足够多,比如:
-
面试官:你是如何获取文本宽度的? https://juejin.cn/post/7091990279565082655
-
通过canvas方法计算任意字符串所占的实际宽度 https://blog.csdn.net/qiao_qiao_happy/article/details/115560550
这个总结大体如下:
直接按照当前字体大小 text.length * fontSize:
这样简单粗暴,但是仔细想下,文字、字母,标点符号,特殊字符等的出现会让计算有特别大的偏差。
隐藏元素计算
创建一个 div 标签,并添加到 body
设置标签 visibility: hidden 或者其他形式
动态修改 div 的 innerText为要计算的文本
offsetWidth、scrollWidth 获取宽度
1 2 3 4 5 6 7 8 9 10 11 12 13 | function getActualWidthOfChars(text: string, options: CSSProperties, dom = document): number { const { fontSize, fontFamily } = options; const tempDom = document.createElement( 'div' ); tempDom.style.cssText = `position: absolute;left: -999em;top:-999em;z-index: -1; ${fontSize ? 'font-size: ;' : 'fontSize' } ${fontFamily ? 'font-family' : 'fontFamily' } `; tempDom.textContent = text; dom.append(tempDom); const { clientWidth } = tempDom; dom.removeChild(tempDom); return clientWidth; } |
这个频繁创建dom也可以解决,就是缓存dom,比如全局变量或者闭包。但是这种方法在字符串中含有多个空格时,测出来的宽度会一样,当然可以通过pre code元素避免。其实最好是转义" "呀。
canvas api TextMetrics获取
1 2 3 4 5 6 7 8 9 | function getActualWidthOfChars(text: string, options: Record<string, any> = {}): number { const { size = 14, family = 'Microsoft YaHei' } = options; const canvas = document.createElement( 'canvas' ); const ctx = canvas.getContext( '2d' ); ctx.font = `${size}px ${family}`; const metrics = ctx.measureText(text); const actual = Math.abs(metrics.actualBoundingBoxLeft) + Math.abs(metrics.actualBoundingBoxRight); return Math.max(metrics.width, actual); } |
这个相比dom操作,无需更改dom结构。
网上很推荐的是使用最后一种方法,但是在实际项目中,做通用化的时候,可能是 :
1 | 链接是:< a href=" style="font-size:30px;" >test</ a >2222 |
这个TextMetrics不好弄。第二个,我们无论做成组件还是 指令,textContent 更好地获取内容文本。关于textContent,推荐《小tips: JS DOM innerText和textContent的区别 https://www.zhangxinxu.com/wordpress/2019/09/js-dom-innertext-textcontent/》
再次通过 getComputedStyle() 后去当前元素的样式属性。二者结合非常好使。
当然,canvas也不是没有解决办法:
综合考量,还是使用Dom方案。
如何监听文本变化
首先想到的肯定是ResizeObserverSize,其次是MutationObserver
MutationObserver
看api,MutationObserver是天选之子。
MutationObserver的出现就是为了解决MutationEvent带来的问题。用来观察Node(节点)变化的。具体参看:《了解HTML5中的MutationObserver https://segmentfault.com/a/1190000012787829?utm_source=tag-newest》
https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | const observer = new MutationObserver((mutationList, observer) => { for (const mutation of mutationList) { switch (mutation.type) { case 'attributes' : console.log(`The ${mutation.attributeName} attribute was modified.`); break ; case 'childList' : console.log( 'A child node has been added or removed.' ); break ; } } }); const targetNode = document.getElementById( 'some-id' ); observer.observe(targetNode, { attributes: true , childList: true , subtree: true }); |
这个配置太复杂,而且我们只需观测宽度变化,不需要那么多操作
ResizeObserver
https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver
1 2 3 4 5 | const observer = new ResizeObserver((entries) => { console.log( "Size changed" ); }); const targetNode = document.getElementById( 'some-id' ); observer.observe(targetNode); |
这个用的 多,最终还是选择ResizeObserver。
在Vue3如何使用?
其实就是使用上面的方法封装一个组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | import { ObjectDirective, } from 'vue' ; import getActualWidthByCanvas from '../utils/getActualWidthByCanvas' ; import getActualWidthByDom from '../utils/getActualWidthByDom' ; const overflowTitle: ObjectDirective<HTMLElement> = { mounted(el, { value = {} }) { const { clientWidth } = el.parentElement; if (!clientWidth) { return ; } const { content, calType = 'dom' } = value; const text = content || el.innerText; let textWidth = 0; if (calType === 'dom' ) { textWidth = getActualWidthByDom(el.textContent, null , el.parentElement); } else { const { fontSize, fontFamily } = getComputedStyle(el); textWidth = getActualWidthByCanvas(text, { fontSize, fontFamily }); } if (textWidth > clientWidth) { el.setAttribute( 'title' , text); } }, }; export default overflowTitle; |
这里面可以跟进一步封装。
在mouted 周期里面里面
1 2 3 | mounted(el: HTMLElement, binding: DirectiveBinding) { createInstance(el, binding); } |
但是,个人觉得还是直接用组件比较好。
具体查看:https://github.com/zhoulujun/textOverflowTitle
转载本站文章《vue3溢出文本tooltip或title展示解决方案—如何获取文本宽度》,
请注明出处:https://www.zhoulujun.cn/html/webfront/ECMAScript/vue3/8933.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了