Vue 实现智能检测文字是否溢出,溢出显示省略号,鼠标悬浮显示全部【附封装组件完整代码+详细注释+粘贴即食】

news2025/3/13 11:17:39

一、场景需求

在项目中,经常会遇到文本内容超出容器的情况。为了提高用户体验,我希望在文字溢出时显示悬浮提示,未溢出时则不显示。

二、效果演示

在这里插入图片描述

三、实现原理

DOM宽度对比法:通过比较元素的scrollWidth(实际内容宽度)和clientWidth(可视区域宽度)判断是否溢出
动态绑定Tooltip:利用el-tooltip的disabled属性按需激活提示
响应式监听:结合Vue的$nextTick和watch实现动态数据更新后的自动检测

四、完整代码

<template>
  <div class="box">
    <div v-for="(item,i) in list" :key="i" class="items">
      <!-- 添加 el-tooltip 并绑定判断逻辑 -->
      <el-tooltip 
        :disabled="!shouldShowTooltip[i]" 
        :content="`${item.name}:${item.score}`" 
        placement="top">
        <span 
          :ref="el => { nameElements[i] = el }"
          class="name"
          @mouseenter="checkOverflow(i)">
          {{ item.name }}{{ item.score }}
        </span>
      </el-tooltip>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      list: [
        {
          name: '我是测试名称1',
          score: '90'
        },
        {
          name: '我是测试我是测试我是测试我是测试',
          score: '92'
        },
        {
          name: '雪芽',
          score: '99'
        },
        {
          name: '果粒橙果粒橙果粒橙果粒橙果粒橙',
          score: '100'
        }
      ],
      shouldShowTooltip: [], // 存储是否需要显示tooltip
      nameElements: []       // 存储DOM引用
    }
  },
  watch: {
    list() {
      this.$nextTick(() => {
        this.list.forEach((_, i) => this.checkOverflow(i))
      })
    }
  },
  mounted() {
    // 初始化时检查一次
    this.$nextTick(() => {
      this.list.forEach((_, i) => this.checkOverflow(i))
    })
  },
  methods: {
    // 通过对比实际宽度和可视宽度判断是否溢出
    checkOverflow(index) {
      const el = this.nameElements[index]
      if (el) {
        this.$set(this.shouldShowTooltip, index, el.scrollWidth > el.clientWidth)
      }
    }
  }
}
</script>

<style lang="scss" scoped>
  .box {
    width: 300px;
    font-size: 30px;
    border: 1px solid red;
    display: flex;
    gap: 24px;
    flex-direction: column;
    .items {
      flex: 1;
      display: flex;
      .name {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }
    }
  }
</style>

五、封装组件

如果项目此需求需求量大,可以将此逻辑封装成组件,便于不同页面使用~

1、组件:
<template>
  <el-tooltip
    :disabled="!showTooltip || disabled"
    :content="content"
    :placement="placement"
    :popper-class="popperClass">
    <div
      ref="contentBox"
      class="auto-tooltip-wrapper"
      @mouseenter="handleCheckOverflow">
      {{ content }}
    </div>
  </el-tooltip>
</template>

<script>
export default {
  name: 'AutoTooltip',
  props: {
    disabled: Boolean,  // 是否完全禁用功能(优先级最高)
    content: String, // 显示内容(同时用于提示和内容区域)
    // 提示框位置,参考ElementUI的placement配置
    placement: {
      type: String,
      default: 'top'
    },
    popperClass: String,  // 自定义Tooltip的类名
    // 溢出容差(解决1像素级误差问题)
    tolerance: {
      type: Number,
      default: 1
    }
  },
  data() {
    return {
      showTooltip: false,  // 控制提示显示状态
      observer: null // ResizeObserver实例
    }
  },
  mounted() {
    this.initObserver()
    this.checkOverflow()
  },
  beforeDestroy() {
    if (this.observer) {
      // 组件销毁时断开观察器
      this.observer.disconnect()
    }
  },
  methods: {
    /**
     * 初始化ResizeObserver
     * 用于监听元素尺寸变化自动检测溢出状态
     */
    initObserver() {
      if (typeof ResizeObserver === 'undefined') return

      try {
        this.observer = new ResizeObserver(() => {
          this.checkOverflow()
        })
        this.observer.observe(this.$refs.contentBox)
      } catch (e) {
        console.warn('ResizeObserver not supported')
      }
    },

    /**
     * 执行溢出检测的主方法
     * 1. 获取DOM引用
     * 2. 调用计算方法
     * 3. 更新显示状态
     */
    checkOverflow() {
      const el = this.$refs.contentBox
      if (!el) return

      this.showTooltip = this.calculateOverflow(el)
    },

    /**
     * 计算元素是否溢出
     * @param {HTMLElement} el - 要检测的元素
     * @returns {boolean} 是否发生溢出
     */
    calculateOverflow(el) {
      return el.scrollWidth > el.clientWidth + this.tolerance
    },

    /**
     * 鼠标进入的回调检测(兼容模式)
     * 当ResizeObserver不可用时,手动触发检测
     */
    handleCheckOverflow() {
      if (!this.observer) {
        this.checkOverflow()
      }
    }
  }
}
</script>

<style scoped>
  .auto-tooltip-wrapper {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: block;
    box-sizing: border-box;
    max-width: 100%;
  }
</style>

2、页面内使用:
<template>
  <div class="box">
    <div v-for="(item,i) in list" :key="i" class="items">
      <AutoTooltip :content="`${item.name}:${item.score}`"></AutoTooltip>
    </div>
  </div>
</template>

<script>
import AutoTooltip from './AutoTooltip.vue'
export default {
  components: { AutoTooltip },
  data() {
    return {
      list: [
        {
          name: '我是测试名称1',
          score: '90'
        },
        {
          name: '我是测试我是测试我是测试我是测试',
          score: '92'
        },
        {
          name: '雪芽',
          score: '99'
        },
        {
          name: '果粒橙果粒橙果粒橙果粒橙果粒橙',
          score: '100'
        }
      ],
      shouldShowTooltip: [], // 存储是否需要显示tooltip
      nameElements: []       // 存储DOM引用
    }
  },
  watch: {
    list() {
      this.$nextTick(() => {
        this.list.forEach((_, i) => this.checkOverflow(i))
      })
    }
  },
  mounted() {
    // 初始化时检查一次
    this.$nextTick(() => {
      this.list.forEach((_, i) => this.checkOverflow(i))
    })
  },
  methods: {
    // 通过对比实际宽度和可视宽度判断是否溢出
    checkOverflow(index) {
      const el = this.nameElements[index]
      if (el) {
        this.$set(this.shouldShowTooltip, index, el.scrollWidth > el.clientWidth)
      }
    }
  }
}
</script>

<style lang="scss" scoped>
  .box {
    width: 300px;
    font-size: 30px;
    border: 1px solid red;
    display: flex;
    gap: 24px;
    flex-direction: column;
    .items {
      flex: 1;
      display: flex;
      .name {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }
    }
  }
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2313540.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

51c大模型~合集10

我自己的原文哦~ https://blog.51cto.com/whaosoft/11547799 #Llama 3.1 美国太平洋时间 7 月 23 日&#xff0c;Meta 公司发布了其最新的 AI 模型 Llama 3.1&#xff0c;这是一个里程碑时刻。Llama 3.1 的发布让我们看到了开源 LLM 有与闭源 LLM 一较高下的能力。 Meta …

关于C/C++语言的初学者在哪刷题,怎么刷题

引言&#xff1a; 这篇博客主要是针对初学者关于怎么在网上刷题&#xff0c;以及在哪里刷题。 1.介绍平台&#xff08;在哪刷题&#xff09;&#xff1a; 1.牛客牛客网https://www.nowcoder.com/ &#xff1a;有许多面试题&#xff0c;也有许多供学习者练习的题 2.洛谷洛谷 …

AI自动化编程初探

先说vscodeclinemodelscope方案&#xff0c;后面体验trae或者cursor再写写其它的。vscode和trae方案目前来说是免费的&#xff0c;cursor要用claud需要付费&#xff0c;而且不便宜&#xff0c;当然效果可能是最好的。 vscode方案&#xff0c;我的经验是最好在ubuntu上&#xff…

《人月神话》:软件工程的成本寓言与生存法则

1975年&#xff0c;Fred Brooks在《人月神话》中写下那句振聋发聩的断言——“向进度落后的项目增加人力&#xff0c;只会让进度更加落后”——时&#xff0c;他或许未曾料到&#xff0c;这一观点会在半个世纪后的人工智能与云原生时代&#xff0c;依然如达摩克利斯之剑般悬在每…

深入理解Java中的static关键字及其内存原理

static是Java中实现类级共享资源的核心修饰符&#xff0c;它突破了对象实例化的限制&#xff0c;使得变量和方法能够直接与类本身绑定。这种特性让static成为构建工具类、全局配置等场景的利器&#xff0c;但同时也带来独特的内存管理机制需要开发者关注。 static修饰成员变量…

20250310-组件基础2

通过插槽来分配内容 一些情况下我们会希望能和 HTML 元素一样向组件中传递内容&#xff1a; <AlertBox>传入的内容 </AlertBox> 我们期望能渲染成这样&#xff1a; 这可以通过 Vue 的自定义 <slot> 元素来实现&#xff1a; <template><div clas…

Fedora41安装MySQL8.4.4

Fedora41安装MySQL8.4.4 Fedora41用yum仓库安装MySQL8.4.4 笔记250310下载安装启动mysqld服务查看生成的初始密码 , 用初始密码登录登录后,必须修改初始密码才能执行其它操作可选设置降低密码强度要求, 使用简单密码降低 validate_password 组件对密码强度的要求 用SET GLOBAL命…

基于YOLO11深度学习的运动品牌LOGO检测与识别系统【python源码+Pyqt5界面+数据集+训练代码】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

java BCC异或校验例子

需求 对一个十六进制的字符串进行BCC校验 方法 private static String XORCheck(String rawMsg) {// 16进制字符串需要转成10进制数组进行校验&#xff0c;然后再返回16进制字符串用于与原来的字符匹配byte[] bytes HexDumpMsgFormat.hexStr2DesBytes(rawMsg);return BytesUt…

华为OD机试九日集训第1期 - 按算法分类,由易到难,循序渐进,提升编程能力和解题技巧,从而提高机试通过率(Python/JS/C/C++)

目录 一、适合人群二、本期训练时间三、如何参加四、数据结构与算法大纲五、华为OD九日集训第1期第1天、逻辑分析第2天、数组第3天、双指针第4天、map与list第5天、队列第6天、栈第7天、滑动窗口第8天、二叉树第9天、矩阵 六、国内直接使用满血ChatGPT4o、o1、o3-mini-high、Cl…

webshell一些上传心得

我们以upload-labs为基础 一、前端拦截&#xff1a; 如第一关 工作方式&#xff1a; 直接在前端拦截 绕过方式&#xff1a; 因为没有限制后端&#xff0c;所有可以用bs 绕过前端修改格式即可 将需要上传的php文件改成jpg格式 使用burp suite 拦截上传后&#xff0c;使用re…

ROS实践(二)构建Gazebo机器人模型文件urdf

目录 一、基础语法 1. urdf文件组成 2. robot根标签 3. link 和 joint标签 4. sensor标签 二、 实验&#xff1a;使用launch文件启动rviz查看机器人模型 1. 编写机器人模型的urdf文件。 2. 编写launch文件。 3. 运行launch&#xff0c;查看效果。 URDF&#xff08;Unifi…

Linux 入门:常用命令速查手册

目录 一.指令 1.pwd&#xff08;显示所在路径&#xff09; 2.ls&#xff08;列出所有子目录与文件&#xff09; 3.touch&#xff08;创建文件&#xff09; 4.mkdir&#xff08;创建目录&#xff09; 5.cd&#xff08;改变所处位置&#xff09; 6.rm&#xff08;删除&…

2路模拟量同步输出卡、任意波形发生器卡—PCIe9100数据采集卡

品牌&#xff1a;阿尔泰科技 型号&#xff1a; PCIe9100、PCIe9101、PXIe9100、PXIe9101 产品系列&#xff1a;任意波形发生器 支持操作系统&#xff1a;XP、Win7、Win8、Win10 简要介绍&#xff1a; 910X 系列是阿尔泰科技公司推出的 PCIe、PXIe 总线的任意波形发生器&…

Facebook 隐私保护技术的发展与未来趋势

Facebook 隐私保护技术的发展与未来趋势 在这个数字化时代&#xff0c;个人隐私保护已成为全球关注的焦点。Facebook&#xff0c;作为全球最大的社交网络平台之一&#xff0c;其在隐私保护技术的发展上扮演着重要角色。本文将探讨 Facebook 在隐私保护技术方面的进展&#xff…

Python基于Django的医用耗材网上申领系统【附源码、文档说明】

博主介绍&#xff1a;✌Java老徐、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&…

⭐LeetCode(数学分类) 48. 旋转图像——优美的数学法转圈(原地修改)⭐

⭐LeetCode(数学分类) 48. 旋转图像——优美的数学法转圈(原地修改)⭐ 示例 1&#xff1a; 输入&#xff1a;root [5,3,6,2,4,null,8,1,null,null,null,7,9] 输出&#xff1a;[1,null,2,null,3,null,4,null,5,null,6,null,7,null,8,null,9] 示例 2&#xff1a; 输入&#xff1…

深度学习PyTorch之13种模型精度评估公式及调用方法

深度学习pytorch之22种损失函数数学公式和代码定义 深度学习pytorch之19种优化算法&#xff08;optimizer&#xff09;解析 深度学习pytorch之4种归一化方法&#xff08;Normalization&#xff09;原理公式解析和参数使用 深度学习pytorch之简单方法自定义9类卷积即插即用 实时…

tomcat单机多实例部署

一、部署方法 多实例可以运行多个不同的应用&#xff0c;也可以运行相同的应用&#xff0c;类似于虚拟主机&#xff0c;但是他可以做负载均衡。 方式一&#xff1a; 把tomcat的主目录挨个复制&#xff0c;然后把每台主机的端口给改掉就行了。 优点是最简单最直接&#xff0c;…

Java开发者如何接入并使用DeepSeek

目录 一、准备工作 二、添加DeepSeek SDK依赖 三、初始化DeepSeek客户端 四、数据上传与查询 五、数据处理与分析 六、实际应用案例 七、总结 【博主推荐】&#xff1a;最近发现了一个超棒的人工智能学习网站&#xff0c;内容通俗易懂&#xff0c;风格风趣幽默&#xff…