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
鈎子中可用。