Vue是一套用于构建用户界面的渐进式框架。
模板渲染
# “Mustache”语法 {{}}的文本插值:
<span>Message: {{ msg }}</span>
绑定的数据对象上 msg 属性发生了改变,插值处的内容都会更新。
# v-once 能执行一次性地插值,当数据改变时,插值处的内容不会更新。
<span v-once>这个将不会改变: {{ msg }}</span>
#{{}}会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用 v-html 指令:
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
!动态渲染的 HTML 可能会导致 XSS 攻击。
#v-bind/':':绑定HTML特性
<div v-bind:id="dynamicId"></div>
复制代码
计算属性computed
类型:{ [key: string]: Function | { get: Function, set: Function } }
<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('')
}
}
})
复制代码
计算属性缓存 vs 方法
类型:{ [key: string]: Function | { get: Function, set: Function } }
通过在表达式中调用方法来达到同样的效果:
<p>Reversed message: "{{ reversedMessage() }}"</p>
// 在组件中
methods: {
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。这就意味
着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,
而不必再次执行函数。
相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。
我们为什么需要缓存?假设我们有一个性能开销比较大的的计算属性 A,它需要遍历一个巨大的数组并做大
量的计算。然后我们可能有其他的计算属性依赖于 A 。如果没有缓存,我们将不可避免的多次执行 A 的
getter!如果你不希望有缓存,请用方法来替代。
复制代码
计算属性 vs 侦听属性
类型:{ [key: string]: Function | { get: Function, set: Function } }
Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。当你有一些数据需要随着
其它数据变动而变动时,你很容易滥用 watch——特别是如果你之前使用过 AngularJS。然而,通常更好的
做法是使用计算属性而不是命令式的 watch 回调。细想一下这个例子:
<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
}
}
})
计算属性的 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]
}
}
}
// ...
现在再运行 vm.fullName = 'John Doe' 时,setter 会被调用,vm.firstName和 vm.lastName
也会相应地被更新。
复制代码
侦听器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.getAnswer()
}
},
methods: {
// `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
// 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
// AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
// `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,
// 请参考:https://lodash.com/docs#debounce
getAnswer: _.debounce(
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
})
},
// 这是我们为判定用户停止输入等待的毫秒数
500
)
}
})
</script>
在这个示例中,使用 watch 选项允许我们执行异步操作 (访问一个 API),限制我们执行该操作的频率,
并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
复制代码
生命周期钩子
所有的生命周期钩子自动绑定 this 上下文到实例中,因此你可以访问数据,对属性和方法进行运算。这意味
着 你不能使用箭头函数来定义一个生命周期方法 (例如 created: () => this.fetchTodos())。这是
因为箭头函数绑定了父上下文,因此 this 与你期待的 Vue 实例不同,this.fetchTodos 的行为未定义。
# beforeCreate 类型:Function
在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
# created 类型:Function
在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方
法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。
# beforeMount 类型:Function
在挂载开始之前被调用:相关的 render 函数首次被调用。
该钩子在服务器端渲染期间不被调用。
# mounted 类型:Function
el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,
当 mounted 被调用时 vm.$el 也在文档内。
注意 mounted 不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用
vm.$nextTick 替换掉 mounted:
mounted: function () {
this.$nextTick(function () {
// Code that will run only after the
// entire view has been rendered
})
}
该钩子在服务器端渲染期间不被调用。
# beforeUpdate 类型:Function
数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加
的事件监听器。
该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。
# updated 类型:Function
由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下
,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或 watcher 取而代之。
注意 updated 不会承诺所有的子组件也都一起被重绘。如果你希望等到整个视图都重绘完毕,可以用
vm.$nextTick 替换掉 updated:
updated: function () {
this.$nextTick(function () {
// Code that will run only after the
// entire view has been re-rendered
})
}
该钩子在服务器端渲染期间不被调用。
# activated 类型:Function
keep-alive 组件激活时调用。
该钩子在服务器端渲染期间不被调用。
# deactivated 类型:Function
keep-alive 组件停用时调用。
该钩子在服务器端渲染期间不被调用。
# beforeDestroy 类型:Function
实例销毁之前调用。在这一步,实例仍然完全可用。
该钩子在服务器端渲染期间不被调用。
# destroyed 类型:Function
Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子
实例也会被销毁。
该钩子在服务器端渲染期间不被调用。
# errorCaptured (2.5.0+ 新增)类型:(err: Error, vm: Component, info: string) => ?boolean
当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含
错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。
你可以在此钩子中修改组件的状态。因此在模板或渲染函数中设置其它内容的短路条件非常重要,它可以防止当一
个错误被捕获时该组件进入一个无限的渲染循环。
错误传播规则
默认情况下,如果全局的 config.errorHandler 被定义,所有的错误仍会发送它,因此这些错误仍然会向
单一的分析服务的地方进行汇报。
如果一个组件的继承或父级从属链路中存在多个 errorCaptured 钩子,则它们将会被相同的错误逐个唤起。
如果此 errorCaptured 钩子自身抛出了一个错误,则这个新错误和原本被捕获的错误都会发送给全局的
config.errorHandler。
一个 errorCaptured 钩子能够返回 false 以阻止错误继续向上传播。本质上是说“这个错误已经被搞定了
且应该被忽略”。它会阻止其它任何会被这个错误唤起的 errorCaptured 钩子和全局的config.errorHandler。
复制代码