1 function showTitle(el, title) { 2 const popover = getPopover() 3 const popoverStyle = popover.style 4 5 if (title === undefined) { 6 popoverStyle.display = 'none' 7 } else { 8 const elRect = el.getBoundingClientRect() 9 const elComputedStyle = window.getComputedStyle(el, null) 10 const rightOffset = parseInt(elComputedStyle.getPropertyValue('padding-right')) || 0 11 const topOffset = parseInt(elComputedStyle.getPropertyValue('padding-top')) || 0 12 13 popoverStyle.visibility = 'hidden' 14 popoverStyle.display = 'block' 15 popover.querySelector('.popover-content').textContent = title 16 popoverStyle.left = elRect.left - popover.offsetWidth / 2 + (el.offsetWidth - rightOffset) / 2 + 'px' 17 popoverStyle.top = elRect.top - popover.offsetHeight + topOffset + 'px' 18 popoverStyle.display = 'block' 19 popoverStyle.visibility = 'visible' 20 } 21 } 22 23 function getPopover() { 24 let popover = document.querySelector('.title-popover') 25 26 if (!popover) { 27 const tpl = ` 28 <div class="popover title-popover top fade in" style="position:fixed;"> 29 <div class="arrow"></div> 30 <div class="popover-content"></div> 31 </div> 32 ` 33 const fragment = document.createRange().createContextualFragment(tpl) 34 35 document.body.appendChild(fragment) 36 popover = document.querySelector('.title-popover') 37 } 38 39 return popover 40 } 41 export default { 42 bind(el, binding, vnode) { 43 // 使用 const 声明一个只读的常量,其值是需要监听的事件类型列表 44 const events = ['mouseenter', 'mouseleave', 'click'] 45 // 声明一个处理器,以根据不同的事件类型传不同的参数 46 const handler = (event) => { 47 if (event.type === 'mouseenter') { 48 // 显示一个提示框 49 showTitle(el, binding.value) 50 } else { 51 // 隐藏一个提示框 52 showTitle() 53 } 54 } 55 56 // 在 el 元素上添加事件监听 57 events.forEach((event) => { 58 el.addEventListener(event, handler, false) 59 }) 60 61 // 在 el 元素上添加一个属性,以在其他钩子进行访问 62 el.destroy = () => { 63 // 移除 el 元素上的事件监听 64 events.forEach((event) => { 65 el.removeEventListener(event, handler, false) 66 }) 67 // 移除 el 元素上的 destroy 68 el.destroy = null 69 } 70 }, 71 unbind(el) { 72 // 移除事件监听和数据绑定 73 el.destroy() 74 } 75 }
使用步骤:
1.建立指令;
2.在要使用的组件中引入并注册指令
1 import title from '@/directives/title' 2 directives: { 3 title 4 }
3.页面中使用,将原来的:title=""改为v-title:
1 <a v-for="item in contacts" v-title="item.title" :href="item.link" :style="contactStyle" target="_blank"> 2 <i :class="`fa fa-${item.icon}`"></i> 3 </a>
指令的基础知识补充:
一个指令定义对象可以提供如下几个钩子函数(均为可选):
bind
:只调用一次,指令第一次绑定到元素时调用,在这里可以进行一次性的初始化设置;inserted
:被绑定元素插入父节点时调用;update
:所在组件的 VNode(虚拟节点)更新时调用,但是可能发生在其子 VNode 更新之前;componentUpdated
:指令所在组件的 VNode 及其子 VNode 全部更新后调用;unbind
:只调用一次,指令与元素解绑时调用,在这里可以移除绑定的事件和其他数据;-
指令钩子函数会被传入以下参数:
el
:指令所绑定的元素,可以用来操作 DOM ;binding
:一个对象,binding.value
表示指令的绑定值,如v-title="'我是标题'"
中,绑定值为'我是标题'
;vnode
:Vue 编译生成的虚拟节点;oldVnode
:上一个虚拟节点,仅在update
和componentUpdated
钩子中可用。