使用vue3自定义指令实现Tooltip

效果预览:

实现代码:

directive.js

javascript 复制代码
import { nextTick } from "vue"

function elFover(e) {

	// e.el.classList.add('hover')

	let res = e.el.getBoundingClientRect()
	// console.log(res)

	let dom_tooltip = document.querySelector('.c-tooltip')
	
	if(dom_tooltip) {
		dom_tooltip.style.display = 'block'
		dom_tooltip.querySelector('.ivu-tooltip-inner').innerText = e.val
	
	} else {
		let _div = document.createElement('div')
		_div.innerHTML = `<div class="c-tooltip ivu-tooltip-popper ivu-tooltip-dark ivu-tooltip-transfer" style="z-index: 1099; position: fixed; will-change: top, left; top: 0px; left: 0px;" x-placement="top">
		<div class="ivu-tooltip-content">
			<div class="ivu-tooltip-arrow"></div>
			<div class="ivu-tooltip-inner">${e.val}</div>
		</div>
	</div>`
		document.body.appendChild(_div)

		
	}

	nextTick(() => {
		!dom_tooltip && (dom_tooltip = document.querySelector('.c-tooltip'))
		let _res = dom_tooltip.getBoundingClientRect()

		if(res.top < _res.height) {
			dom_tooltip.style.top = res.bottom +'px'
			dom_tooltip.setAttribute('x-placement', 'bottom')
		} else {
			dom_tooltip.style.top = (res.top - _res.height) +'px'
			dom_tooltip.setAttribute('x-placement', 'top')
		}

		if(res.left < (_res.width - res.width)/2) {
			dom_tooltip.style.left = 0 +'px'
		} else if(window.innerWidth - res.right < (_res.width - res.width)/2) {
			dom_tooltip.style.left = (window.innerWidth - _res.width) +'px'
		} else {
			dom_tooltip.style.left = (res.left + (res.width - _res.width)/2) +'px'
		}

		
	})
	
}

function elLeave() {
	let dom_tooltip = document.querySelector('.c-tooltip')
	
	if(dom_tooltip) {
		dom_tooltip.style.display = 'none'
	}
}

let fb = undefined

export const vFocus = {
	mounted: (el, binding) => {
		fb = elFover.bind(this, {
			el: el,
			val: binding.value
		})
		el.addEventListener('mouseenter', fb)
		el.addEventListener('mouseleave', elLeave)
	},
	// 绑定元素的父组件卸载前调用
  beforeUnmount(el, binding, vnode, prevVnode) {
		el.removeEventListener('mouseenter', fb)
		el.removeEventListener('mouseleave', elLeave)
	},
}

main.ts

TypeScript 复制代码
import { vFocus } from '@/utils/directive.js'
import { createApp } from 'vue'

const app = createApp(App)
app.directive('focus', vFocus)

组件里使用

TypeScript 复制代码
<i class="md-more" v-focus="'更多'"></i>
相关推荐
半个落月16 小时前
LangSmith 全链路观测(下):用 Dataset 与 LLM Judge 量化评估 RA
javascript·langchain
半个落月17 小时前
LangSmith 全链路观测(上):用 LangGraph 与 Milvus 构建可追踪的 RAG 客服
javascript·langchain
Java后端的Ai之路17 小时前
06-React-Props
前端·react.js·前端框架
半个落月17 小时前
LangChain.js Agent 中间件实战:生命周期、动态工具与文件权限
javascript·langchain
Flynt18 小时前
开源"间谍卫星"说数据全是真的,我把它的免key数据源挨个试了一遍
前端·开源·数据可视化
Csvn18 小时前
渲染管线
前端
程序员大阳19 小时前
副队长CSS教程(33)–圆角与透明
前端·css·透明·圆角
志尊宝19 小时前
Vue3 零基础每日笔记(082):文件上传实战——el-upload 校验、自定义上传、头像预览
前端·javascript·vue.js·笔记·#javascript·#vue.js
鬼手点金19 小时前
opencode-rules 插件
java·开发语言·前端·人工智能·chrome·git·github
柳杉19 小时前
借助 Codex 和可视化工作流,从调研到完整实现,3D 大屏竟然可以这么简单
前端·ai编程·数据可视化