每天一个偷懒小技巧之开发一个「poptip」指令
已收集到的情报
首先需要一个poptip组件,这里引用的是iview的poptip
<Poptip title="Title" content="content" placement="top-start">
<Button>Top Left</Button>
</Poptip>
日常开发需要在写好的组件外面套一层poptip,写法僵硬;对于不需要poptip的要写成下面丑陋的代码:
<Poptip v-if="showPoptip" title="Title" content="content" placement="top-start">
<Button>Top Left</Button>
</Poptip>
<Button v-else>Top Left</Button>
期望实现的目标
<Button v-poptip:hover="{title:'标题',content:'poptip提示的内容'}">Top Left</Button>
即要实现一个poptip指令,当trigger触发poptip时,render出一个poptip,提示还是采用当前的组件。
实现步骤
❝实现的思路是在绑定指令的当前el下创建一个占位,并将占位与当前el重叠,占位通过trigger触发poptip,就实现了仿当前元素向外叠加「Poptip」组件。
❞

一、render 「popTip」组件
首先引入Vue 和 Iview,使用new Vue来render占位div;创建一个空节点来挂载当前的Vue实例:
let popRoot = document.createElement('div')
new Vue({
el: popRoot,
render: h => {
return h(iView.Poptip, {
props: {
trigger: arg || 'click',
content: value.content
},
class: {
'v-poptip-render': true
}
}, [
h('div', {
style: {
width: '100%',
height: '100%'
}
})
])
}
})
「注意:new Vue挂载的节点会直接替换当前的DOM,所以不能直接在当前的el上挂载。el可以为DOM或者‘#’+id。」
二、重叠实体和占位「div」
let popRoot = document.createElement('div')
el.style.position = 'relative'
el.appendChild(popRoot)
当前的节点不能作为Vue实例的跟节点,只能创建一个新空节点,再将实例出来的DOM挂载到当前的el上。重叠实体和占位css实现即可。
三、注册「v-poptip」
- el:指令所绑定的元素,可以用来直接操作 DOM。
- binding:一个对象,包含以下 property:
- name:指令名,不包括 v- 前缀。
- value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
- oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
- expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
- arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
- modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。 vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。 oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
export default {
inserted: (el, { value, arg }, vnode) => {
}
}
源码
import Vue from '../../../vue/dist/vue.runtime.common.js'
import iView from '../../../iview/src/index.js'
export default {
inserted: (el, { value, arg }, vnode) => {
let popRoot = document.createElement('div')
el.style.position = 'relative'
el.appendChild(popRoot)
/* eslint-disable no-new */
new Vue({
el: popRoot,
render: h => {
return h(iView.Poptip, {
props: {
trigger: arg || 'click',
content: value.content
},
class: {
'v-poptip-render': true
}
}, [
h('div', {
style: {
width: '100%',
height: '100%'
}
})
])
}
})
}
}
本文使用 mdnice 排版