企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
Vue.js最著名的功能就是响应式系统,想要详细介绍Vue的响应式系统需要大量的篇幅。因此,本节的目的只是介绍响应式系统的大体工作流程,使你在以后深入学习的时候不至于一头雾水。 ## 核心概念 ### 1、Object.defineProperty 为对象的属性设置getter和setter。 ```js var obj={}; var bind=[]; //触发obj对象set和get方法的时候,趁机来输出或修改bind数组的内容 Object.defineProperty(obj,'s',{ set:function(val){ console.log('正在设置obj对象的s属性') bind['s']=val; }, get:function(){ console.log('正在读取obj对象的s属性') return bind['s']; } }) obj['s'] = 1; // 触发了obj的set方法,等于1赋值给bind['s']。 打印 正在设置obj对象的s属性 var ts = obj['s']; // 触发了obj的get方法。 打印 正在读取obj对象的s属性 ``` IE9以下的浏览器不能兼容Object.defineProperty。所以vue只能兼容ie9以上的浏览器了。 ## 相关概念 先来看看 Vue 的配置,以组件为例 ``` { render(h) { ...... }, props: { props1: Number }, data() { return { data1: 1, data2: 0 } }, computed: { computed1() { return this.data1 + this.props1 } }, watch: { computed1(newValue) { setTimeout(()=>{ console.log(newValue) }, 0) } } } ``` 响应式实现过程大概可以分为三块: #### 数据 Data 初始化` data、props、computed `时(初始化 render 时还有一些其他内置属性),通过 `Object.defineProperty `设置属性的 `getter` 和 `setter`,并为每个属性绑定一个 Dep 实例。 #### 组件 Component 可以把整个 Vue 应用认为是大大小小的组件堆砌而成。Vue 为每个组件都定义了两块重要的内容:`Watcher`和` Render`。 执行` $mount `时调用 `mountComponent`、初始化 `watch、computed`时、调用实例方法` $watch`时,都会给实例化一个 Watcher。而 Watcher 初始化时会进行一次求值(执行实例中的` getter `方法),首先会将当前实例设置为 Dep 当前目标,然后触发数据的相关属性的 ` getter ` 方法。 #### 依赖 Dep Dep 类就是用来关联数据与组件的 Watcher 的。利用 **订阅发布设计模式** 实现数据响应式变化。 在初始化 Watcher 时,通过执行了对应属性的 `getter` 方法,将Watcher 实例放入数据对应的 Dep 实例的订阅列表中。而当数据发生变化时,对应属性执行 `set` 方法,会通知到对应的 Dep 实例,再通知订阅列表中的 Watcher。 此时,Watcher 将通知组件执行 Render,重新计算出新的 VNode,通过新旧 VNode 的对比,进行视图更新。 #### Observer 类 Vue的响应式数据都会有一个__ob__的属性作为标记,里面存放了该属性的观察器,也就是Observer的实例,防止重复绑定。 Observer为数据加上响应式属性进行双向绑定。如果是对象则进行深度遍历,为每一个子对象都绑定上方法,如果是数组则为每一个成员都绑定上方法。 >相当于对响应式数据进行一层包,方便监控数据的变化,以便通知 Watcher 实例。 ## 响应式原理 ![](http://p878i6l4k.bkt.clouddn.com/Vue%E6%95%B0%E6%8D%AE%E7%BB%91%E5%AE%9A%E5%8E%9F%E7%90%86.png) 在Vue组件创建过程中, 为 `data、props、computed ` 三类数据添加__ob__的属性作为标记。即用 Observer 包装响应式数据,监控数据的`getter` 和 `setter` 操作。每一个数据都有与之对应的Dep实例。 利用 **订阅发布** 设计模式, 将 Dep 于 Watcher 关联。 解析 `template` 中的指令,为每一条数据绑定指令创建 一个 Watcher,使之关联 对应的 数据。 在对数据进行修改时,数据绑定的Dep.subs中的 Watcher 实例 推入 Watcher队列中,等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。