如何实现一个tooltip指令

导读

最近碰到一个问题,一个标题过长导致了换行,页面效果类似于下面这样

---- 给出一张模拟图--- 我就想用css的的ellipsis来让超出最大允许宽度的后显示省略号,但是呢,鼠标浮动还是要显示标题的是吧?加上目前项目又是使用了element-ui,那就用tooltip组件就完事了。然而,标题很短很短(不知道有没有某根牙签短)的时,我并不想让它显示tooltip,这就需要在mouseenter时做出判断了。然鹅,本来想套tooltip发现实在有点达不到预想的效果,又研究了tooltip的底层实现机制,发现了popperjs这个库,就很完美了!

「本文基于vue2」

---- 给效果图。----

知识导读

要充分理解以下内容,你需要了解以下知识点:

实现步骤

css 样式设置

首先毫无疑问地,我们的目标必须将文字内容超出给定的宽度显示省略号,通常css将这样设置

.tooltip{
  width700px/*超出此宽度后显示省略号*/
  text-overflow: ellipsis;
  overflow: hidden;
  white-space:nowrap;
}

在给目标设置css样式时,我们可以通过el拿到目标dom, 然后设置style(內联写法),我们将写成这样的代码

el.style.setproperty("width","700px");

感觉有点心智负担,如果看过element的部分实现,可以在src/utils/dom.js文件下找到一些实用的方法,比如setStyle

setStyle方法
setStyle方法
//el即是指令绑定的元素
setStyle(el, 'text-overflow''ellipsis')

创建popper

首先引入库包

npm i @popperjs/core -S

然后直接引入创建方法

import {createPopper} from "@popperjs/core"

使用popper必须制定目标元素和作为tooltip的元素 tooltip其实也应该是一个div,通过研究Element-UItooltip可知,其div是插入到body下方的,因此我们的代码如下

const div =document.createElement('div');
div.textContent=content;
addClass(div, 'auto-tooltip')
div.setAttribute('id','tooltip')
div.setAttribute('role','tooltip')
const body = document.querySelector('body')
body.appendChild(div)
createPopper(el,div,{
    placement:placement
})

宽度判断

这里是自动功能的核心,鼠标浮动时我们必须知道目标元素中文字的长度是否超过了指定宽度,是否需要tooltip的功能。 以下是获取文本在真实dom内部的代码 MDN参考

const range=document.createRange();
range.setStart(el,0);
range.setEnd(el,el.childNodes.length);
const rangeWidth = Math.round(range.getBoundingClientRect().width);

通过与预设的长度width比较我们就能知道我们是需要tooltip的了。

tooltip样式设定

这里的样式设定几乎都照抄Element-UItooltip样式,没啥好说的。

逻辑优化

功能做完了,我们就要重新梳理,得到完整的代码了,相关的说明直接放代码注释里,请看下图:

Vue.directive('auto-tooltip', {
  insertedfunction(el, binding, vNode{
    //get value from binding.value;
    // console.log(el.childNodes.length);
    //tooltip的placement属性, 阈值宽度和主题均可以通过绑定得到,防止为undefined,
    //预设初始值
    var placement = binding?.value?.placement ?? 'bottom';
    var width=binding?.value?.width ?? 700;
    var effect=binding?.value?.effect ?? "dark"
    //ellipsis省略样式
    setStyle(el, 'max-width',width+'px')
    setStyle(el, 'text-overflow''ellipsis')
    setStyle(el, 'overflow''hidden')
    setStyle(el, 'display''block')
    setStyle(el, 'white-space''nowrap')
    //mouseenter事件
    el.addEventListener('mouseenter'function({
      //没有ellipsis时的真实宽度
      const range=document.createRange();
      range.setStart(el,0);
      range.setEnd(el,el.childNodes.length);
      const rangeWidth = Math.round(range.getBoundingClientRect().width);
      //与阈值宽度做比较
      if(rangeWidth>width){
        createTooltip();
      }
    })
    //鼠标离开的mouseleave事件中移除所有的tooltip dom
    el.addEventListener('mouseleave'function(e{
      const divs = document.querySelectorAll('.auto-tooltip')
      divs.forEach(function(div{
        div.remove()
      })
    })
    //创建tooltip的逻辑单独封装
    function createTooltip(){
      var content=el.innerText; //设置内容
      var div = document.createElement('div')
      div.textContent=content;
      //样式设定
      addClass(div, 'auto-tooltip')
      div.setAttribute('id','tooltip')
      div.setAttribute('role','tooltip')
      setStyle(div,'position','absolute')
      setStyle(div,'border-radius','4px')
      setStyle(div,'padding','10px');
      setStyle(div,'z-index','2000');
      setStyle(div,'font-size','14px');
      setStyle(div,'line-height',1.2);
      setStyle(div,'min-width','12px');
      setStyle(div,'word-wrap','break-word');
      setStyle(div,'background',effect=='dark'?'#303133':'#FFF');
      if(effect=='dark'){
        setStyle(div,'color','#303133');
        setStyle(div,'border','solid 1px #303133');
      }
      setStyle(div,'color','#FFF');
      const body = document.querySelector('body')
      body.appendChild(div)
      //使用popperjs创建
      createPopper(el,div,{
        placement:placement
      })
    }
    // el.addEventListener('mouseenter',addToolTip);
  }

总结&回顾

通过Popperjs我们实现了类似于Element-UI中的tooltip功能,并通过指令的形式全局注册。同时,使用了不常见的Range.getBoundingClientRect()方法来识别我们的文字区域(因为文字部分也将作为一个TextNode成为DOM的一部分)的宽度来判断我们是否需要创建tooltip。

本文由 mdnice 多平台发布

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这里是一个简单的`v-tooltip`指令实现。该指令可以将鼠标悬浮在元素上时显示提示框,提示框的内容可以通过指令的参数或者绑定的值动态设置。 ```js // 自定义指令 Vue.directive('tooltip', { // 当被绑定的元素插入到 DOM 中时…… inserted: function (el, binding) { const tooltipText = binding.value || binding.arg || '' el.addEventListener('mouseenter', function () { // 创建提示框 const tooltip = document.createElement('div') tooltip.innerHTML = tooltipText tooltip.style.position = 'absolute' tooltip.style.top = `${event.clientY + 10}px` tooltip.style.left = `${event.clientX + 10}px` tooltip.style.backgroundColor = '#333' tooltip.style.color = '#fff' tooltip.style.padding = '5px' tooltip.style.zIndex = 9999 // 将提示框添加到DOM中 document.body.appendChild(tooltip) // 鼠标移出元素时,删除提示框 el.addEventListener('mouseleave', function () { document.body.removeChild(tooltip) }) }) } }) ``` 在使用时,在需要添加提示框的元素上使用`v-tooltip`指令,并且可以将提示框的内容作为指令的参数或者绑定的值来设置,例如: ```vue <template> <div> <span v-tooltip="'这是一个提示框'">鼠标放在这里</span> <span v-tooltip:top="'这是一个提示框'">鼠标放在这里</span> <span v-tooltip="tooltipText">鼠标放在这里</span> </div> </template> <script> export default { data() { return { tooltipText: '这是一个提示框' } } } </script> ``` 在上面的代码中,我们分别使用了指令的参数、修饰符和动态绑定来设置提示框的内容。当鼠标悬浮在元素上时,会显示相应的提示框,当鼠标离开元素时,提示框会消失。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值