模拟元素的title属性,自定义Vue指令

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

 

posted @ 2018-07-14 10:28  前端极客  阅读(3073)  评论(0编辑  收藏  举报