【Vue.js 2.0】指令
一、内置指令
1. v-bind 主要用于动态绑定DOM元素属性(attribute),即元素属性实际的值是由vm实例中的data属性提供的。例如:
<img v-bind:src='imgPath' /> <script> var app = new Vue({ data:{ imgPath: 'http://...' } }) </script>
2. v-model 主要对表单元素进行双向数据绑定,在修改表单元素值的同时,实例vm中对应的属性值也同时更新,反之亦然。输入框示例:
<div id="app"> <h1>输入内容为:{{message}}</h1> <input type="text" v-model="message" /> </div> <script> var app = new Vue({ el: '#app', data: { message: 'this is v-model example' } }) </script>
Vue.js 2.0中取消了lazy和number作为参数,用修饰符(modifier)来代替:
<input type="text" v-model.lazy="message" /> <%-- 加lazy后会更改为在change事件中同步 --%> <input type="text" v-model.trim="message" /> <%-- 去掉输入值的首尾空格 --%> <input type="number" v-model.number="message" /> <%-- 自动将用户的输入值转为数值类型。即使input输入框的type=number类型,获取到的值也是string类型,如果加上.number获取到的值则为number类型 --%>
3. v-if v-else v-show 主要用于根据条件展示对应的模板内容。需要注意的是,v-else必须紧跟v-if,不然该指令不起作用,例如:
<div id="app"> <div v-if="yes">yes</div> <p>the v-else div shows</p> <div v-else>no</div> </div> <script> var app = new Vue({ el: '#app', data: { yes: false } }) //显示:the v-else div shows </script>
除了 v-if,v-show 也是可以根据条件展示元素的一种指令。与v-if 不同的是,v-show 元素的使用会渲染并保持在 DOM 中。v-show 只是切换元素的 css 属性 display。v-if 的切换消耗要比 v-show 高,但初始条件为 false 的情况下,v-if 的初始渲染要稍快。
4. v-for 主要用于列表渲染,将根据接收到的数组重复渲染v-for绑定到的DOM元素及内部的子元素,并且可以通过设置别名的方式,获取数组内的数据并渲染到节点中。例如:
<div id="app"> <p>--------------------列表渲染--------------------</p> <ul> <%-- items为data中的属性名,item为别名,可以通过item来获取当前数组遍历的每个元素--%> <li v-for="item in items"> <h3>{{item.title}}</h3> <p>{{item.description}}</p> </li> </ul> <p>--------------------列表渲染 + 索引--------------------</p> <ul> <%-- 也可以用 of 替代 in 作为分隔符,因为它更接近 JavaScript 迭代器的语法;index为当前数组元素的索引--%> <li v-for="(item, index) of items"> <h3>{{index}}:{{item.title}}</h3> <p>{{item.description}}</p> </li> </ul> <p>--------------------列表渲染 + (key, value)形式--------------------</p> <ul> <li v-for="(value, key) of objectDemo"> <h3>{{key}}</h3> <p>{{key}}:{{value}}</p> </li> </ul> <p>--------------------列表渲染 + template--------------------</p> <ul> <template v-for="item in items"> <li>{{ item.title }}</li> <li>{{item.description}}</li> </template> </ul> <p>--------------------迭代1-10--------------------</p> <ul> <%--Vue.js 2.0之后n 由原来的 0 ~ 9 迭代变成 1 ~ 10 迭代--%> <li v-for="n in 10">{{ n }} </li> </ul> <p>--------------------v-bind:key--------------------</p> <%-- key的作用就是为了防止更新了数据的时候重新渲染整个列表,有key相当于做了一个缓存,只会去重新渲染更新了的数据--%> <div v-for="item in items" v-bind:key="item.id"> <h3>{{item.title}}</h3> </div> </div> <script> var app = new Vue({ el: '#app', data: { yes: true, items: [ { title: 'title-1', description: 'description-1' }, { title: 'title-2', description: 'description-2' }, { title: 'title-3', description: 'description-3' }, { title: 'title-4', description: 'description-4' } ], objectDemo: { a: 'a-value', b: 'b-value', c: 'c-value' } } }) </script>
5. v-on 主要用于事件绑定
<div id="app"> <%-- 按钮1、按钮2等价,响应结果:弹框输出 Hello Vue.js --%> <button v-on:click="say">按钮1</button> <button @click="say">按钮2</button> <%-- v-on 也支持内联 JavaScript 语句,但仅限一个语句,响应结果:弹框输出 Hello Vue.js from param --%> <button v-on:click="sayFrom ('from param')">按钮3</button> <%-- 同一元素上也可以通过 v-on 绑定多个相同事件函数,执行顺序为顺序执行,响应结果:依次弹框输出 Hello Vue.js:one;Hello Vue.js:two --%> <button v-on:click="sayFrom (':one'), sayFrom (':two')">按钮4</button> </div> <script> var app = new Vue({ el: '#app', data: { msg: 'Hello Vue.js' }, methods: { say: function () { alert(this.msg); }, sayFrom: function (from) { alert(this.msg + '' + from); } } }) </script>
5.1 .prevent 调用 event.preventDefault();.self只当事件是从侦听器绑定的元素本身触发时才触发回调;v-on:click.self.prevent 和 v-on:click.prevent.self的区别:
<%-- 节点关系:div标签>a标签>P标签 --%> <div style="border: 1px solid #000; padding: 10px; margin: 10px"> <div v-on:click="alert('爷爷')"> <a href="https://www.baidu.com" v-on:click="alert('爸爸')">爸爸 <p v-on:click="alert('儿子')">儿子</p> </a> </div> <%--结果说明:点击'爷爷'会弹出'爷爷'不跳转;点击'爸爸'会依次弹出'爸爸'、'爷爷'并跳转;点击'儿子'会依次弹出'儿子'、'爸爸'、'爷爷'并跳转。这发生了事件冒泡--%> <%--v-on:click.self.prevent 阻止对元素自身的点击,.prevent修饰符在后,修饰的是元素的v-on事件在被.self修饰后的事件,所以它只能阻止对元素自身的点击,无法阻止事件冒泡--%> <div v-on:click="alert('爷爷')"> <a href="https://www.baidu.com" v-on:click.self.prevent="alert('爸爸')">爸爸 <p v-on:click="alert('儿子')">儿子</p> </a> </div> <%--结果说明:点击'爷爷'会弹出'爷爷'不跳转;点击'爸爸'会依次弹出'爸爸'、'爷爷'不跳转;点击'儿子'会依次弹出'儿子'、'爷爷'并跳转。分析:点击自身,.prevent修饰符阻止了<a>标签的默认事件,但是事件冒泡没有阻止;.self修饰符阻止了事件冒泡时触发元素本身绑定的事件 --%> <%--v-on:click.prevent.self 阻止所有的点击,.prevent修饰符在前,修饰的是元素的v-on事件,所以它会阻止所有的点击,自身点击和事件冒泡--%> <div v-on:click="alert('爷爷')"> <a href="https://www.baidu.com" v-on:click.prevent.self="alert('爸爸')">爸爸 <p v-on:click="alert('儿子')">儿子</p> </a> </div> <%--结果说明:点击'爷爷'会弹出'爷爷'不跳转;点击'爸爸'会依次弹出'爸爸'、'爷爷'不跳转;点击'儿子'会依次弹出'儿子'、'爷爷'不跳转。分析:不管是点击自身还是由于事件冒泡,.prevent修饰符都阻止了<a>标签的默认事件;.self修饰符阻止了事件冒泡时触发元素本身绑定的事件 --%> </div>
5.2 v-on:click.stop 调用 event.stopPropagation()
<div id="app"> <div v-on:click="dodo"> <%-- 先弹出'noclick',再弹出'dodo' --%> <button v-on:click="doThis">单击事件</button> <%--只弹出'noclick'--%> <button v-on:click.stop="doThis">阻止单击事件继续传播</button> </div> </div> <script> var app = new Vue({ el: '#app', data: { msg: 'Hello Vue.js' }, methods: { doThis: function () { alert("noclick"); }, dodo: function () { alert("dodo"); } } }) </script>
6. v-text和v-html
<div id="app"> <p v-html="html"></p> <p v-text="text"></p> </div> <script> var app = new Vue({ el: '#app', data: { html: "<h1>html标签在渲染的时候被解析</h1>", text: "<h1>html标签在渲染的时候被源码输出</h1>", }, beforeDestroy: function () { debugger } }) </script>
8. v-once 用于标明元素或组件只渲染一次,即使随 后发生绑定数据的变化或更新,该元素或组件及包含的子元素都不会再次被编译和渲染
<div id="app"> <p>{{message}}</p> <p v-once>{{msg}}</p> </div> <script> var app = new Vue({ el: '#app', data: { message: 'aaa', msg: 'bbb', }, }) </script>
二、自定义指令
1. 注册指令
Vue.directive(id, definition)
2. 指令的定义对象
1 <body> 2 <div id="app"> 3 <div v-lang="color">{{num}}</div> 4 <p> 5 <button v-on:click="add">add</button> 6 </p> 7 </div> 8 <p> 9 <button onclick='unbind()'>解绑</button> 10 </p> 11 12 <script type="text/javascript"> 13 function unbind() { 14 console.log('6 - unbind');//另外起一个方法解绑 15 } 16 17 Vue.directive('lang', { //五个注册指令的钩子函数 18 bind: function () { //被绑定 19 console.log('1 - bind'); 20 }, 21 inserted: function () { //绑定到节点 22 console.log('2 - inserted'); 23 }, 24 update: function () { //组件更新 25 console.log('3 - update'); 26 }, 27 componentUpdated: function () { //组件更新完成 28 console.log('4 - componentUpdated'); 29 }, 30 unbind: function () { //解绑 31 console.log('5 - unbind'); 32 } 33 }) 34 var vm = new Vue({ 35 el: "#app", 36 data: { 37 num: 10, 38 color: 'red' 39 }, 40 methods: { 41 add: function () { 42 this.num++; 43 } 44 } 45 }) 46 </script> 47 </body>
指令的钩子函数(都是可选函数)
- bind: 只被调用一次,在指令第一次绑定到元素上时调用
- inserted:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中)
- update :指令绑定 bind 函数执行后不直接调用 update 函数, 只要组件发生重绘,无论指令接受的值是否发生变化,均会调用 update 函数,update 接收到的参数为 newValue 和 oldValue。如果需要过滤不必要的更新,则可以使用 binding.value == binding.oldValue 来判断
- componentUpdate:当整个组件都完成了 update 状态后即所有 DOM 都更新后调用该钩子函数,无论指令接受的参数是否发生变化
- unbind :指令从元素上解绑时调用,只调用一次
3. 对象字面量
如果指令需要多个值,可以传入一个JavaScript对象字面量,指令函数能够接受所有合法的JavaScript表达式
1 <body> 2 <div id="app"> 3 <div v-demo="{color:'white',text:'hello!'}"></div> 4 </div> 5 6 <script type="text/javascript"> 7 Vue.directive('demo', function (el, binding) { 8 console.log(binding.value.color); // 输出'white' 9 console.log(binding.value.text); // 输出'hello!' 10 }); 11 new Vue({ 12 el: '#app', 13 }); 14 </script> 15 </body>
4. 指令实例属性
1 <body> 2 <div id="app"> 3 <div v-demo="message"></div> 4 </div> 5 6 <script type="text/javascript"> 7 Vue.directive('demo', { 8 bind: function (el, binding, vnode) { 9 let s = JSON.stringify; 10 el.innerHTML = 11 'name:' + s(binding.name) + '<br>' + 12 'value:' + s(binding.value) + '<br>' + 13 'expression:' + s(binding.expression) + '<br>' + 14 'argument:' + s(binding.arg) + '<br>' + 15 'modifiers:' + s(binding.modifiers) + '<br>' + 16 'vnode keys:' + Object.keys(vnode).join(',') 17 } 18 }); 19 new Vue({ 20 el: '#app', 21 data: { 22 message: 'hello' 23 } 24 }); 25 </script> 26 </body>
- el:指定所绑定的元素,可以直接操作DOM
- binding:一个对象,包含若干属性
- vnode:Vue编译生成的虚拟节点
- oldVnode:上一个虚拟节点,尽在update和componentUpdated钩子函数中可用
binding对象包含的属性:
- name:指令名,不包含v-前缀
- value:指令的绑定值,例如:v-mode='1+1'中,绑定值为2
- oldValue:指定绑定的前一个值,仅在update和componentUpdate钩子中可用,无论是否改变都可用
- expression:字符串形式的指令表达式,例如:v-mode='1+1'中,表达式为'1+1'
- arg:传给指令的参数、可选。例如v-demo:foo中,参数为'foo'
- modifiers:一个包含修饰符的对象。例如:v-demo.foo.bar中,修饰符对象为{foo:true,bar:true}