# 生命周期
has template option,当为no时,会读取嵌套在div指定根节点里的内容。
总结
- beforecreated:el 和 data 并未初始化
- created:完成了 data 数据的初始化,
el没有【完成了属性和方法的运算,watch、event事件的回调配置】 - beforeMount:完成了 el 和 data 初始化
- mounted :完成挂载
- beforeCreate(){} // 执行时组件实例还未创建,通常用于插件开发中执行一些初始化任务,举个栗子:可以在这加个loading事件
- created(){} // 组件初始化完毕,各种数据可以使用,常用于异步数据获取
- beforeMount(){} // 未执行渲染、更新,dom未创建
- mounted(){} // 初始化结束,dom已创建,
可用于获取访问数据和dom元素 - beforeUpdate(){} // 更新前,可用于获取更新前各种状态
- updated(){} // 更新后,所有状态已是最新
- beforeDestroy(){} // 销毁前,可用于一些定时器或订阅的取消
- destroyed(){} // 组件已销毁,作用同上
beforeCreate 组件实例刚被创建,组件属性计算之前,获取不到 props 或者 data 中的数据的。
这些数据的初始化都在 initState 中。data和methods中的数据都没初始化
created 组件实例创建完成,data和methods中的数据都被初始化好了,属性已绑定,
但DOM还未生成,$el属性还不存在
beforeMount:模板编译/挂载前 开始创建VDOM,最后执行mounted 钩子,并将VDOM渲染为真实DOM且渲染数据。
组件中如果有子组件的话,会递归挂载子组件,当所有子组件全部挂载完毕,才会执行根组件的挂载钩子.
<div id=“app”>{{msg}} </div>->在内存中生成一个编译好的最终模板字符串->把这个模板字符串渲染为内存中dom
注意:只是在内存中渲染好了模板,并没有把模板挂载到页面上去,此时 页面还是旧的,
就是在内存中渲染了一个 <div id=“app”>ok</div> 的dom元素,但页面上还是 <div id=“app”>{{msg}} </div>
mounted 模板编译/挂载之后
将内存中渲染好的dom元素即 < div id=“app”>ok< /div>已经 提换了页面上的 < div id=“app”>{{msg}} < /div>
activated for keep-alive,组件被激活时调用
deactivated for keep-alive,组件被移除时调用
beforeCreate(){
console.log('beforecreate:',document.getElementById('first'))//null
console.log('data:',this.text);//undefined
this.sayHello();//error:not a function
},
created(){
console.log('create:',document.getElementById('first'))//null
console.log('data:',this.text);//this.text
this.sayHello();//this.sayHello()
},
beforeMount(){
console.log('beforeMount:',document.getElementById('first'))//null
console.log('data:',this.text);//this.text
this.sayHello();//this.sayHello()
},
mounted(){
console.log('mounted:',document.getElementById('first'))//<p></p>
console.log('data:',this.text);//this.text
this.sayHello();//this.sayHello()
}
| 生命周期 | 是否获取dom节点 | 是否可以获取data | 是否获取methods |
|---|---|---|---|
| beforeCreate | 否 | 否 | 否 |
| created | 否 | 是 | 是 |
| beforeMount | 否 | 是 | 是 |
| mounted | 是 | 是 | 是 |
TIP
一、加载渲染过程 父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
二、子组件更新过程 父beforeUpdate->子beforeUpdate->子updated->父updated
三、父组件更新过程 父beforeUpdate->父updated
四、销毁过程 父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
# watch监听
# computed 计算属性
fullName作为计算属性,那么data里就不该再定义了!
<p id="app"> {{fullName}} </p>
<script>
var vm = new Vue({
el: '#app',
data: {
firstName: 'Foo',
lastName: 'Bar',
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
</script>
计算属性默认只有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 = ‘bibi wang’,相应的firstName和lastName也会改变。
# filter
# methods
vue所有事件方法的集合
methods:{
// 清除被选中的颜色
removecolor(){
}
},
- 这是因为计算属性会基于它们的依赖关系进行 缓存 ;
- 在数据不发生变化时,计算属性是不需要重新计算的;
- 但是如果依赖的数据发生变化,在使用时,计算属性依然会重新进行计算;
# data写成函数的原因
组件中 data 什么时候可以使用对象?
组件复用时所有组件实例都会共享 data,如果 data 是对象的话,就会造成一个组件修改 data 以后会影响到其他所有组件,所以需要将 data 写成函数,每次用到就调用一次函数获得新的数据。
当使用 new Vue() 的方式的时候,无论我们将 data 设置为对象还是函数都是可以的,因为 new Vue() 的方式是生成一个根组件,该组件不会复用,也就不存在共享 data 的情况了。
// 当data如果是对象时就直接获取,那么如果复用组件的话,数据就会污染
function initData (vm: Component) {
let data = vm.$options.data
data = vm._data = typeof data === 'function'
? getData(data, vm)
: data || {}
if (!isPlainObject(data)) {
data = {}
process.env.NODE_ENV !== 'production' && warn(
'data functions should return an object:\n' +
'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
vm
)
}
strats.data = function (
parentVal: any,
childVal: any,
vm?: Component
): ?Function {
if (!vm) {
if (childVal && typeof childVal !== 'function') {
process.env.NODE_ENV !== 'production' && warn(
'The "data" option should be a function ' +
'that returns a per-instance value in component ' +
'definitions.',
vm
)
return parentVal
}
return mergeDataOrFn(parentVal, childVal)
}
return mergeDataOrFn(parentVal, childVal, vm)
}
类别引用数据类型
Object是引用数据类型,如果不用function返回,每个组件的data都是内存的同一个地址,一个数据改变了其他也改变了;????(是复用组件还是所有组件)
JS只有函数构成作用域(注意理解作用域,只有函数{}构成作用域,对象的{}以及if(){}都不构成作用域),data是一个函数时,每个组件实例都有自己的作用域,每个实例相互独立,不会相互影响。
这里模仿组件构造函数,定义data属性,采用对象的形式:
function Component(){
}
Component.prototype.data = {
count : 0
}
const componentA = new Component()
const componentB = new Component()
console.log(componentB.data.count) // 0
componentA.data.count = 1
console.log(componentB.data.count) // 1
如果是函数则不会相互干扰:
function Component(){
this.data = this.data()
}
Component.prototype.data = function (){
return {
count : 0
}
}
console.log(componentB.data.count) // 0
componentA.data.count = 1
console.log(componentB.data.count) // 0
当然根节点还是可以使用对象的方法:
new Vue({
data:{
ss:1111
},
mounted(){
console.log(this.ss)
},
router,
store,
render: h => h(App)
}).$mount('#app')
注意
注意,不应该使用箭头函数来定义 method 函数 (例如 plus: () => this.a++)。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.a 将是 undefined。