先了解一下,在 vue
中,有很多内置的指令.
比如:
v-for
用于遍历v-if
&v-show
用于隐藏和显示元素(区别在于后者是修改display:block|none
,前者是不创建把元素从dom中删除或者创建.v-bind:
属性绑定,把数据绑定在HTML元素的属性上.v-html
&v-text
把数据绑定在HTML元素的属性上,作用同innerHTML
&innerText
v-on:
绑定HTML元素事件v-if
&v-else-if
&v-else
条件渲染v-model
绑定表单元素,实现双向绑定.
等等.....
所以,关于指令,我们可以总结下面几点:
- 指令是写在 HTML 属性地方的.
<input v-model='name' type='text' />
- 指令都是以
v-
开头的. - 指令表达式的右边一般也可以跟值
v-if = false
2.0 Vue自定义指令场景小DEMO(非常尬)
场景: 我们需要一个指令,写在某个HTML表单元素上,然后让它在被加载到DOM中时,自动获取焦点.
// 和自定义过滤器一样,我们这里定义的是全局指令 Vue.directive('focus',{ inserted(el) { el.focus() } })
<div id='app'> <input type="text"> <input type="text" v-focus placeholder="我有v-focus,所以,我获取了焦点"> </div>
这里放了两个 input
,但是后面的 input
才使用了我们的自定义 v-focus
指令,所以看到了是后面那个文本框获取了焦点,而不是前面一个.
先总结几个点:
- 使用
Vue.directive()
来新建一个全局指令,(指令使用在HTML元素属性上的) Vue.directive('focus')
第一个参数focus
是指令名,指令名在声明的时候,不需要加v-
- 在使用指令的HTML元素上,
<input type="text" v-focus placeholder="我有v-focus,所以,我获取了焦点"/>
我们需要加上v-
. Vue.directive('focus',{})
第二个参数是一个对象,对象内部有个inserted()
的函数,函数有el
这个参数.el
这个参数表示了绑定这个指令的DOM元素
,在这里就是后面那个有placeholder
的input
el
就等价于document.getElementById('el.id')
....- 可以利用
$(el)
无缝连接jQuery
指令的生命周期
其实上面个例子很尬!
HTML5 本身就提供了一个 autofocus
的属性,我们直接写这个就OK了.
用指令我们需要:
- 新增一个指令
- 定义指令的第二个参数里的
inserted
函数 - 在需要获取焦点的元素上,使用这个指令.
非常的费时费力....
在说明,为什么我要这么麻烦的使用指令之前,可以先了解一下指令的一些基本知识.
上述例子中,我们写了一个叫 inserted(){}
的函数,
有了 inserted
就说明了,指令在绑定到 HTML 元素上时,肯定也是有一堆钩子函数的,说白了也就是生命周期.
当一个指令绑定到一个元素上时,其实指令的内部会有五个生命周期事件函数.
先上官方说明:
-
bind(){}
当指令绑定到 HTML 元素上时触发.只调用一次. -
inserted()
当绑定了指令的这个HTML元素插入到父元素上时触发(在这里父元素是div#app
).但不保证,父元素已经插入了 DOM 文档. -
updated()
所在组件的VNode
更新时调用. -
componentUpdate
指令所在的组件的VNode
以及其子VNode
全部更新后调用. -
unbind
: 指令和元素解绑的时候调用,只调用一次
Vue.directive('gqs',{ bind() { // 当指令绑定到 HTML 元素上时触发.**只调用一次** console.log('bind triggerd') }, inserted() { // 当绑定了指令的这个HTML元素插入到父元素上时触发(在这里父元素是 `div#app`)**.但不保证,父元素已经插入了 DOM 文档.** console.log('inserted triggerd') }, update() { // 所在组件的`VNode`更新时调用. console.log('update triggerd') }, componentUpdated() { // 指令所在组件的 VNode 及其子 VNode 全部更新后调用。 console.log('componentUpdated triggerd') }, unbind() { // 只调用一次,指令与元素解绑时调用. console.log('unbind triggerd') } })
HTML
<div id='app' v-gqs></div>
结果
bind triggerd
inserted triggerd
发现默认情况下只有 bind
和 inserted
声明周期函数触发了.
那么剩下的三个什么时候触发呢?
<div id='app' > <p v-gqs v-if="show">v-if是删除或者新建dom元素,它会触发unbind指令声明周期吗?</p> <button @click="show=!show">toggle</button> </div>
一开始猜测 unbind
应该是删除元素的时候触发,也是弄了个 v-if
.
然后点击按钮,发现果然如此.
当指令绑定的元素被销毁时,会触发指令的 unbind
事件.
(新建并显示,仍然是触发 bind
& inserted
)
- v-show的显示/隐藏
- :style与:class的样式改变时(:style={fontSize:fontSize+'px'} :style={changeClass: bool} )
- 内容改变 (v-model="text") v-mode一定要绑定,否则无法触发
注意:使用this.$refs.<dom>来修改隐藏、显示、样式、内容是无法触发update()和componentUpdated()
利用指令,可以做一些小事情.
既然,指令并不是一次性的活.
当绑定指令的元素的状态发生改变时(这里主要是指元素绑定的vue数据发生改变时),仍然会触发指令中的 update
函数.
那么我们可以利用指令的简写形式,来做一些有意思的事情.
核心思想就是:
当一个HTML元素设置了指令,那么在这个元素的状态发生改变时(由vue数据变化带来的带来的监控
),我们可以利用update()钩子函数监控到这个元素的变化,然后根据需要做一些其他的事情.
使用官方指定的指令简写模式:
Vue.directive('color-swatch', function (el, binding) { el.style.backgroundColor = binding.value })
inserted
or update
.
当元素的状态发生改变时,就会触发 update
在写demo之前,还需要了解一下指令钩子函数的几个参数.
el
: 绑定指令的那个dom元素.(doucument.getElementById('el.id')binding
: 一个对象name
:v-gqs
==>gqs
不包括前面的v-
valule
: 指令后面的值v-gqs='abc'
value=abcoldValue
前一个值,只能在update
&componentUpdate
中使用.expression
:v-gqs='1+1'
,如果是value
=2
,如果是expression
=1 + 1
arg
: 指令传递的参数 ,比如v-gqs:hello
arg = hellomodifiers
: 比如v-gqs.a.b
modifiers
= {a:true,b:true}
vnode
:Vue编译生成的虚拟节点.oldVnode
:上一个虚拟节点,仅在update
&componentUpdated
中可用.
Vue.directive('change-bgc', (el, binding,vnode,oldVnode) => { el.style.backgroundColor = 'red' console.log(`binding.name:${binding.name}`) console.log(`binding.value:${binding.value}`) console.log(`binding.expression:${binding.expression}`) console.log(`binding.arg:${binding.arg}`) console.log(`binding.modifiers:${JSON.stringify(binding.modifiers)}`) console.log(`binging.oldValue:${binding.oldValue}`) console.log(`vnode:${Object.keys(vnode).join(',')}`) console.log(`oldVnode:${JSON.stringify(oldVnode)}`) })
binding.name:change-bgc binding.value:2 binding.expression:1+1 binding.arg:foo binding.modifiers:{"left":true,"bottom":true} binging.oldValue:undefined vnode:tag,data,children,text,elm,ns,context,fnContext,fnOptions,fnScopeId,key,componentOptions,componentInstance,parent,raw,isStatic,isRootInsert,isComment,isCloned,isOnce,asyncFactory,asyncMeta,isAsyncPlaceholder oldVnode:{"tag":"","data":{},"children":[],"raw":false,"isStatic":false,"isRootInsert":true,"isComment":false,"isCloned":false,"isOnce":false,"isAsyncPlaceholder":false}