一般情况下,我们使用vue时,去服务器请求数据,通常是这么写的
<script>
var vm = new Vue({
el: '#app',
data: {
postsList: []
},
methods: {
fetchData () {
axios.get('/api/posts')
.then(function(response) {
vm.postsList = response.data.postsList;
vm.postsList.forEach((element) => element.url = '/posts/show?id=' + element._id);
})
}
},
});
vm.fetchData();
</script>
看上去似乎也没啥问题,上面的例子 能保证fetchData的callback回来后,vue已经虚拟化完了。
假设 我们的代码 在vue结构外面,就很难保证整个业务逻辑的完整性。如果vue对HTML没有完成虚拟化,
更新数据操作DOM都是徒劳的。甚至可能因为找不到对应绑定的节点而报错。
因此保证在vue将HTML虚拟化之后 初始化数据操作dom才是安全可靠的。
事实上vue对象从创建到销毁有一个生命周期
上图很清晰的表明了vue在生命周期的各个阶段做的事情,并且提供了生命周期的几个回调函数
- beforeCreate 创建之前:已经完成了 初始化事件和生命周期
- created 创建完成:已经完成了 初始化注册和响应
- beforeMount 挂载之前:已经完成了模板渲染
- mounted :挂载之后:已完成HTML虚拟化,创建了el节点 可以操作DOM了
- beforeDestroy :摧毁之前:整个vue都处在实时监控空渲染和更新
- destroyed: 已摧毁,已经摧毁了观察者,子元素和事件监听
所以,在完成HTML渲染之后,初始化请求数据是安全可靠的,也就是把vue初始化请求的数据放在mounted的钩子函数中比较好。
所以,上面代码改进如下:
<script>
var vm = new Vue({
el: '#app',
data: {
postsList: []
},
mounted:function() {
axios.get('/api/posts')
.then(function(response) {
vm.postsList = response.data.postsList;
vm.postsList.forEach((element) => element.url = '/posts/show?id=' + element._id);
})
}
});
</script>
需要明确的是:
- vue提供了生命周期的钩子函数,其值就是一个函数。既然是钩子函数,在该触发的时候,会自动调用,不需要我们手动调用。
- 如果需要执行多个函数,没问题呀,函数中是可以调用其他函数,也是可以定义函数的。
- 不要在选项属性或回调上使用箭头函数,比如 created: () => console.log(this.a)
或 vm.$watch('a', newValue => this.myMethod())
。因为箭头函数是和父级上下文绑定在一起的,this
不会是如你所预期的 Vue 实例,且 this.a
或 this.myMethod
也会是未定义的。