Vue从入门到实战:内置指令
目录
v-show
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>v-show指令</title> </head> <body> <div id="app"> <h1 v-show="yes">Yes!</h1> <h1 v-show="no">No!</h1> <h1 v-show="age >= 25">Age: {{ age }}</h1> <h1 v-show="name.indexOf('Smith') >= 0">Name: {{ name }}</h1> </div> <script src="vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { yes: true, no: false, age: 28, name: 'Will Smith' } }) </script> </body> </html>
v-show指令是通过CSS样式属性display来控制元素的显示与否。
如果要显示或隐藏多个元素怎么办呢 ? 我们可以使用HTML5 新增的<template>元素来包裹需要切换的显示与隐藏的多个元素,在<template>上使用v-show指令。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>v-show指令</title> </head> <body> <div id="app"> <template v-show="!isLogin"> <form> <p>username: <input type="text"></p> <p>password: <input type="password"></p> </form> </template> </div> <script src="vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { isLogin: false } }) </script> </body> </html>
v-if/v-else-if/v-else
v-if指令
v-if指令根据表达式的值的真假来生成或删除一个元素。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>v-if指令</title> </head> <body> <div id="app"> <h1 v-if="yes">Yes!</h1> <h1 v-if="no">No!</h1> <h1 v-if="age >= 25">Age: {{ age }}</h1> <h1 v-if="name.indexOf('Smith') >= 0">Name: {{ name }}</h1> </div> <script src="vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { yes: true, no: false, age: 28, name: 'Will Smith' } }) </script> </body> </html>
v-if指令在HTML元素的显示与否的实现机制上与v-show指令不同,当表达式的值计算为false时,v-if指令不会创建该元素。
v-else-if/v-else
v-else-if 是在vue2.1.0版本中新增,与v-if一起使用,可以使用互斥的条件判断。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="app"> <span v-if="score >= 85">优秀</span> <span v-else-if="score >= 75">良好</span> <span v-else-if="score >= 60">及格</span> <span v-else>不及格</div> </div> <script src="vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { score: 90 } }) </script> </body> </html>
当一个条件满足时,后续的条件都不会再判断。
用key管理可复用的元素
vue会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。例如在下面的代码中,vue为了提高渲染效率,复用了<input>元素。
但是如果我们不希望在E-mail输入框中看到之前输入的用户名,这可以通过为<input>元素添加一个具有唯一值的key属性。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>v-if-key</title> </head> <body> <div id="app"> <template v-if="loginType === 'username'"> <label>用户名:</label> <input placeholder="请输入你的用户名" key="username-input"> </template> <template v-else> <label>Email:</label> <input placeholder="请输入你的Email" key="email-input"> </template> <p><button v-on:click="changeLoginType">切换登录方式</button></p> </div> <script src="vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { loginType: 'username' }, methods: { changeLoginType(){ if(this.loginType === 'username'){ this.loginType = "email"; } else{ this.loginType = "username"; } } } }) </script> </body> </html>
v-for指令
v-for指令就是通过循环的方式来渲染一个列表,循环的对象可以是数组,也可以是一个Javascript对象。
v-for遍历数组
vue实例的数据对象定义了一个数组属性books,然后在数组更新检测
为了检测数组中元素的变化,以便及时将变化反映到视图中,Vue对数组的下列变异方法进行了包裹:
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
如:
vm.books.push({title:'Java Web开发详解'})
数组中还有一些非变异方法,如filter(),concat(),slice() ,他们不会改变原始数组:
vm.books =vm.books.concat([{title:'Java Web开发详解'},{title: 'Java无难事'}])
vue在检测到数组变化时,并不是直接重新渲染整个列表,而是最大化地复用DOM元素。替换的数组中,含有相同元素的项不会被重新渲染,因此可以大胆地使用新数组来替换旧数组,不用担心性能问题。
为了解决部分方法的数组变动 vue检测不到的问题,可采用下列方法:
//使用Vue的全局set()方法 Vue.set(vm.books,0,{title: 'Java Web开发详解'}) //使用数组原型的splice()方法 vm.books.splice(0,1,{title: 'Java Web开发详解'})
过滤与排序
有时想显示一个数组经过过滤或排序后的版本,但不实际改变或重置原始数据。
在这种情况下,可以创建一个计算属性,来返回经过过滤或排序后的数组
<nowiki> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="app"> <ul> <li v-for="n in evenNumbers">{{ n }}</li> </ul> </div> <script src="vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { numbers:[1,2,3,4,5] }, computed:{ evenNumbers:function(){ return this.numbers.filter(function (number){ return number %2 ===0 }) } } }) </script> </body> </html></nowiki>
v-for遍历整数
v-for指令也可以接受整数。
<div> <span v-for="n in 10">{{ n }} </span> </div>
v-for遍历对象
遍历对象的语法形式和遍历数组是一样的,即value in object
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="app"> <ul> <li v-for="(value, key, index) in book">{{index}}. {{key}} : {{value}}</li> </ul> </div> <script src="vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { book: { title: 'VC++深入详解', author: '孙鑫', isbn: '9787121362217' } } }) </script> </body> </html>
对象更新检测
由于Javascripts的限制,Vue不能检测对象属性的添加和删除。要解决这个问题,可以使用Vue全局的set()和delete()方法来添加和删除属性,或是Vue实例的$set()和$delete()方法来添加和删除属性,并触发视图更新。
Vue.set(vm.book,'publishDate','2019-06-01') vm.$set(vm.book,'publishDate','2019-06-01') Vue.delete(vm.book,'isbn') vm.$delete(vm.book,'isbn')
在<template>上使用v-for
类似v-show和v-if,也可以利用带有v-for指令的<template>来渲染一段包含多个元素的内容。代码如下所示:
<ul> <template v-for="item in items"> <li>{{ item.msg }}</li> <li class="divider" role="presentation"></li> </template> </ul>
key属性
为了给Vue一个提示,以便它能够跟踪每个节点的身份,从而重用和重新排序现有元素,需要为列表中每一项提供一个唯一key属性。
key属性的类型只能是string或者number类型。
如下文中的v-bind:key="book.id"
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="app"> <p> ID:<input type="text" v-model="bookId"/> 书名:<input type="text" v-model="title"/> <button v-on:click="add()">添加</button> </p> <p v-for="book in books" v-bind:key="book.id"> <input type="checkbox"> <span>ID:{{book.id}} , 书名:{{book.title}}</span> </p> </div> <script src="vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { bookId: '', title: '', books: [ {id: 1 ,title: 'Vue无难事'}, {id: 2, title: 'VC++深入详解'}, {id: 3, title: 'Servlet/JSP深入详解'} ] }, methods:{ add(){ this.books.unshift({ id : this.bookId, title : this.title }); this.bookId = ''; this.title = ''; } } }) </script> </body> </html>
v-for与v-if一同使用
如果渲染一个列表时,对列表中的某些项需要根据条件来判断是否渲染,那么就可以将v-if和v-for联合一起使用。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="app"> <h1>已完成的工作计划</h1> <ul> <li v-for="plan in plans" v-if="plan.isComplete"> {{plan.content}} </li> </ul> <h1>未完成的工作计划</h1> <ul> <li v-for="plan in plans" v-if="!plan.isComplete"> {{plan.content}} </li> </ul> </div> <script src="vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { plans: [ {content: '写《Vue无难事》', isComplete: false}, {content: '买菜', isComplete: true}, {content: '写PPT', isComplete: false}, {content: '做饭', isComplete: true}, {content: '打羽毛球', isComplete: false} ] } }) </script> </body> </html>
v-bind
v-bind指令主要用于响应更新HTML元素的属性,将一个或多个属性或者一个组件的prop动态绑定到表达式。
<nowiki> <div id="app"> <!-- 绑定一个属性 --> <img v-bind:src="imgSrc"> <!-- 缩写 --> <img :src="imgSrc"> <!-- 动态属性名 (2.6.0+) --> <a v-bind:[attrname]="url">链接</a> <!-- 内联字符串拼接 --> <img :src="'images/' + fileName"> <!-- 绑定一个有属性的对象 --> <form v-bind="formObj"> <input type="text"> </form> </div>
<nowiki> var vm = new Vue({ el: '#app', data: { attrname: 'href', url: 'https://www.phei.com.cn/', imgSrc: 'images/bg.jpg', fileName: 'bg.jpg', formObj: { method: 'get', action: '#' } } })
</nowiki>
v-bind指令还可以直接绑定一个有属性的对象,代码如下所示:
<!-- 绑定一个有属性的对象 --> <form v-bind="formObj"> <input type="text"> </form>
<nowiki>var vm = new Vue({ el: '#app', data: { formObj: { method: 'get', action: '#' } } })
</nowiki>
v-model
v-model指令用来在表单<input>、<textarea>及<select>元素上创建双向数据绑定,
它会根据控件类型自动选取正确的方法来更新元素。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="app"> <input type="text" v-model="message"> </div> <script src="vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { message: 'Hello World' } }) </script> </body> </html>
在浏览器Console窗口输入,并回车:
vm.message="welcome"
这时输入框中的文字也变为welcome
在输入框中输入hello world,
这时在浏览器Console窗口输入vm.message,并回车
也显示:
"hello world"
这就是所谓的创建双向数据绑定。
v-on
v-on指令用于监听DOM事件,并在触发时运行一些Javascript代码
<nowiki><!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="app"> <p> <!--(1)click事件直接使用JavaScript语句--> <button v-on:click="count += 1">Add 1</button> <span>count: {{count}}</span> </p> <p> <!--(2)click事件直接绑定一个方法--> <button v-on:click="greet">Greet</button> <!--缩写语法--> <button @click="greet">Greet</button> </p> <p> <!--(3)click事件使用内联语句调用方法--> <button v-on:click.once="say('Hi')">Hi</button> </p> <a href="/login" v-on:click.prevent="login">登录</a> </div> <script src="vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { count: 0, message: 'Hello, Vue.js!' }, // 在选项对象的methods属性对象中定义方法 methods: { greet: function() { // 方法内this指向vm alert(this.message) }, // 对象方法的简写语法 say(msg) { alert(msg) }, login(event){ // ... //event.preventDefault(); } } }) </script> </body> </html>
</nowiki>
说明:
- 方法是在选项对象的method属性中定义的,该属性是一个对象属性,在method属性中定义的方法,可以直接通过Vue实例来访问。
- 一定不要使用箭头函数来定义method方法。
- 当Vue实例销毁时,所有的事件处理器都会被自动删除,所以无须担心如何清理他们。
- 在使用v-on指令绑定事件处理器时,就可以使用$event传入原始的DOM事件对象,然后在事件处理器方法中访问原生的事件对象
<a href="/login" v-on:click="login($event)">登录</a> //... // 在选项对象的methods属性对象中定义方法 methods: { login(event){ // ... event.preventDefault(); } }
事件修饰符
在事件处理程序中调用event.preventDefault()是非常常见的需求,为了解决这个问题,Vue.js提供了事件修饰符,让我们可以专注于纯粹的数据逻辑,而不需要考虑如何处理DOM事件细节。
Vue提供了如下修饰符:
为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。
- stop
- prevent
- capture
- self
- once
- passive
<nowiki><nowiki><nowiki><!-- 阻止单击事件继续传播 --> <a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 --> <form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 --> <a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 --> <form v-on:submit.prevent></form>
<!-- 添加事件监听器时使用事件捕获模式 --> <!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 --> <div v-on:click.capture="doThis">...</div>
<!-- 只当在 event.target 是当前元素自身时触发处理函数 --> <!-- 即事件不是从内部元素触发的 --> <div v-on:click.self="doThat">...</div></nowiki></nowiki>
</nowiki>
针对前面调用event.preventDefault()方法来阻止默认的链接跳转行为的需求,使用事件修饰符就可以轻松实现相同的功能。
<a href="/login" v-on:click.prevent="login">登录</a> //... // 在选项对象的methods属性对象中定义方法 methods: { login(event){ // ... } }
按键修饰符
在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` --> <input v-on:keyup.enter="submit"> <!-- 使用回车键的按键码 --> <input v-on:keyup.13="submit">
为了在必要的情况下支持旧浏览器,Vue 提供了绝大多数常用的按键码的别名:
- .enter
- .tab
- .delete (捕获“删除”和“退格”键)
- .esc
- .space
- .up
- .down
- .left
- .right
要想在同时按下Ctrl+某个键时触发keyup.ctrl ,那么需要用Ctrl的虚拟机代码17来代替Ctrl修饰键
<input @keyup.17.67="doSomething">
.exact修饰符
.exact 修饰符允许你控制由精确的系统修饰符组合触发的事件。
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 --> <button v-on:click.ctrl="onClick">A</button> <!-- 有且只有 Ctrl 被按下的时候才触发 --> <button v-on:click.ctrl.exact="onCtrlClick">A</button> <!-- 没有任何系统修饰符被按下的时候才触发 --> <button v-on:click.exact="onClick">A</button>
鼠标按钮修饰符
- .left
- .right
- .middle
这些修饰符会限制处理函数仅响应特定的鼠标按钮。
v-text
v-text元素用于更新元素的文本内容
<!DOCTYPE html> <html> <head> <meta charset="gbk"> <title></title> </head> <body> <div id="app"> <span v-text="message"></span> <!-- 等价于 <span v-text>{{message}}</span> --> </div> <script src="vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { message: 'Hello Vue.js' } }) </script> </body> </html>
如果只是更新部分文本内容,那么还是用{{Mustache}}插值形式。
v-html
v-html指令用于更新元素的innerHTML,该部分内容作为普通的HTML代码插入,不会作为Vue模板进行编译。
<div id="app"> <div v-html="hElt"></div> </div>
var vm = new Vue({ el: '#app', data: { hElt: "<h1>《Vue.js无难事》</h1>" } })
在网站上动态渲染任意的HTML是非常危险的,因为很容易导致XSS攻击。
切记,只在可信的内容上使用v-html,永远不要在用户提交的内容上使用v-html.
v-once
v-once指令可以让元素或组件只渲染一次。之后再次渲染是,元素/组件及其所有的子节点被视为静态内容并跳过。
<nowiki><!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style> a { margin: 20px; } </style> </head> <body> <div id="app"> <h1>{{title}}</h1> <a v-for="nav in navs" href="nav.url" v-once>{{nav.name}}</a> </div> <script src="vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { title: 'v-once指令的用法', navs: [ {name: '首页', url: '/home'}, {name: '新闻', url: '/news'}, {name: '视频', url: '/video'}, ] } }) </script> </body> </html>
</nowiki>
v-pre
v-pre指令也不需要表达式,用于跳过这个元素和它的子元素的编译过程。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="app"> <h1 v-pre>{{message}}</h1> </div> <script src="vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { message: 'Vue.js无难事', } }) </script> </body> </html>
v-cloak
v-cloak指令可以隐藏未编译的Mustache标签直到实例准备完毕。
<nowiki> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style> [v-cloak] { display: none; } </style> </head> <body> <div id="app"> <h1 v-cloak>{{message}}</h1> </div> <script src="vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { message: 'Vue.js无难事', } }) </script> </body> </html></nowiki>