vue2 响应式原理

变化侦测

Vue.js最独特的特性之一是看起来并不显眼的响应式系统。当数据变化时 ,UI界面跟着变化,所以平时开发只需要关心数据 ,包括样式也是数据。简单来说变化侦测的作用就是着侦测数据的变化,当数据变化时,会通知视图相应的更新。

如何追踪变化

可以通过 Object.defineProperty来监测对象变化 ,Object.defineProperty用法如下

定义:: 静态方法Object.defineProperty()直接在对象上定义一个新属性,或者修改对象上已有的属性,并返回该对象。
Object.defineProperty(obj, prop, descriptor) obj 定义的对象 prop一个字符串 descriptor 被定义或修改的属性的描述符。

kotlin 复制代码
Object.defineProperty(this, 'message', {
        get: function() {
                      console.log('Getting value:', this._message);
                        return this._message;
                    },
       set: function(newValue) {
                        console.log('Setting value to:', newValue);
                        if (newValue !== this._message) {
                            this._message = newValue;
                            this.$forceUpdate(); // 强制更新视图
                        }
                    }
                });

如何收集依赖 Dep

该模板中使用了数据name,所以当它发生变化时,要向使用了它的地方发送通知。 对于上面的问题是,先收集依赖,用到name的地方收集起来 ,然后等属性发生变化时,把之前收集好的依赖循环触发一遍 总结: 在get中收集依赖 在set中触发依赖

依赖收集在哪里

封装一个dep 类

javascript 复制代码
class Dep {
  constructor() {
    // 存储订阅者的集合
    this.subscribers = new Set();
  }

  // 将当前活动的副作用添加到订阅者集合中
  depend() {
    if (activeEffect) {
      this.subscribers.add(activeEffect);
    }
  }

  // 通知所有订阅者重新运行他们的副作用
  notify() {
    this.subscribers.forEach(effect => effect());
  }
}

依赖是谁 Watch

观察者,当依赖的数据变化时,触发回调函数。

kotlin 复制代码
// Watcher 类:观察者,当依赖的数据变化时,触发回调函数
class Watcher {
  constructor(vm, expOrFn, cb) {
    this.vm = vm;
    this.getter = parsePath(expOrFn);
    this.cb = cb;
    this.value = this.get();
  }

  // 获取值,并进行依赖收集
  get() {
    Dep.target = this;
    const value = this.getter.call(this.vm, this.vm);
    Dep.target = null;
    return value;
  }

  // 更新值
  update() {
    const oldValue = this.value;
    this.value = this.get();
    this.cb.call(this.vm, this.value, oldValue);
  }
}

watcher 是如何与模版关联的

Watcher 主要用于监听数据的变化,并在数据变化时更新视图。为了将 Watcher 与模板关联起来,Vue 使用了一个编译器将模板转换为渲染函数(render function),然后通过这些渲染函数来创建虚拟 DOM(VNode)。当数据发生变化时,Watcher 会触发重新渲染过程,更新实际的 DOM。 一个dom 关联一个watcher 创建相应的 Watcher 实例,并将初始值插入到 DOM 中

Array的变化侦测

获取原始数组原型:

ini 复制代码
const arrayProto = Array.prototype;

创建新的数组方法对象:

ini 复制代码
const arrayMethods = Object.create(arrayProto);

定义需要拦截的方法:

ini 复制代码
const methodsToPatch = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
];

拦截每个方法并添加响应性逻辑

复制代码
ini 复制代码
methodsToPatch.forEach(function (method) {
  const original = arrayProto[method];
  def(arrayMethods, method, function mutator(...args) {
    const result = original.apply(this, args);
    const ob = this.__ob__;
    let inserted;
    switch (method) {
      case 'push':
      case 'unshift':
        inserted = args;
        break;
      case 'splice':
        inserted = args.slice(2);
        break;
    }
    if (inserted) ob.observeArray(inserted);
    ob.dep.notify();
    return result;
  });
});

它的作用是将拦截器(加工后具备拦截功能的arrayMethods)赋值给value.proto ,通过 proto 可以很巧妙地实现覆盖value原型的功能

kotlin 复制代码
 export class Observer {
         constructor (value) {
         this.value = value
         }
 
 if (Array.isArray(value)) {
  value.__proto__ = arrayMethods
  } else {
 this.walk(value) 
      } 
      } 
      }
相关推荐
0思必得02 小时前
[Web自动化] Selenium处理动态网页
前端·爬虫·python·selenium·自动化
东东5163 小时前
智能社区管理系统的设计与实现ssm+vue
前端·javascript·vue.js·毕业设计·毕设
catino3 小时前
图片、文件的预览
前端·javascript
layman05285 小时前
webpack5 css-loader:从基础到原理
前端·css·webpack
半桔5 小时前
【前端小站】CSS 样式美学:从基础语法到界面精筑的实战宝典
前端·css·html
AI老李5 小时前
PostCSS完全指南:功能/配置/插件/SourceMap/AST/插件开发/自定义语法
前端·javascript·postcss
_OP_CHEN5 小时前
【前端开发之CSS】(一)初识 CSS:网页化妆术的终极指南,新手也能轻松拿捏页面美化!
前端·css·html·网页开发·样式表·界面美化
啊哈一半醒5 小时前
CSS 主流布局
前端·css·css布局·标准流 浮动 定位·flex grid 响应式布局
PHP武器库5 小时前
ULUI:不止于按钮和菜单,一个专注于“业务组件”的纯 CSS 框架
前端·css
电商API_180079052475 小时前
第三方淘宝商品详情 API 全维度调用指南:从技术对接到生产落地
java·大数据·前端·数据库·人工智能·网络爬虫