前言
19年渣本毕业正在接受社会洗礼的前端小黄,接受社会的一顿暴打,开启写文章之路,技术有限,只是想写写个人对学习到的知识点的一个理解,理解有误务必请大佬们纠正指出,我会继续查阅资料及时修改。
写文章另外一个目的就是又多了一件持之以恒的事,能记录自己的个人学习情况以及监督自己短期目标计划的一个进度。自我的第一个短期计划是剖析vue源码,所以接下来的文章是对vue的一个剖析。
还有一点就是手撸的代码我都会以图的形式进行显示,因为只有自己手撸理解转换为思想才能达到掌握的目的,这是从上传下的一个真理,看会的不一定就能写得出,过目不忘也不是平常人,或许你就是那个不平常的人。
理解Vue的设计思想
对 你现在脑子出现的字眼就是 MVVM,那么问你什么是MVVM你该如何用自己的话进行阐述?
不管三七二十一 脑子里先有这个图:
由此可得
1. MVVM字面理解:View视图层,Model数据层,ViewModel视图模型。
2. MVVM框架是三要素:数据响应式,模板引擎,渲染.
3. VM主要做的事:上联:将数据绑定到视图(连接Model与View),下联:通过数据监听修改数据(连接View与Model)。横批:连接View与Model的桥梁。
数据响应式
- Object.defineProperty() vue2.0的写法
- Proxy vue3.0的写法
模板引擎
- 插值
- v-bind v-on v-module v-for v-if
渲染
- 模板(template)->属性文本todoList vue1.0页面中一个文本一个Watcher结果产生n多Watcher文本多会造成卡顿。
- 模板(template)->ast语法树->vdom->dom vue2.0引入虚拟Dom,一个组件一个Wacther,具体更新内容Diff比对更新。
数据响应式原理
什么是数据响应 通俗的说他就是修改数据然后页面显示修改的值。
拿最简单的数据来说
结果如下:
加个html渲染看看:
渲染我们先用innerText来模拟
结果就是视图两秒后输出xiaohong
总结:
1. 对数据进行拦截,定义数据的get set
2. 当数据发生改变更新视图,set数据的时候触发update更新
对于复杂的数据来说 一般我们需要进行数据的遍历
问题来了obj.say.job的get set没有触发 因为我们只监听了第一层 我们需要对数据进行递归的监听 修改数据劫持前的操作
问题又来了 下面重新赋值会输出想要的结果吗
显然不行 当用户修改的新数据是个对象时 我们并没有对此对象进行监听 我们需要对新值做一个监听的处理
下一个问题 如果此时我向obj添加新的属性 那个能执行响应吗
没错 不行 在vue中我们怎么向obj添加属性的,是不是set方法呀!所以set的主要目的就是添加数据响应
简单的实现下set
哈哈哈哈哈 有没有想抽死的冲动 这里只是简单的实现了一下 这样我们就可以调用set进行对象新属性的响应式添加
到此数据响应就完事了吗 扶我起来 还有个大牌数组
对于数组就那7个方法 vue的操作是对数组这些方法进行原型的重写,除了方法能做的事外还要做一个事就是实现数据劫持监听。对数组处理思路大致如下
总结:
1. 需对传入的数据进行递归劫持监听。
2. 对于用户设置新的内容也要进行劫持监听。
3. 对于设置新的属性,我们使用的是$set方法,它的目的也是对新的数据进行劫持监听。
4. 对于数组,我们需要重写数组的方法,抛出新的方法让数据(data)的原型等于我们抛出的方法,从而操作数组时先找到原型我们抛出的方法执行,抛出的方法除了数组方法能做的事外还对数据进行了劫持监听。
上面只是小菜 我们来看看这张图
这个图大家都不陌生的,这张图的流程是怎样的?
流程:
1. new Vue初始化,传入数据data。
2. Observer Object.defineProperty进行数据劫持。
3. Compile 对模板进行编译 解析{{}} v-if v-module…指令,调用get()将数据显示在视图上。
4. Watcher 我们模板中的每一个{{xx}}都是一个watcher,它有一个update方法,大概就是对dom元素.innerText = 'qq'。
5. 由于data某个key可以在模板中出现多次,所以需要一个Dep管家管理多个Watcher,当key发生变化,通知到管家然后管家管理的所有相同key(Watcher)进行更新。
6. Observer(一)-Dep(一)-Watcher(多)三者关系是一对一对多的关系。每个key有一个Dep,每个Dep可能会有多个watcher。
手撸涉及介绍
1. hVue:初始化入口函数(响应式处理,代理,创建编译器)。
2. Observer:数据劫持响应(分辨是传入数据是对象还是数组)。
3. Compile:编译模板,初始化视图,收集依赖(Watcher创建)。
4. Watcher:执行更新函数update。
5. Dep:管理多个Watcher,批量更新。
先看看我们要实现的功能,引入正常的vue,视图正常显示。
1.现在我们引入自己的hVue.js
2.创建构造函数
3.响应式处理
4.代理 意义在于我们可以vm.number就可以获取到数据 而不用vm.$data.number
5.编译原理图
6.获取Dom
7.遍历子元素 节点 文本分开处理 首先我们先处理文本节点让插值{{}}显示到视图中
结果如下图:
8.接下来处理元素 解析元素属性 创建对应属性的方法 h-text h-html为例
结果如下图:
9.依赖收集
思路:
1. defineReactive时为每一个key创建一个Dep实例。
2. 初始化视图时读取某个key,创建一个Watcher。
3. 由于读取会触发getter方法,便将Watcher添加到对应的Dep中。
4. key更新时触发setter方法,便可通过对应的Dep通知所有的Watcher批量更新。
10.创建观察者
11.解析时创建Watcher->抽离一个update方法做两件事第一初始化数据赋值显示在视图,第二添加对应的Watcher
12.创建Dep管家 管理某个key相关的所有Watcher
13.何时创建Dep,之前说了一个key对应一个Dep,所以我们在数据劫持前创建
14.何时收集依赖(get时),何时通知更新(set),如何添加收集(神操作)-先在Dep静态属性创建当前Watcher实例,触发getter,然后就销毁。
至此初步的流程我们已经走通了,但这只是vue1.0的实现,后续我们再走走2.0使用Vdom渲染的操作。
如果你看到这了,码字不易,点个赞憋兄弟。