1. 计算属性
<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: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
})
(1) 计算属性缓存 vs 方法
<p>Reversed message: "{{ reversedMessage() }}"</p>
// 在组件中
methods: {
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
我们可以将同一函数定义为一个方法而不是一个计算属性. 两种方式的最终结果确实是完全相同的. 然而, 不同的是计算属性是基于它们的响应式依赖进行缓存的. 只在相关响应式计算依赖发生改变时它闪才会重新求值. 这就意味着只要message还没有发生改变, 多次访问reversedMessage计算属性会立即返回之前的计算结果 , 而不必再次执行函数.
(2) 计算属性 vs 侦听属性
Vue提供了一种更通用的方式来观察和响应Vue实例上的数据变动: 侦听属性.
<div id="demo">{{ fullName }}</div>
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
}
}
})
(3) 计算属性的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]
}
}
}
// ...
2. 侦听器
虽然计算属性在大多数情况下更合适, 但有时也需要一个自定义的侦听器. 这就是为什么Vue通过watch选项提供了一个更通用的方法, 来响应数据的变化. 当需要在数据变化时执行异步或开销较大的操作时, 这个方式是最有用的.
div id="watch-example">
<p>
Ask a yes/no question:
<input v-model="question">
</p>
<p>{{ answer }}</p>
</div>
<!-- 因为 AJAX 库和通用工具的生态已经相当丰富,Vue 核心代码没有重复 -->
<!-- 提供这些功能以保持精简。这也可以让你自由选择自己更熟悉的工具。 -->
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script>
<script>
var watchExampleVM = new Vue({
el: '#watch-example',
data: {
question: '',
answer: 'I cannot give you an answer until you ask a question!'
},
watch: {
// 如果 `question` 发生改变,这个函数就会运行
question: function (newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.debouncedGetAnswer()
}
},
created: function () {
// `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
// 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
// AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
// `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,
// 请参考:https://lodash.com/docs#debounce
this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
},
methods: {
getAnswer: function () {
if (this.question.indexOf('?') === -1) {
this.answer = 'Questions usually contain a question mark. ;-)'
return
}
this.answer = 'Thinking...'
var vm = this
axios.get('https://yesno.wtf/api')
.then(function (response) {
vm.answer = _.capitalize(response.data.answer)
})
.catch(function (error) {
vm.answer = 'Error! Could not reach the API. ' + error
})
}
}
})
</script>
在这个示例中, 使用watch选项允许我们执行异步操作, 限制我们执行该操作的频率, 并在我们得到最终结果前, 前置中间状态, 这些都是计算属性无法做到的.
3. Class与Style绑定
操作元素的class列表和内联样式是数据绑定的一个常见需求. 因为它们都是属性, 所以我们可以用v-bind处理它们: 只需要通过表达式计算出字符串结果即可. 不过, 这符串拼接麻烦且易错. 因此, 在将v-bind用于class和style时, Vue.js 做了专门的增强. 表达式结果的类型除了字符串之外, 还可以是对象和数组.
(1) 绑定HTML Class
#对象语法
v-bind:class指令可以与普通的class属性共存.
<div
class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }"
></div>
我们也可以在这里绑定一个返回对象的计算属性
<div v-bind:class="classObject"></div>
ata: {
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>
data: {
activeClass: 'active',
errorClass: 'text-danger'
}
(2) 绑定内联样式
#对象语法
v-bind:style的对象语法十分直观, 看着非常像css, 但其实是一个JavaScript对象. css属性名可以用驼峰式或短横线分隔(记得用引号括起来)来命名.
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
data: {
activeColor: 'red',
fontSize: 30
}
#数组语法
<div v-bind:style="[baseStyles, overridingStyles]"></div>
4. 条件渲染
(1) 在<template>元素上使用v-if条件渲染分组
因为v-if是一个指令, 所以必须将它添加到一个元素上. 但是如果想切换多个元素, 可以把一个<template>元素当做不可见的包裹元素, 并在上面使用v-if, 最终的渲染结果不包含<template>元素.
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
(2) v-else -if v-else
<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>
(3) 用key管理可复用的元素
Vue会尽可能高效地渲染元素, 通常会复用已有元素而不是从头开始渲染. 这样也不总是符合实际需求, 如果不需要复用, 只需添加一个具有唯一值的key属性即可.
<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>
(4) v-show
v-show的元素始终会被渲染并保留在DOM中, v-show只是简单地切换元素的css属性display.
(5)v-if VS v-show
v-if是"真正"的条件渲染, 因为它会确保在切换过程中条件块中的事件监听器和子组件适当被销毁和重建.
一般来说, v-if有更高的切换开销, 而v-show有更高的初始渲染开销.
5. 列表渲染
(1). 用v-for把一个数组对应为一组元素
我们可以用v-for指令基于一个数组来渲染一个列表, v-for指令需要使用item in items形式的特殊语法, 其中items是源数据数组, 而item 则是被迭代的数组元素的别名.
<ul id="example-1">
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
var example1 = new Vue({
el: '#example-1',
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
你也可以用of代替in作为分隔符.
(2). 维护状态
当Vue正在更新使用v-for渲染的元素列表时, 它默认使用"就地更新"策略, 如果数据项的顺序被改变, Vue将不会移动DOM元素来匹配数据项的顺序, 而是就地更新每个元素, 并且确保它们在每个索引位置正确渲染.
为了给Vue一个提示, 以便它能跟踪每个节点的身份, 从而重用和得新排序现有元素, 你需要为每项提供一个唯一key属性.
(3). 数组更新检测
#变异方法
这些方法会改变原始的数组
push(), pop(), shift(), unshift(), splice(), sort(), reverse()
# 替换数组
这些方法不会改变原始数组, 而总是返回一个新数组.
filter(), concat(), slice()
由于JavaScript的限制, Vue不能检测以下数组的变动:
# 当你利用索引直接设置一个数组项时, 例如:
vm.items[indexOfItem] = newValue
但是可以用下面方式来实现:
/ Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
vm.$set(vm.items, indexOfItem, newValue)
# 当你修改数组的长度时,
vm.items.length = newLength
可以使用splice
vm.items.splice(newLength)
(4). 对象变更检测
由于JavaScript的限制, Vue不能检测对象属性的添加或删除, 对于已经创建的实例, Vue不允许动态添加根级别的响应式属性. 但是, 可以使用Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式属性.
6. 监听处理
可以用v-on指令监听DOM事件,
(1) 事件修饰符
Vue.js为v-on提供了事件修饰符
<!-- 阻止单击事件继续传播 -->
<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>
<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成 -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>
(2) 按键修饰符
7. 表单输入绑定
(1) 基本用法
你可以用v-model指令在表单<input> <textarea>及<select>元素上创建双向数据绑定. 它会根据控件类型自动选取正确的方法来更新元素. 但v-model本质上不过是语法糖, 它负责监听用户的输入事件以及更新数据, 并对一些极端的场景进行一些特殊处理.
(2)值绑定
对于单选按钮, 复选框及选择框的选项, v-model绑定的值通常是静态字符串.