一、自定义全局指令
开门见山 举个栗子:
<label>
搜索
<input type="text" id="search">
</label>
此时 若要触发这个输入框的获得焦点事件 在原生方法中是这样的:
document.getElementById("search").focus();
而在Vue中 使用自定义指令来实现该效果
指令 就是形如v-model v-text之类的 只不过这些是Vue默认提供的
而自定义指令 就是自定义的(废话
在Vue中 所有的指令使用的时候都以v-
开头
自定义一个名为v-focus的自定义指令:
加在标签中
<label>
搜索
<input type="text" id="search" v-focus>
</label>
然后 用Vue.directive()来定义全局指令
语法:Vue.directive(指令名称,对象)
第一个参数是指令的名称 在定义的时候 指令前面无需加上v-的前缀 但在调用的时候必须加
第二个参数是个对象 该对象上面有一些指令相关的钩子函数 这些函数可以在特定阶段执行相关的操作
在每个钩子函数中 第一个参数永远是el 其表示被绑定了该指令的元素(element)【当然 参数名可随意取】
它是原生的js的dom对象 因此可以在其上面尽情使用js方法
常用的钩子函数有bind inserted和updated:
- bind是每当指令绑定到元素上时 会立即执行该bind函数
其只会执行一次 因为一个指令只能绑定到一个元素上一次 - inserted是当元素插入到DOM中的时候会执行该inserted函数
其也只会执行一次 - updated是当DOM节点(VNode组件)更新的时候 会执行该upload函数
可能会触发多次
Vue.directive("focus",{
// 钩子函数
// 在bind刚绑定的时候 元素还并没有被放到dom中去 因此此时调用focus()方法没作用 不会生效 因为一个元素只有在插入dom之后才能获取焦点
bind:function(el)
{
// el.focus();
},
// 元素插入到DOM中的时候会执行该inserted函数
// 【只会执行一次】
inserted:function(el)
{
el.focus();
},
// 当DOM节点(VNode组件)更新的时候 会执行该upload函数
// 【可能会触发多次】
updated:function(el)
{
}
})
除此之外 还有:
- componentUpdated:指令所在组件的DOM节点(VNode组件)及其子DOM节点(VNode组件)全部更新后调用
- unbind:指令与元素解绑时调用
只调用一次
如此 即可实现自定义指令了
当然 样式和行为还是有区别的:
何为样式?样式就是比如设置颜色之类的
而行为 就是比如focus()之类的js行为
拿自定义字体颜色指令举个栗子吧:
Vue.directive("color",{
bind:function(el)
{
el.style.color="aqua";
}
})
我们发现样式是可以在bind里设置的
那是因为因为只要样式被解析了 那么显示在页面上就会带有颜色
样式只要通过指令绑定给了元素 不管这个元素有没有被插入到页面中去 这个元素肯定会有了一个内联样式
在那之后 元素肯定会显示到页面中 在这个时候 浏览器的渲染引擎必然会解析样式 然后应用给该元素
但 focus()之类的方法是一个行为 行为必须添加到DOM中才能获得焦点 在bind的时候还只是在内存中 并没有添加到DOM上
在内存中调用的行为 然后再渲染到页面上时 自然是无效的
而insert是到了页面上之后才调用 因此行为会有效
总而言之 和js行为有关的操作最好在inserted里执行 防止js行为不生效
而 和样式相关的操作 通常可以放在bind中执行
在自定义指令中拿到传递的值
在定义的时候 要加上引号 因为传递的是一个字符串
若不加引号 则会识别为是一个变量
<input type="text" id="search" v-color="'blue'">
首先 看一下钩子函数共有哪些参数:
el
:指令所绑定的元素 可用来直接操作DOMbinding
:一个对象 包含以下属性:
name:指令名(不包括v-前缀)
value:指令的绑定值
例:在v-my-directive=“1+1"中 绑定值是为2 即:value是经过字符串解析后的结果
oldValue:指令绑定的前一个值
仅在update和componentUpdated钩子中可用
无论值是否改变都可用
expression:字符串形式的指令表达式
例:在v-my-directive=“1+1"中 表达式为"1+1” 即:expression是不经过字符串解析后的结果 原原本本的结果
arg:传给指令的参数
例:在v-my-directive:foo中 参数为"foo”
modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }vnode
:Vue 编译生成的虚拟节点oldVnode
:上一个虚拟节点
仅在update和componentUpdated钩子中可用
拿到传递的值
例:
// 自定义设置字体颜色指令
Vue.directive("color",{
bind:function(el,binding) // 此处的el和binding可任意命名
{
console.log(binding.value);
el.style.color=binding.value;
}
})
二、自定义私有指令
就像过滤器一样 指令也是不但有共有的指令 也有私有的指令
自定义私有指令其实和自定义私有过滤器类似
都是在Vue实例中的属性对象里进行设置
<div id="app2">
<h3 v-fontWeight="1000">{{date | dateFormat}}</h3>
</div>
<script>
var vm2=new Vue({
el:'#app2',
data:{
date:new Date()
},
methods:{},
filters:{},
// 自定义私有指令
directives:{
"fontweight":{
bind:function(el,binding)
{
el.style.fontWeight=binding.value;
}
}
}
})
</script>
三、指令的简写
Vue的自定义指令还支持简写
如果只想在bind
和update
这两个钩子上进行重复的动作
且不关心其它的钩子函数
那么 可以直接在指令名后面跟上方法
例:
<div id="app2">
<h3 v-fontWeight="1000" v-fontsize="'50'">{{date | dateFormat}}</h3>
</div>
<script>
var vm2=new Vue({
el:'#app2',
data:{
date:new Date()
},
methods:{},
filters:{},
// 自定义私有指令
directives:{
// 字体粗细
"fontweight":{
bind:function(el,binding)
{
el.style.fontWeight=binding.value;
}
},
// 字体大小
"fontsize":function(el,binding) // 该function就相当于将里面的代码写到【且只写到】bind和update钩子上去了
{
el.style.fontSize=parseInt(binding.value)+"px";
}
}
})
</script>