Vue.js 的指令是带有特殊前缀 “v-“ 的 HTML 特性。它绑定一个表达式,并将一些特性应用到 DOM 上。javascript
v-cloak 不须要表达式,它会在 Vue 实例结束编译时从绑定的 HTML 元素上移除,常常和 CSS 的 display: none ;配合使用:css
<div id="app" v-cloak> {{ message }} </div> <script> var app = new Vue({ el: '#app', data: { message: '这是一段文本' } }) </script>
这时虽然已经加了指令 v-cloak ,但其实并无起到任何做用,当网速较慢、Vue.js 文件尚未加载完时,在页面上会显示 {{ message }} 的字样,直到 Vue 建立实例、编译模板时,DOM 才会被替换,因此这个过程屏幕是有闪动的。只要加一句 CSS 就能够解决这个问题了:html
[v-cloak] { display: none; }
在通常状况下,v-cloak 是一个解决初始化慢致使页面闪动的最佳实践,对于简单的项目很实用,可是在具备工程化的项目里,好比在项目的 HTML 机构只有一个空的 div 元素,剩余的内容都是由路由去挂载不一样组件完成的,因此再也不须要 v-cloak 。java
v-once 也是一个不须要表达式的指令,做用是定义它的元素或组件只渲染一次,包括元素或组件的全部子节点。首次渲染后,再也不随数据的变化从新渲染,将被视为静态内容,例如:webpack
<div id="app"> <span v-once>{{ message }}</span> <div v-once> <span>{{ message }}</span> </div> </div> <script> var app = new Vue({ el: "#app", data: { message: '这是一段文本' } }) </script>
v-once 在业务中不多使用,但当须要进一步优化性能时,可能会用到。web
与 JavaScript 的条件语句 if、else、else if 相似,Vue.js 的条件指令能够根据表达式的值在 DOM 中渲染或销毁元素/组件,例如:数组
<div id="app"> <p v-if="status === 1">当status为1时显示该行</p> <p v-else-if="status === 2">当status为2时显示该行</p> <p v-else>不然显示该行</p> </div> <script> var app = new Vue({ el: "#app", data: { status: 1 } }) </script>
v-else-if 要紧跟 v-if,v-else 要紧跟 v-else-if 或 v-if ,表达式的值为真时,当前元素/组件及全部子节点将被渲染,为假时被移除。若是一次判断的是多个元素,能够在 Vue.js 内置的<template>元素上使用条件指令,最终渲染的结果不会包含该元素,例如:app
<div id="app"> <template v-if="status ==== 1"> <p>这是一段文本</p> <p>这是一段文本</p> <p>这是一段文本</p> </template> </div> <script> var app = new Vue({ el: "#app", data: { status: 1 } }) </script>
Vue 在渲染元素时,出于效率考虑,会尽量地复用已有的元素而非从新渲染,好比下面的示例:函数
<div id="app"> <template v-if="type === 'name'"> <label>用户名:</label> <input placeholder="输入用户名"》 </template> <template v-else> <label>邮箱:</label> <input placeholder="输入邮箱"》 </template> <button @click="handleToggleClick">切换输入类型</button> </div> <script> var app = new Vue({ el: '#app', data: { type: 'name' }, nethods: { handleToggleClick: function() { this.type = this.type === 'name' ? 'mail' : 'name'; } } }) </script>
这样键入内容后,点击切换按钮,虽然 DOM 变了,可是以前在输入框键入的内容并无改变,只是替换了 placeholder 的内容,说明 <inpout> 元素被复用了。组件化
若是不但愿这样复用,可使用 Vue.js 提供的 key 属性,它可让你本身决定是否要复用元素,key 的值必须惟一的,例如:
<div id="app"> <template v-if="type === 'name'"> <label>用户名:</label> <input placeholder="输入用户名" key="name-input"> </template> <template v-else> <label>邮箱:</label> <input placeholder="输入邮箱" key="mail-input"> </template> <button @click="handleToggleClick">输入类型切换</button> </div> <script> var app = new Vue({ el: '#app', data: { type: 'name' }, methods: { handleToggleClick: function() { this.type = this.type === 'name' ? 'mail' : 'name'; } } }) </script>
v-show (v-show 不能在<template>上使用)的用法与 v-if 基本一致,只不过 v-show 是改变元素的 CSS 属性 display 。当 v-show 表达式的值为 false 时,元素会隐藏,查看 DOM 结构会看到元素上加载了内联样式 display: none;,例如:
<div id="app"> <p v-show="status === 0">当 status 为 0 时显示该行</p> </div> <script> var app = new Vue({ el: '#app', data: { status: 1 } }) </script>
渲染后的结果为:
<p style="dispaly: none;">当 status 为 1 时显示该行</p>
v-if 和 v-show 具备相似的功能,不过 v-if 才是真正的条件渲染,它会根据表达式适当地销毁或重建元素及绑定的事件或子组件。若表达式初始值为 false ,则一开始元素/组件并不会渲染,只有当条件第一次变为真时才开始编译。
而 v-show 只是简单的 CSS 属性切换,不管条件真与否,都会被编译。相比之下,v-if 更适合条件不常常改变的场景,由于它切换开销相对较大,而 v-show 适用于频繁切换条件。
当须要一个数组遍历或枚举一个对象循环显示时,就会用到列表渲染指令 v-for 。它的表达式须要结合 in 来使用,相似 item in items 的形式,例如:
<div id="app"> <ul> <li v-for="book in books">{{ book.name }}</li> </ul> </div> <script> var app = new Vue({ el: '#app', data: { books: [ { name: '《Oracle 从删库到跑路》'}, { name: '《MySql 从删库到跑路》' }, { name: '《JavaScript 高级程序设计》' } ] } }) </script>
在表达式中,books 是数据,book 是当前数组元素的别名,循环出的每一个 <li> 内的元素均可以访问到对应的当前数据 book 。列表渲染也支持用 of 来代替 in 做为分割符,它更接近 JavaScript 迭代器的语法:
<li v-for="book of books">{{ book.name }}</li>
v-for 的表达式支持一个可选参数做为当前项的索引,例如:
<div id="app"> <ul> <li v-for="book in books">{{ index }} - {{ book.name }}</li> </ul> </div> <script> var app = new Vue({ el: '#app', data: { books: [ { name: '《Oracle 从删库到跑路》'}, { name: '《MySql 从删库到跑路》' }, { name: '《JavaScript 高级程序设计》' } ] } }) </script>
分割符 in 前的语句使用括号,第二项就是 books 当前项的索引 (在 Vue.js 1.x 的版本,这里的 index 也能够由内置的 $index 代替,不过,在 2.x 版本里取消了该用法)。
与 v-if 同样,v-for 也能够用在内置标签 <template> 上,将多个元素进行渲染:
<div id="app"> <ul> <template v-for="book in books"> <li>书名:{{ book.name }}</li> <li>做者:{{ book.author }}</li> </template> </ul> </div> <script> var app = new Vue({ el: '#app', data: { books: [ { name: '《Oracle 从入门到跑路》', author: 'Mart' }, { name: '《MySql 从入门到跑路》', author: '尹成' }, { name: '《JavaScript 高级程序设计》', author: 'Nicholas C.Zakas' } ] } }) </script>
除数组外,对象的属性也是能够遍历的,例如:
<div id="app"> <span v-for="value in user">{{ value }}</span> </div> <script> var app = new Vue({ el: '#app', data: { user: { name: '王麻子', gender: '男', age: 28 } } }) </script>
渲染后的结果为:
<span>王麻子</span><span>男</span><span>28</span>
遍历对象属性时,有两个可选参数,分别是键名和索引:
<div id="app"> <ul> <li v-for="(value, key, index) in user" > {{ index }} - {{ key }} : {{ value }} </li> </ul> </div> <script> var app = new Vue({ el: '#app', data: { user: { name: '王麻子', gender: '男', age: 28 } } }) </script>
v-for 还能够迭代整数:
<div id="app"> <span v-for="n in 100">{{ n }}</span> </div> <script> var app = new Vue({ el: '#app' }) </script>
Vue 的核心是数据与视图的双向绑定,当咱们修改数组时,Vue 会检测到数据变化,因此用 v-for 渲染的视图也会当即更新。Vue 包含了一组观察数组变异的方法,使用它们改变数组也会触发视图更新:
· push()
· pop()
· shift()
· unshift()
· splice()
· sort()
· reverse()
例如,将以前的示例的数据 books 添加一项:
app.books.push({ name: '《CSS揭秘》', author: '[希] Lea Verou' });
使用上述方法会改变被这些方法调用的原始数组,有些方法不会改变原数组,例如:
· filter()
· concat()
· slice()
它们返回的是一个新数组,在使用这些非变异方法时,能够用新数组来替换原数组,仍是以前展现示例,找出含有 JavaScript 关键词的书目,例如:
<div id="app"> <ul> <template v-for="book in books"> <li>书名:{{ book.name }}</li> <li>做者:{{ book.author }}</li> </template> </ul> </div> <script> var app = new Vue({ el: '#app', data: { books: [ { name: '《Oracle 从入门到跑路》', author: 'Mart' }, { name: '《MySql 从入门到跑路》', author: '尹成' }, { name: '《JavaScript 高级程序设计》', author: 'Nicholas C.Zakas' } ] } }); app.books = app.books.filter(function (item) { return item.name.match(/JavaScript/); }); </script>
渲染的结果中,只显示了书名中含有 JavaScript 的选项。
Vue 在检测到数组变化时,并非直接从新渲染整个列表,而是最大化地复用 DOM 元素。替换的数组中,含有相同元素的项不会被从新渲染,所以能够大胆地用新数组来替换旧数组,不用担忧性能问题。
须要注意的是,如下变更的数组中,Vue 是不能检测到的,也不会触发视图更新:
· 经过索引直接设置项,好比 app.books[2]={...} 。
· 修改数组长度,好比 app.books.length = 1 。
解决第一个问题能够用两种方法实现一样的效果,第一种是使用 Vue 内置的 set 方法:
Vue.set(app.books, 3, { name: '《CSS 揭秘》', author: '[希] Lea Verou' });
若是是在 webpack 中使用组件化的方式,默认是没有导入 Vue 的,这是可使用 $set ,例如:
this.$set(app.books, 3, { name: '《CSS 揭秘》', author: '[希] Lea Verou' })
这里的 this 指向的就是当前组件实例,即 app 。在非 webpack 模式下也能够用 $set 方法,例如 app.$set(...) 。另外一种方法:
app.books.splice(3, 1, { name: '《CSS 揭秘》', author: '[希] Lea Verou' })
第二个问题也能够直接用 splice 来解决:
app.books.splice(1);
当你不想改变原数组,想经过一个数组的副原本作过滤或排序的显示时,可使用计算属性来返回过滤或排序后的数组,例如:
<div id="app"> <ul> <template v-for="book in filterBooks"> <li>书名:{{ book.name }}</li> <li>做者:{{ book.author }}</li> </template> </ul> </div> <script> var app = new Vue({ el: '#app', data: { books: [ { name: '《Oracle 从入门到跑路》', author: 'Mart' }, { name: '《MySql 从入门到跑路》', author: '尹成' }, { name: '《JavaScript 高级程序设计》', author: 'Nicholas C.Zakas' } ] }, computed: { filterBooks: function () { return this.books.filter(function (book){ return book.name.match(/JavaScript/); }); } } }) </script>
上例是把书名中包含 JavaScript 关键词的数据过滤出来,计算属性 filterBooks 依赖 books,可是不会修改 books 。实现排序也是相似的,好比:
sortedBooks: function () { return this.books.sort(function (a, b){ return a.name.length < b.name.length; }); }
在 Vue.js 2.x 中废弃了 1.x 中内置的 limitBy,filterBy 和 orderBy 过滤器,统一改用计算属性来实现。
Vue 事件处理的概念 v-on ,在事件绑定上,相似原生 JavaScript 的 onclick 等写法,也是 HTML 上进行监听的。好比,监听一个按钮的点击事件,设置一个计数器,每次点击都加 1 :
<div id="app"> 点击计数:{{ counter }} <button @click="counter++">+ 1</button> </div> <script> new Vew({ el: '#app', data: { counter: 0 } }) </script>
@click 的表达式能够直接使用 JavaScript 语句,也能够是一个在 Vue 实例中 methods 选项内的函数名,好比对上例进行扩展,再增长一个按钮,点击一次,计数器加100 ;
<div id="app"> 点击计数:{{ counter }} <button @click="handleAdd()">+ 1</button> <button @click="handleAdd(100)">+ 100</button> </div> <script> new Vew({ el: '#app', data: { counter: 0 }, methods: { handleAdd: function (count) { count = count || 1; // this 指向当前 Vue 实例 app this.counter += count; } } }) </script>
在 methods 中定义了咱们须要的方法供 @click 调用,须要注意的是,@click 调用的方法名后能够不跟括号“()”。此时,若是该方法有参数,默认会将原生对象 event 传入。
这种在 HTML 元素上监听事件的设计看似将 DOM 与 JavaScript 紧耦合,违背分离的的原理,实则恰好相反。由于经过HTML 就能够知道调用的是哪一个方法,将逻辑与 DOM 解耦,便于维护。最重要的是,当 ViewModel 销毁时,全部的事件处理器都会自动删除,无须本身清理。
Vue 提供了一个特殊变量 $event , 用于访问原生 DOM 事件,好比,能够阻止连接打开:
<div id="app"> <a href="https://www.baidu.com" @click="handleClick('禁止打开', $event)">打开连接</a> </div> <script> var app = new Vue({ el: '#app', methods: { handleClick: function (message, event) { event.preventDefault(); window.alert(message); } } }) </script>
4.2 修饰符
上述使用的 event.preventDefault() 也能够用 Vue 事件的修饰符来实现,在 @绑定的事件后加小圆点” . “,再跟一个后缀来使用修饰符。Vue 支持如下修饰符:
· .stop
· .prevent
· .capture
· .self
· .once
具体用法以下:
<!-- 阻止单击事件冒泡 --> <a @click.stop="handle"></a> <!-- 提交事件再也不重载页面 --> <form @submit.prevent="handle"></form> <!-- 修饰符能够串联 --> <a @click.stop.prevent="handle"></a> <!-- 只有修饰符 --> <form @submit.prevent></form> <!-- 添加事件监听器时使用事件捕获模式 --> <div @click.capture="handle">...</div> <!-- 只当事件在该元素自己(而不是子元素)触发时触发回调 --> <div @click.self="handle">...</div> <!-- 只触发一次,组件一样适用 --> <div @click.once="handle">...</div>
在表单元素上监听键盘事件时,还可使用按键修饰符,好比按下具体某个键时才调用方法:
<!-- 只有在 keyCode 是 32 时调用 vm.submit() --> <input @keyup.32="submit"> <!-- 也能够本身配置具体按键 --> Vue.config.keyCodes.f1 = 112; // 全局定义后,就可使用 @keyup.f1
除了具体的某个 keyCode 外,Vue 还提供了一些快捷名称,如下是所有的别名:
· .enter
· .tab
· .delate (捕获 ”删除“ 和 ”退格“ 键)
· .esc
· .space
· .up
· .down
· .left
· .right
这些按键修饰符也能够组合使用,或和鼠标一块儿配合使用:
· .ctrl
· .alt
· .shift
· .meta (Mac 下是 Command 键,Windows 下是窗口键)
例如:
<!-- Shift + S --> <input @keyup.shift.83="handleSave"> <!-- Ctrl + Click --> <div @click.ctrl="doSomething">Do someting</div>