vue3溢出文本tooltip或title展示解决方案—如何获取文本宽度

Author:zhoulujun Date:2023-03-06 Hits:5

解决文本溢出,鼠标悬浮展示tooltips,要解决2大难题。第一个是解决文本宽度的问题。毕竟 若果text-overflow: ellipsis生效,那么其父容

解决文本溢出,鼠标悬浮展示tooltips,要解决2大难题。

第一个是解决文本宽度的问题。毕竟 若果 text-overflow: ellipsis生效,那么其父容器就是文本,是无法直接获取宽度的。比如span元素是无法直接获取clienWidth。

第二个,就是文本编辑更改搞,需要重新计算。

文本宽度获取总结:

网上总结的足够多,比如:

这个总结大体如下:

直接按照当前字体大小 text.length * fontSize:

这样简单粗暴,但是仔细想下,文字、字母,标点符号,特殊字符等的出现会让计算有特别大的偏差。

隐藏元素计算

创建一个 div 标签,并添加到 body

设置标签 visibility: hidden 或者其他形式

动态修改 div 的 innerText为要计算的文本

offsetWidth、scrollWidth 获取宽度

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获取

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结构。

网上很推荐的是使用最后一种方法,但是在实际项目中,做通用化的时候,可能是 :

链接是:<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

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

const observer = new ResizeObserver((entries) => {
  console.log("Size changed");
});
const targetNode = document.getElementById('some-id');
observer.observe(targetNode);

这个用的 多,最终还是选择ResizeObserver。

在Vue3如何使用?

其实就是使用上面的方法封装一个组件

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 周期里面里面

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

vue3溢出文本tooltip或title展示解决方案—如何获取文本宽度的更多相关文章

  1. JS中通过id或者class获取文本内容

    一.JS通过id获取文本内容 二.JS通过class获取文本内容

  2. 【NLP】Python NLTK获取文本语料和词汇资源

    Python NLTK 获取文本语料和词汇资源 作者:白宁超 2016年11月7日13:15:24 摘要:NLTK是由宾夕法尼亚大学计算机和信息科学使用python语言实现的一种自然语言工具包,其收集 ...

  3. js/jquery获取文本框的值与改变文本框的值

    我们就用它来学习获取文本框的值及改变文本框的值. 代码如下 复制代码 <script>function get1(){ document.getElementById("txtb ...

  4. jquery设置文本框值 与获取文本框的值

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  5. python开发_tkinter_获取文本框内容_给文本框添加键盘输入事件

    在之前的blog中有提到python的tkinter中的菜单操作 python开发_tkinter_窗口控件_自己制作的Python IDEL_博主推荐 python开发_tkinter_窗口控件_自 ...

  6. DOM节点中获取文本易混淆的属性

    DOM 节点中对于获取文本易混淆的属性,innerText, innerHTML, outerHTML, textContent, nodeValue. 一个实例: <!DOCTYPE html ...

  7. JavaWeb后台从input表单获取文本值的两种方式

    JavaWeb后台从input表单获取文本值的两种方式 #### index.html <!DOCTYPE html> <html lang="en"> & ...

  8. 每天一个JavaScript实例-展示设置和获取CSS样式设置

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  9. 获取元素节点的子节点 & 获取文本节点

    1. 获取元素节点的子节点(**只有元素节点才有子节点):              ①. childNodes 属性获取全部的子节点, 但该方法不实用. 因为如果要获取指定的节点          ...

  10. jquery获取文本框的内容

    使用jquery获取文本框的内容有以下几种: 1.根据ID取值(id属性): // javascript <script type="text/javascript"> ...

随机推荐

  1. 01背包问题的js解决方式

    如果你有兴趣看这个相信你已经对背包问题有所了解,所以关于背包问题的描述,我就不写了. 只记录一下自己对这个问题的一些看法和思考,于我而言,这个东西现在困扰我的是如何确定最优解. 实质上关于背包问题网上 ...

  2. 数据结构与算法 | 二分搜索(Binary Search)

    二分搜索(Binary Search) 文承上篇,搜索算法中除了深度优先搜索(DFS)和广度优先搜索(BFS),二分搜索(Binary Search)也是最基础搜索算法之一. 二分搜索也被称为折半搜索 ...

  3. 最新 2023.2 版本 WebStorm 永久破解教程,WebStorm 破解补丁永久激活(亲测有效)

    最近 jetbrains 官方发布了 2023.2 版本的 IDEA,之前的激活方法并不支持这个新的版本. 下面是最新的激活教程,激活步骤和之前是类似的,只是换用了不同的补丁文件. 本教程支持 Jet ...

  4. JVM SandBox 的技术原理与应用分析

    https://www.infoq.cn/article/tsy4lgjvsfweuxebw*gp https://blog.csdn.net/qq_40378034/article/details/ ...

  5. fileclude

    打开界面是一篇源代码 看到有flag.php文件,直接打开出现错误提示,看来只能用编码读取数据了 需要传入file1和file2 file1编码读取flag.php的内容 file1=php://fi ...

  6. 微服务系列-Spring Boot使用Open Feign 微服务通信示例

    公众号「架构成长指南」,专注于生产实践.云原生.分布式系统.大数据技术分享. 前言 在前几个教程中我们已经看到: 使用 RestTemplate 的 Spring Boot 微服务通信示例 使用 We ...

  7. Markdown & typora 速查

    Markdown & typora 速查 一级标题 # 一级标题 说明:#数量表示几级标题,如二级标题为"## 二级标题",支持到6级标题,#和标题中间有一个空格 typo ...

  8. led灯实现跑马灯效果,达到设定时间(2秒)两LED灯全部亮起,持续时间1秒,而后重新恢复跑马灯效果;

    #include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器 typedef unsigned int u16; //对数据类型进行声明定义 typedef ...

  9. OpenSSL 使用AES对文件加解密

    AES(Advanced Encryption Standard)是一种对称加密算法,它是目前广泛使用的加密算法之一.AES算法是由美国国家标准与技术研究院(NIST)于2001年发布的,它取代了原先 ...

  10. Kotlin协程系列(三)

    1.前言 前面两节,我们运用了kotlin提供的简单协程去实现了一套更易用的复合协程,这些基本上是以官方协程框架为范本进行设计和实现的.虽然我们还没有直接接触kotlin官方协程框架,但对它的绝大多数 ...