Open tomoya06 opened 4 years ago
高清图见Vue官方文档
生命周期钩子 | 组件状态 | 最佳实践 | 可访问变量 |
---|---|---|---|
beforeCreate | 实例初始化之后,this指向创建的实例,不能访问到data、computed、watch、methods上的方法和数据 | 常用于初始化非响应式变量 | None |
created | 实例创建完成,可访问data、computed、watch、methods上的方法和数据,未挂载到DOM,不能访问到$el属性,$ref属性内容为空数组 | 常用于简单的ajax请求,页面的初始化 | data/computed/watch/methods |
beforeMount | 在挂载开始之前被调用,beforeMount之前,会找到对应的template,并编译成render函数 | + $el | |
mounted | 实例挂载到DOM上,此时可以通过DOM API获取到DOM节点,$refs属性可以访问 | 常用于获取VNode信息和操作,ajax请求 | +$refs |
beforeupdate | 响应式数据更新时调用,发生在虚拟DOM打补丁(patch)之前 | 适合在更新之前访问现有的DOM,比如手动移除已添加的事件监听器 | 更新的data |
updated | 虚拟 DOM 重新渲染和打补丁之后调用,组件DOM已经更新,可执行依赖于DOM的操作 | 避免在这个钩子函数中操作数据,可能陷入死循环 | 同上 |
beforeDestroy | 实例销毁之前调用。这一步,实例仍然完全可用,this仍能获取到实例 | 常用于销毁定时器、解绑全局事件、销毁插件对象等操作 | |
destroyed | 实例销毁后调用,调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁 | – |
另外,<keep-alive>
元素独有的生命周期,分别为 activated 和 deactivated 。用 keep-alive 包裹的组件在切换时不会进行销毁,而是缓存到内存中并执行 deactivated 钩子函数,命中缓存渲染后会执行 activated 钩子函数。
$el, $ref, data
$el -> beforeMounted, $ref -> mounted, data -> created
beforeUpdated
加载渲染过程 父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
子组件更新过程 父beforeUpdate->子beforeUpdate->子updated->父updated
父组件更新过程 父beforeUpdate->父updated
销毁过程 父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
直接看小册吧,就是这本
参考掘金博客总结
Object.defineProperty
的 get/set 方法对其进行数据劫持;new Vue()
创建vue组件时,在constructor里面调用observe(this._data)
对this._data
的每个属性“响应式”化observe()
内部,实际上是对data的每个key、调用defineReactive()
为每个key注册Dep;Dep类中有一个sub列表,用于存储所有需要监听这个key值变化的Watcher对象defineReactive()
中继续调用Object.defineProperty()
来添加getter/setter
代理方法,getter/setter
是依赖收集的关键,也是Vue实现MVVM的双向数据绑定的关键Watcher
对象收集到Dep
中本质上是通过原生DOM操作方式来生成DOM节点,然后插入$el
中。完整流程可以参考掘金博客。关键点如下:
图片来自这里
data是Vue原型链上的一个属性,每个Vue组件都是一个Vue实例,通过new Vue()
实例化。如果data直接是一个对象的话,那么一旦修改其中一个组件的数据,其他组件相同数据就会被改变。因此Vue规定,data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝。
参考这篇博客,Vue的data定义类似如下,是在原型链上绑定的:
// 创建一个简单的构建函数
var MyComponent = function() {
// ... code here
}
// 原型链对象上设置data数据,为里为Object
MyComponent.prototype.data = {
name: 'abc',
age: 20,
}
// 创建两个实例:小明,小红
var xiaoming = new MyComponent()
var xiaohong = new MyComponent()
// 默认状态下小明和小红的年龄一样
console.log(xiaoming.data.age === xiaohong.data.age) // true
// 改变一下小明的年龄
xiaoming.data.age = 30;
// 打印下小红的年龄,发现因为改变了小明的年龄,结果造成小红的年龄也变了
console.log(xiaoming.data.age)// 30
console.log(xiaohong.data.age) // 30
props emit $parent $children
$parent.$children() $refs
Vue.set(object, propertyName, value)
vm.items[indexOfItem] = newValue
;解决:Vue.set(vm.items, indexOfItem, newValue) / vm.items.splice(indexOfItem, 1, newValue)
vm.items.length = newLength
;解决:vm.items.splice(newLength)
参考这篇博客的测试分析,Object.defineProperty
在数组中的表现和在对象中的表现是一致的,数组的索引就可以看做是对象中的 key。
所以,Object.defineProperty
是有监控数组下标变化的能力的,只是vue2.x放弃了这个特性。在2.x中vue重新hack了数组的内置方法,包括push / pop / shift / unshift / splice / sort / reverse
。
Vue3.x将改用Proxy来实现响应化。用法参考MDN文档。与 Object.defineProperty 相比,proxy的好处如下:
但缺点在于兼容性差。
Vue组件中支持的另外两个API。用于实现侦听器和计算属性。
本段参考掘金博客
给要监听属性的Dep中注册一个watcher,该watcher的cb就是watch定义的handler。当属性更新时,按照一般的响应式流程触发watcher执行。
addIfCondition
方法,生成vnode的时候会忽略对应节点,render的时候就不会渲染;display:none
来隐藏元素;Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,我们的代码将会变得更结构化且易维护。
注册了Vuex的组件可以通过this.$store来进行vuex的相关操作
经过测试,在mutation中使用setTimeout异步更新state也是可以的,action中不借助mutation、而是直接更新state也可以。参考尤雨溪的知乎回答,Vuex文档中对mutation和action的操作限制更多的是建议而非强制规定,目的是为了能更好地调试,例如在devTools中做state回滚的操作。以测试为例,如果在action中直接修改state,devTools中是不记录这次修改记录的;mutation中的异步更新,devTools添加的记录也有延迟。
Vue.use(Vuex)
安装插件,内部调用install方法,install方法使用Vue.mixin
方法在beforeCreate
中注入vuexInit
方法vuexInit
方法会给每一个vm添加this.$store
,这样每级节点都能访问到统一的store了store._vm = new Vue()
,然后通过设置getter来创建代理,可以通过this.store[key]
来访问store._vm[key]
的值参考阮一峰的博客
Vuex的实现参考了Flux、Redux等状态管理的基本思想。下图是Flux的数据流。
Flux 的最大特点,就是数据的"单向流动"。
概述
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。Vue的设计收到MVVM模型影响。
MVC/MVVM等软件架构简介
MVC
组成部分:
通信方式
所有通信都是单向的。
交互方式
接受用户指令时,MVC 可以分成两种方式。一种是通过 View 接受指令,传递给 Controller;另一种是直接通过controller接受指令。但实际上还有其他灵活的方式。
MVVM
通信方式