计算属性
<div id="example"> <p>Original message: "{{ message }}"</p> <p>Computed reversed message: "{{ reversedMessage }}"</p> </div>
var vm = new Vue({ el: '#example', data: { message: 'Hello' }, computed: { // a computed getter reversedMessage: function () { // `this` points to the vm instance return this.message.split('').reverse().join('') } } })
对比methods:
<p>Reversed message: "{{ reversedMessage() }}"</p>
// in component methods: { reversedMessage: function () { return this.message.split('').reverse().join('') } }
不同的是计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。这就意味着只要 message
还没有发生改变,多次访问 reversedMessage
计算属性会立即返回之前的计算结果,而不必再次执行函数。
相比而言,只要发生重新渲染,method 调用总会执行该函数。
对比watched:
var vm = new Vue({ el: '#demo', data: { firstName: 'Foo', lastName: 'Bar', fullName: 'Foo Bar' }, watch: { firstName: function (val) { this.fullName = val + ' ' + this.lastName }, lastName: function (val) { this.fullName = this.firstName + ' ' + val } } })
var vm = new Vue({ el: '#demo', data: { firstName: 'Foo', lastName: 'Bar' }, computed: { fullName: function () { return this.firstName + ' ' + this.lastName } } })
Vue 确实提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:watch 属性。然而,通常更好的想法是使用 computed 属性而不是命令式的 watch
回调。上面代码是命令式的和重复的。
计算setter
计算属性默认只有 getter ,不过在需要时你也可以提供一个 setter :
// ... computed: { fullName: { // getter get: function () { return this.firstName + ' ' + this.lastName }, // setter set: function (newValue) { var names = newValue.split(' ') this.firstName = names[0] this.lastName = names[names.length - 1] } } } // ...
观察wathers
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的 watcher 。这是为什么 Vue 提供一个更通用的方法通过 watch
选项,来响应数据的变化。当你想要在数据变化响应时,执行异步操作或开销较大的操作,这是很有用的。
html class与内联样式的绑定
数据绑定一个常见需求是操作元素的 class 列表和它的内联样式。因为它们都是属性 ,我们可以用v-bind
处理它们:只需要计算出表达式最终的字符串。不过,字符串拼接麻烦又易错。因此,在 v-bind
用于 class
和 style
时, Vue.js 专门增强了它。表达式的结果类型除了字符串之外,还可以是对象或数组。
v-bind:class
对象语法:
<div class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }"> </div>
你也可以直接绑定数据里的一个对象:
<div v-bind:class="classObject"></div>
data: { classObject: { active: true, 'text-danger': false } }
渲染的结果和上面一样。我们也可以在这里绑定返回对象的计算属性。这是一个常用且强大的模式:
data: { isActive: true, error: null }, computed: { classObject: function () { return { active: this.isActive && !this.error, 'text-danger': this.error && this.error.type === 'fatal', } } }
数组语法:
<div v-bind:class="[activeClass, errorClass]">
<div v-bind:class="[isActive ? activeClass : '', errorClass]">
不过,当有多个条件 class 时这样写有些繁琐。可以在数组语法中使用对象语法:
<div v-bind:class="[{ active: isActive }, errorClass]">
|
用在组件上
<my-component class="baz boo"></my-component>//添加class <my-component v-bind:class="{ active: isActive }"></my-component>//绑定class
v-bind:style
对象语法
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
<div v-bind:style="styleObject"></div>
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
数组语法
<div v-bind:style="[baseStyles, overridingStyles]">
自动添加前缀
当 v-bind:style
使用需要特定前缀的 CSS 属性时,如 transform
,Vue.js 会自动侦测并添加相应的前缀。
条件渲染和列表渲染
v-if
<h1 v-if="ok">Yes</h1> <h1 v-else>No</h1>
<template v-if="ok"> <h1>Title</h1> <p>Paragraph 1</p> <p>Paragraph 2</p> </template> //template 中v-if条件组
<div v-if="Math.random() > 0.5"> Now you see me </div> <div v-else> Now you don't </div> //v-else
v-else
元素必须紧跟在 v-if
或者 v-else-if
元素的后面——否则它将不会被识别。
<div v-if="type === 'A'"> A </div> <div v-else-if="type === 'B'"> B </div> <div v-else-if="type === 'C'"> C </div> <div v-else> Not A/B/C </div>
类似于 v-else
,,v-else-if
必须紧跟在 v-if
或者 v-else-if
元素之后。
用key 管理可服用的元素
<div id="no-key-example" class="demo"> <div> <template v-if="loginType === 'username'"> <label>Username</label> <input placeholder="Enter your username" key="username-input"> </template> <template v-else=""> <label>Email</label> <input placeholder="Enter your email address" key="email-input"> </template> </div> <button @click="toggleLoginType">Toggle login type</button> </div> <script> new Vue({ el: '#no-key-example', data: { loginType: 'username' }, methods: { toggleLoginType: function () { return this.loginType = this.loginType === 'username' ? 'email' : 'username' } } }) </script>
v-show
另一个用于根据条件展示元素的选项是 v-show
指令。用法大致一样:
<h1 v-show="ok">Hello!</h1>
不同的是带有 v-show
的元素始终会被渲染并保留在 DOM 中。v-show
是简单地切换元素的 CSS 属性 display
。
注意, v-show
不支持 <template>
语法,也不支持 v-else
。
v-if vs v-show
v-if
是“真正的”条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if
也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
相比之下, v-show
就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
一般来说, v-if
有更高的切换开销,而 v-show
有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show
较好;如果在运行时条件不太可能改变,则使用 v-if
较好。
当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级。
v-for
我们用 v-for
指令根据一组数组的选项列表进行渲染。 v-for
指令需要以 item in items
形式的特殊语法, items
是源数据数组并且 item
是数组元素迭代的别名。
在 v-for
块中,我们拥有对父作用域属性的完全访问权限。 v-for
还支持一个可选的第二个参数为当前项的索引。
<ul id="example-2"> <li v-for="(item, index) in items"> {{ parentMessage }} - {{ index }} - {{ item.message }} </li> </ul>
var example2 = new Vue({ el: '#example-2', data: { parentMessage: 'Parent', items: [ { message: 'Foo' }, { message: 'Bar' } ] } }) // Parent - 0 - Foo
Parent - 1 - Bar
你也可以用 of
替代 in
作为分隔符,因为它是最接近 JavaScript 迭代器的语法:
<div v-for="item of items"></div>
Template v-for
<ul> <template v-for="item in items"> <li>{{ item.msg }}</li> <li class="divider"></li> </template> </ul>
对象迭代 v-for
<ul id="repeat-object" class="demo"> <li v-for="value in object"> {{ value }} </li> <li v-for="(value, key) in object"> {{ key }} : {{ value }} </li> <li v-for="(value, key, index) in object"> {{ index }}. {{ key }} : {{ value }} </li> </ul> <script> new Vue({ el: '#repeat-object', data: { object: { FirstName: 'John', LastName: 'Doe', Age: 30 } } }) </script>
整数迭代 v-for
<div> <span v-for="n in 10">{{ n }}</span> </div>
组件和v-for
事件处理器
v-on
监听事件:可以用 v-on
指令监听 DOM 事件来触发一些 JavaScript 代码。
<div id="example-1"> <button v-on:click="counter += 1">增加 1</button> <p>这个按钮被点击了 {{ counter }} 次。</p> </div> var example1 = new Vue({ el: '#example-1', data: { counter: 0 } })
方法事件处理器:许多事件处理的逻辑都很复杂,所以直接把 JavaScript 代码写在 v-on
指令中是不可行的。因此 v-on
可以接收一个定义的方法来调用。
<div id="example-2"> <!-- `greet` 是在下面定义的方法名 --> <button v-on:click="greet">Greet</button> </div> var example2 = new Vue({ el: '#example-2', data: { name: 'Vue.js' }, // 在 `methods` 对象中定义方法 methods: { greet: function (event) { // `this` 在方法里指当前 Vue 实例 alert('Hello ' + this.name + '!') // `event` 是原生 DOM 事件 alert(event.target.tagName) } } }) // 也可以用 JavaScript 直接调用方法 example2.greet() // -> 'Hello Vue.js!'
内联处理器方法:除了直接绑定到一个方法,也可以用内联 JavaScript 语句:
有时也需要在内联语句处理器中访问原生 DOM 事件。可以用特殊变量 $event
把它传入方法:
<button v-on:click="warn('Form cannot be submitted yet.', $event)">Submit</button> // ... methods: { warn: function (message, event) { // 现在我们可以访问原生事件对象 if (event) event.preventDefault() alert(message) } }
事件修饰符
在事件处理程序中调用 event.preventDefault()
或 event.stopPropagation()
是非常常见的需求。尽管我们可以在 methods 中轻松实现这点,但更好的方式是:methods 只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。
为了解决这个问题, Vue.js 为 v-on
提供了 事件修饰符。通过由点(.)表示的指令后缀来调用修饰符。
.stop
.prevent
.capture
.self
.once
<!-- 阻止单击事件冒泡 -->
<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>
<!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 -->
<div v-on:click.self="doThat">...</div>
<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>
|
按键修饰符
在监听键盘事件时,我们经常需要监测常见的键值。 Vue 允许为 v-on
在监听键盘事件时添加按键修饰符:
记住所有的 keyCode 比较困难,所以 Vue 为最常用的按键提供了别名:
<!-- 同上 -->
<input v-on:keyup.enter="submit">
<!-- 缩写语法 -->
<input @keyup.enter="submit">
|
全部的按键别名:
.enter
.tab
.delete
(捕获 “删除” 和 “退格” 键).esc
.space
.up
.down
.left
.right
可以通过全局 config.keyCodes
对象自定义按键修饰符别名:
// 可以使用 v-on:keyup.f1
Vue.config.keyCodes.f1 = 112
|
.ctrl
.alt
.shift
.meta