惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

SecWiki News
SecWiki News
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
Visual Studio Blog
博客园 - 叶小钗
S
SegmentFault 最新的问题
IT之家
IT之家
大猫的无限游戏
大猫的无限游戏
博客园_首页
Apple Machine Learning Research
Apple Machine Learning Research
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
月光博客
月光博客
酷 壳 – CoolShell
酷 壳 – CoolShell
腾讯CDC
D
Darknet – Hacking Tools, Hacker News & Cyber Security
V
V2EX
阮一峰的网络日志
阮一峰的网络日志
L
Lohrmann on Cybersecurity
量子位
C
Cyber Attacks, Cyber Crime and Cyber Security
T
Tor Project blog
J
Java Code Geeks
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
博客园 - 三生石上(FineUI控件)
Attack and Defense Labs
Attack and Defense Labs
AI
AI
The Cloudflare Blog
T
Tailwind CSS Blog
S
Schneier on Security
爱范儿
爱范儿
PCI Perspectives
PCI Perspectives
Stack Overflow Blog
Stack Overflow Blog
S
Secure Thoughts
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
T
The Exploit Database - CXSecurity.com
博客园 - 【当耐特】
V2EX - 技术
V2EX - 技术
S
Securelist
P
Proofpoint News Feed
T
Threat Research - Cisco Blogs
Help Net Security
Help Net Security
C
Cisco Blogs
N
News and Events Feed by Topic
人人都是产品经理
人人都是产品经理
B
Blog RSS Feed
K
Kaspersky official blog
T
The Blog of Author Tim Ferriss
G
Google Developers Blog
S
Security Affairs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Simon Willison's Weblog
Simon Willison's Weblog

博客园 - 一丝心情

Volta 安装和使用指南 免费国产ai试用总结 glb格式3d模型压缩 nuxt.js 项目流水线自动部署设置 免费的云数据库 vue 实用指令 IntelliJ IDEA license server 激活(亲测有效) win10/win11专业版激活码(亲测有效) Git 常用指令完全指南 npm 安装依赖报错整理 css3文字渐变, svg文字渐变 http/https与websocket的ws/wss的关系 指令 v-tooltip element-ui NavMenu 多级嵌套封装 常用css vue.config.js config.resolve.alias 目录别名配置 three.js 在低版本浏览报THREE.WebGLProgran: shader error 报错解决办法 nuxt 低版本浏览器兼容babel编译配置 常用软件历史版本下载 前端常用指令 数组常用方法总结 vue 中 echarts 添加事件 常用正则
vue 自定义指令实现v-overflow-tooltip
一丝心情 · 2023-07-07 · via 博客园 - 一丝心情

利用element ui el-tooltip 组件实现

一、注册创建局部指令

<template>
    <!-- eslint-disable -->
    <div>
            <div class="t-ellipsis" v-overflow-tooltip style="width: 70%;">
                    文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位
            </div>
            <div class="t-ellipsis" v-overflow-tooltip style="width: 30%;">
                    文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位
            </div>
    
             <!-- 添加本组件全局公用el-tooltip -->
            <el-tooltip  placement="top" ref="tooltip" :content="tooltipContent"></el-tooltip>
    </div>
</template>

<script>
/* eslint-disable */
    // 获取style
function getStyle(obj, attr) {
    if (obj.currentStyle) {
            return obj.currentStyle[attr];
    } else {
            return getComputedStyle(obj)[attr];
    }
}
export default {
    data() {
        return {
            // 为el-tooltip设置content值
            tooltipContent: ''
        }
    },
    directives: {
        overflowTooltip: {
            inserted(el, binding, vnode, oldVnode) {
                const tooltip = vnode.context.$refs.tooltip
                el.__vueOverflowTooltipMouseenter__ = function() {
                    const childNodesLength = el.childNodes.length
                    if (childNodesLength) {
                        const range = document.createRange();
                        range.setStart(el, 0);
                        range.setEnd(el, childNodesLength);
                        const rangeWidth = range.getBoundingClientRect().width;
                        const boxSizing = getStyle(el, 'boxSizing');
                        const padding = boxSizing === 'border-box' ? 0 : (parseInt(getStyle(el, 'paddingLeft'), 10) + parseInt(getStyle(el, 'paddingRight'), 10))

                        if (rangeWidth + padding > el.offsetWidth || el.scrollWidth > el.offsetWidth) {
                            vnode.context.$data.tooltipContent = el.innerText || el.textContent;
                            tooltip.referenceElm = el;
                            tooltip.$refs.popper && (tooltip.$refs.popper.style.display = 'none');
                            tooltip.doDestroy();
                            tooltip.setExpectedState(true);
                            tooltip.handleShowPopper()
                        }
                    }
                }

                el.__vueOverflowTooltipMouseleave__ = function() {
                    tooltip.setExpectedState(false);
                    tooltip.handleClosePopper();
                }

                // 绑定事件
                el.addEventListener('mouseenter', el.__vueOverflowTooltipMouseenter__);
                el.addEventListener('mouseleave', el.__vueOverflowTooltipMouseleave__);
            },
            unbind(el) {
           el.__vueOverflowTooltipMouseleave__()
                el.removeEventListener('mouseenter', el.__vueOverflowTooltipMouseenter__);
                el.removeEventListener('mouseleave', el.__vueOverflowTooltipMouseleave__);
                delete el.__vueOverflowTooltipMouseenter__;
                delete el.__vueOverflowTooltipMouseleave__; 
            }
        }
    }
}
</script>
    
<style>
.t-ellipsis {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
</style>

二、注册创建全局指令

1. 创建overflow-tooltip指令

import Vue from 'vue'
/* eslint-disable */

function getStyle(obj, attr) {
  if (obj.currentStyle) {
      return obj.currentStyle[attr];
  } else {
      return getComputedStyle(obj)[attr];
  }
}

Vue.directive('overflow-tooltip', {
  inserted(el, binding, vnode, oldVnode) {
    // 获取app.vue根节点下的 ref为tooltip的el-tooltip组件
    const tooltip = vnode.context.$root._vnode.child.$refs.tooltip
    // 给添加指令的el对象添加鼠标移入事件
    el.__vueOverflowTooltipMouseenter__ = function() {
      // 获取el.childNodes长度判断是否触发Range对象计算宽度
      const childNodesLength = el.childNodes.length
      if (childNodesLength) {
        // 使用 range 代替 scrollWidth 来判断文本是否溢出,这样做是为了解决潜在的 bug。
        const range = document.createRange();
        // 设置 range 的起点
        range.setStart(el, 0);
        // 设置 range 的终点,因为起终点都在同一个节点上,所以设置终点偏移量以选中节点的内容
        range.setEnd(el, childNodesLength);
        // 获取节点的内容的宽度
        const rangeWidth = range.getBoundingClientRect().width;
        // 获取el盒模型
        const boxSizing = getStyle(el, 'boxSizing');
        // 获取el左右pandding
        const padding = boxSizing === 'border-box' ? 0 : (parseInt(getStyle(el, 'paddingLeft'), 10) + parseInt(getStyle(el, 'paddingRight'), 10))

        if (rangeWidth + padding > el.offsetWidth || el.scrollWidth > el.offsetWidth) {
          // 改变app.vue根节点的data里tooltipContent 值(给el-tooltip组件的content设置值)
          tooltip.$parent.$data.tooltipContent = el.innerText || el.textContent;
          // 关联el
          tooltip.referenceElm = el;
          // 隐藏之前打开的popper
          tooltip.$refs.popper && (tooltip.$refs.popper.style.display = 'none');
          tooltip.doDestroy();
          tooltip.setExpectedState(true);
          tooltip.handleShowPopper()
        }
      }
    }
    // 给添加指令的dom对象添加鼠标移出事件
    el.__vueOverflowTooltipMouseleave__ = function() {
      tooltip.setExpectedState(false);
      tooltip.handleClosePopper();
    }
    
    // 绑定事件
    el.addEventListener('mouseenter', el.__vueOverflowTooltipMouseenter__);
    el.addEventListener('mouseleave', el.__vueOverflowTooltipMouseleave__);
  },
  update: function () {},
  componentUpdated: function () {},
  unbind: function (el) {
    el.__vueOverflowTooltipMouseleave__()
    el.removeEventListener('mouseenter', el.__vueOverflowTooltipMouseenter__);
    el.removeEventListener('mouseleave', el.__vueOverflowTooltipMouseleave__);
    delete el.__vueOverflowTooltipMouseenter__;
    delete el.__vueOverflowTooltipMouseleave__; 
  }
})

2.app.vue 添加全局el-tooltip组件

<template>
  <div id="app">
    ...
    <router-view/>
    <!-- 添加全局公用el-tooltip -->
    <el-tooltip  placement="top" ref="tooltip" :content="tooltipContent"></el-tooltip>
  </div>
</template>
<script>
export default {
  data() {
    return {
     // 为el-tooltip设置content值
      tooltipContent: ''
    }
  },
  components: {
  },
  mounted() {
  },
  created() {
  },
  methods: {
  }
}
</script>

3.main.js 引入overflow-tooltip指令

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import 'element-ui/lib/theme-chalk/index.css'
import ElementUI from 'element-ui'
// 引入overflow-tooltip指令
import '@/directive/overflow-tooltip'


Vue.config.productionTip = false
Vue.use(ElementUI)
Vue.use(window.ELEMENT, {
  size: 'small'
})
new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

 4.应用v-overflow-tooltip 指令

<template>
  <div>
        <div class="t-ellipsis" v-overflow-tooltip style="width: 70%;">
            文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位
        </div>
        <div class="t-ellipsis" v-overflow-tooltip style="width: 30%;">
            文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位文字占位
        </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
    }
  },
  mounted() {
  },
  methods: {
  }
}
</script>
<style>
.t-ellipsis {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
</style>