6 Vue 原理(SY)

组件化 mvvm
响应式
vdom 和 diff
模板编译
渲染过程
前端路由

目录

1 Vue 与MVVM

1 如如何理解MVVM模型

1 vue响应式如何实现

2  监听data变化的核心API

3 如何深度监听·data变化 

4 如何监听 数组变化 

2  diff 算法

1 虚拟DOM 与   diff算法 

2 深入diff算法源码 - 生成Vnode

3  深入diff算法源码 - patch函数 

4 深入diff算法源码 - patchVnode函数

5  深入diff算法源码 - updateChildren函数  

6 diff算法总结

 3 组件化

注册组件的基本步骤

全局组件和局部组件

为什么组件data必须是函数

4  模板编译

5  渲染过程

6 前端路由

                   vue-router实现原理:


1 Vue 与MVVM

1 如如何理解MVVM模型

数据驱动视图

  • 在”很早以前“就有了组件化(如:asp、jap、php)

  • node 也有类似组件化

  • 但传统的组件化,只是静态渲染,更新还要依赖操作 DOM,这也是 jQuery 流行的原因

  • Vue、React 在这基础上做了一个微创新,即数据驱动视图

  • 数据驱动视图的出现,使得我们更关注数据(业务逻辑),不用再去关心DOM的增删改查

  • Vue 是 MVVM,React 是 setState

  • M -> Model V -> View VM -> ViewModel

 

左到右:DOM事件被vm模型监听到之后,可以去修改Model中的数据

右到左:Model中的数据一旦修改就立刻更新view,重新渲染

如此一来视图就不用我们自己手动去改了

1 vue响应式如何实现

只要在 Vue 实例中声明过的数据,这个数据就是响应式的。

什么是响应式,即,数据发生改变的时候,视图会重新渲染,匹配更新为最新的值。
在具体实现上,vue用到了几个核心部件

image-20210226163936839

描述:

​ 一开始渲染组件要运行render函数,把render函数交给watcher执行的

​ watcher的执行过程中会运行render函数 ,render函数执行中会用到一些数据,

​ 这些数据又会用到getter(),这个getter是把原始对象通过observer把每一个属性变成getter和setter,

​ 因此在render函数中会用到一些数据,这些数据会触发它的getter执行,而在触发getter的时候会有依赖收集,

​ 就会记录watcher用到了这些数据,

​ 有一天数据发生变化了,因为在之前数据已经被记录了,所以会通知watcher把render函数重新运行一遍,

​ watcher不会自己执行,它会把自己交给调度器,调度器会把watcher添加到队列,如果有重复就不添加。然后把执行

​ 这个队列的操作加到nextTick里面,这里面是异步的,
 

响应式原理流程.png


1Observer 

在组件生命周期中,这件事发生在beforeCreate之后,created之前。Observer把对象的每个属性通过Object.defineProperty转换为带有gettersetter的属性。

Observer的目标,就是要让一个对象,它属性的读取、赋值,内部数组的变化都要能够被vue感知到。

vue提供了$set$delete两个实例方法,让开发者通过这两个实例方法对已有响应式对象添加或删除属性。

数组,vue会更改它的隐式原型,之所以这样做,是因为vue需要监听那些可能改变数组内容的方法 

 

 

2 Dep实例  Dependency依赖

Vue会为响应式对象中的每个属性、对象本身、数组本身创建一个Dep实例,每个Dep实例都有能力做以下两件事:

  • 记录依赖:是谁在用我
  • 派发更新:我变了,我要通知那些用到我的人

3 Watcher

我们不要直接执行函数,而是把函数交给一个叫做watcher的东西去执行,watcher是一个对象,每个这样的函数执行时都应该创建一个watcher,通过watcher去执行

watcher会设置一个全局变量,让全局变量记录当前负责执行的watcher等于自己,然后再去执行函数,在函数的执行过程中,如果发生了依赖记录dep.depend(),那么Dep就会把这个全局变量记录下来,表示:有一个watcher用到了我这个属性

Dep进行派发更新时,它会通知之前记录的所有watcher:我变了
 

每一个vue组件实例,都至少对应一个watcher,该watcher中记录了该组件的render函数。

watcher首先会把render函数运行一次以收集依赖,于是那些在render中用到的响应式数据就会记录这个watcher。

当数据变化时,dep就会通知该watcher,而watcher将重新运行render函数,从而让界面重新渲染同时重新记录当前的依赖。

4 Scheduler 调度器

现在还剩下最后一个问题,就是Dep通知watcher之后,如果watcher执行重运行对应的函数,就有可能导致函数频繁运行,从而导致效率低下

这样显然是不合适的,因此,watcher收到派发更新的通知后,实际上不是立即执行对应函数,而是把自己交给一个叫调度器的东西

调度器维护一个执行队列,该队列同一个watcher仅会存在一次,队列中的watcher不是立即执行,它会通过一个叫做nextTick的工具方法,把这些需要执行的watcher放入到事件循环的微队列中,nextTick的具体做法是通过Promise完成的

nextTick 通过 this.$nextTick 暴露给开发者

也就是说,当响应式数据变化时,render函数的执行是异步的,并且在微队列中

  深入浅出 Vue 响应式原理源码剖析_IT沐华的博客-CSDN博客_vue响应式源码解析先看张图,了解一下大体流程和要做的事初始化在 new Vue 初始化的时候,会对我们组件的数据 props 和 data 进行初始化,由于本文主要就是介绍响应式,所以其他的不做过多说明来,看一下源码源码地址:src/core/instance/init.js - 15行export function initMixin (Vue: Class<Component>) { // 在原型上添加 _init 方法 Vue.prototype._init = function (opthttps://blog.csdn.net/a151681931/article/details/120686534?ops_request_misc=&request_id=&biz_id=102&utm_term=vue%E5%93%8D%E5%BA%94%E5%BC%8F%20%E6%BA%90%E7%A0%81&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-2-120686534.142%5Ev47%5Enew_blog_pos_by_title,201%5Ev3%5Econtrol_2&spm=1018.2226.3001.4187

5  Object.defineProperty缺点

深度监听,需要递归到底,一次性计算量大

无法监听新增属性/删除属性(Vue.set Vue.delete)

data.x = '100'//新增属性,监听不到 - 所以有Vue.set
delete data.name //删除属性,监听不到 - 所以有Vue.delete

2  监听data变化的核心API

    1,Observer

        将data中的数据用Object.defineProperty进行数据劫持,每个目标对象的键值(即data中的数据)转换成getter/setter形式,用于进行依赖收集和通过依赖通知更新

    2,Dep(依赖管理)

        1)什么是依赖?

            数据响应式后,如何通知视图更新?Dep就是帮我们收集【究竟要通知到哪里的】

        2)如何收集依赖

            我们如何知道data中的某个属性被使用了,答案就是Object.defineProperty,因为读取某个属性就会触发get方法

        3)Dep就是收集与视图相关的数据,触发了get的数据,主要起到依赖收集和通知更新的作用。用于收集当前响应式对象的依赖关系,每个响应式对象包括子对象都拥有一个 Dep 实例(里面 subs 是 Watcher 实例数组),当数据有变更时,会通过 dep.notify()通知各个 watcher。

        4)initState 时,对 computed 属性初始化时,触发 computed watcher 依赖收集

        5)initState 时,对侦听属性初始化时,触发 user watcher 依赖收集

        6)render()的过程,触发 render watcher 依赖收集

        7)re-render 时,vm.render()再次执行,会移除所有 subs 中的 watcer 的订阅,重新赋值。

    3,Watcher

        1)Watcher就是类似中介的角色,比如message就有三个中介,当message变化,就通知这三个中介,他们就去执行各自需要做的变化。

        2)Watcher必须要有的2个方法。一个就是通知变化,另一个就是被收集起来到Dep中去。

        3)遍历所有的 subs(Watcher 实例),调用每一个 watcher 的 update 方法。

    4,Watcher 和 Dep 的关系

        watcher 中实例化了 dep 并向 dep.subs 中添加了订阅者,dep 通过 notify 遍历了 dep.subs 通知每个 watcher 更新。

三,总结

    1,在数据被改的时候,触发set方法,通过对应的所有依赖(Watcher),去执行更新。比如watch和computed就执行开发者自定义的回调方法。

    2,Observer中进行响应式的绑定,在数据被读的时候,触发get方法,执行Dep来收集依赖,也就是收集Watcher。

3 如何深度监听·data变化 

const data = {
  name: '张三',
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值