指令是带有 v- 前缀的特殊属性,指令属性的预期是单个JavaScript表达式(v-for例外),指令的职责是当表达式的值改变的时候,将其产生的连带影响响应式地作用于DOM。
一个指令能够接收一个"参数", 在指令名称之后以冒号表示 ,例如:v-bind指令可以响应式地更新HTML属性:
<body> <div id="app"> <a v-bind:href="url">百度</a> </div> <script src="./node_modules/vue/dist/vue.min.js"></script> <script> var app = new Vue({ el: '#app', data: { url: 'http://www.baidu.com' } }) </script> </body>这里的 href 就是参数,用来告知v-bind指令将元素的href属性与表达式url的值进行绑定。
从2.6.0开始,可以用方括号扩起来的JavaScript表达式作为一个指令的参数:
<a v-bind:[attributename]="url"></a>这里的attributename会被作为一个JavaScript表达式进行动态求值,求得的值将会作为最终的参数来使用。
<body> <div id="app"> <a v-bind:[attributename]="url">百度</a> </div> <script src="./node_modules/vue/dist/vue.js"></script> <script> new Vue({ data: { attributename: 'href', url: 'http://www.baidu.com' } }).$mount('#app') </script> </body>动态参数预期会求出一个字符串,异常情况下值为null,这个特殊的null值可以被显性地用于移除绑定。任何其它非字符串类型的值都将会触发一个警告。
动态参数表达式有一些语法约束,因为某些字符,如空格和引号,放在HTML属性名里是无效的,例如:
<!-- 这会触发一个编译警告 --> <a v-bind:['foo' + bar]="value"></a>变通的办法是使用没有空格或者引号的表达式,或者是使用计算属性替代这种复杂表达式。另外,在DOM中使用模板时(直接在一个HTML文件里撰写模板),还需要避免使用大写字符来命名,因为浏览器会把属性名全部强制转换为小写:
<!-- DOM会转换为 'v-bind:[someattr]' --> <a v-bind:[someAttr]="value"></a>修饰符是以半角句号"."指明的特殊后缀,用于指出一个指令应该以特殊方式绑定,例如:.prevent 修饰符告诉v-on指令对于触发的事件调用event.preventDefault()方法:
<body> <div id="app"> <!-- 阻止了跳转,只会弹窗 --> <a href="http://www.baidu.com" v-on:click.prevent="handle">百度</a> </div> <script src="./node_modules/vue/dist/vue.min.js"></script> <script> var app = new Vue({ el: '#app', methods: { handle() { alert('Hello World') } }, }) </script> </body>除了内置的指令,Vue还允许注册自定义指令,有的情况下,你仍然需要对普通的DOM元素进行底层操作,这个时候使用自定义指令更为方便。
注册自定义指令有两种方法:
全局注册 Vue.directive('指令名',{ // el代表使用了此指令的那个DOM元素 // binding 可获取使用了此指令的绑定值、表达式、指令名等 inserted: function(el, binding) { // 逻辑代码 } }) 局部注册 let vm1 = new Vue({ el: '#app', directives: { '指令名': { // el代表使用了此指令的那个DOM元素 // binding 可获取使用了此指令的绑定值、表达式、指令名等 inserted: function(el, binding) { // 逻辑代码 } } } })注意:注册的时候指令名称不要带 v- 前缀
注册成功之后就可以使用这个自定义指令:
引用指令的时候,需要在前面加上v-直接在元素上使用即可: v-指令名=“表达式” <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title></title> </head> <body> <div id="app"> <p v-upper-text="message"></p> 自动获取焦点:<input type="text" v-focus> </div> <script src="./node_modules/vue/dist/vue.min.js"></script> <script> let app = new Vue({ data: { message : "Hello World" }, directives: { 'upper-text': { bind (el) { el.style.color = 'red'; }, inserted (el, binding) { el.innerHTML = binding.value.toUpperCase(); } }, 'focus' : { inserted (el) { el.focus() } } } }).$mount("#app"); </script> </body> </html>注意:
注册指令的时候,指令名不要带 v- ,但是使用的时候需要加上和js相关的操作,最好放在inserted中执行和css相关的操作,最好放在bind中执行一个指令定义对象可以提供如下几个钩子函数(均为可选):
bind:只调用一次,指令第一绑定到元素时调用,在这里可以一次性的初始化设置inserted:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已经被插入到文章中)update:所在组件的VNode更新时候调用,但是可能发生在其子VNode更新之前。指令的值可能发生了改变,也可能没有发生改变,但是你可以通过比较更新前后的值来忽略不必要的模板更新。componentUpdated:指令所在组件的VNode及其子VNode全部更新后调用unbind:只调用一次,指令与元素解绑时调用指令钩子函数会被传入以下参数:
el:指令所绑定的元素,可以用来直接操作DOMbinding:一个对象,包含以下属性: name:指令名称,不包括 v- 前缀value:指令的绑定值,例如:v-my-directive=“1 + 1”,绑定值为2oldValue:指令绑定的前一个值,仅在update和componentUpdated钩子中可用,无论值是否改变都可以用expression:字符串形式的指令表达式。例如:v-my-directive=“1 + 1”,表达式为 1 + 1arg:传给指令的参数,可选。例如:v-my-directive:foo中,参数为foomodifiers:一个包含修饰符的对象,例如:v-my-directive.foo.bar中,修饰符对象为 {foo: true, bar: true} vnode:vue编译生成的虚拟节点oldVnode:上一个虚拟节点,仅在update和componentUpdated钩子中可用 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title></title> </head> <body> <div id="app"> <p v-demo:foo.a.b="message"></p> </div> <script src="./node_modules/vue/dist/vue.min.js"></script> <script> let app = new Vue({ data: { message : "Hello World" }, directives: { 'demo': { inserted: function (el, binding) { el.innerHTML = 'name: ' + binding.name + '<br>' + 'expression: ' + binding.expression + '<br>' + 'value: ' + binding.value + '<br>' + 'modfiers: ' + JSON.stringify(binding.modifiers) + '<br>' } } } }).$mount("#app"); </script> </body> </html>注意:除了el之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的dataset来进行
指令的参数可以是动态的:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title></title> </head> <body> <div id="app"> <div v-demo:[pos]="200">内容</div> </div> <script src="./node_modules/vue/dist/vue.min.js"></script> <script> let app = new Vue({ data: { message : "Hello World", pos: 'left' }, directives: { 'demo': { bind: function (el, binding) { el.style.position = 'absolute'; el.style[binding.arg] = binding.value + 'px'; } } } }).$mount("#app"); </script> </body> </html>在很多时候,你可能想在bind和update时触发相同的行为,而不关心其它的钩子,可以简写为这样:
Vue.directive('color-swatch', function(el, binding) { })如果指令需要多个值,可以传入一个JavaScript对象字面量,指令函数能够接受所有合法的JavaScript表达式:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title></title> </head> <body> <div id="app"> <p v-demo="{ a: 12, b: 23}"></p> </div> <script src="./node_modules/vue/dist/vue.min.js"></script> <script> let app = new Vue({ directives: { 'demo': function (el , binding) { el.innerHTML = `${binding.value.a} + ${binding.value.b} = ${binding.value.a + binding.value.b}` } } }).$mount("#app"); </script> </body> </html>