一步一步实现Vue的响应式(对象观测)

yizhihongxing

实现Vue的响应式(对象观测)

什么是Vue的响应式?

Vue的响应式是指当Vue数据模型中的数据发生变化时,页面中涉及这些数据的部分会自动重新渲染并更新。Vue通过数据劫持方式实现响应式,也就是通过监听对象属性的变化来实现自动触发视图更新。

如何实现Vue的响应式?

Vue的响应式是基于Object.defineProperty()方法实现。该方法能够监听对象属性的变化,并在属性值变更时触发回调函数。

流程如下:

  1. 首先要创建一个Observer对象,采用递归的方式为所有属性添加getter和setter。getter负责收集依赖并返回属性值,setter则负责派发更新通知。
  2. 收集依赖,依赖就是指有哪些Watcher依赖于该属性。在getter中监听数据属性的访问者(Watcher),并将其添加到依赖里面去。
  3. 派发更新,当属性变更后,会在setter中通知对应的依赖进行更新操作。

下面通过两条简单的示例说明:

示例1:响应式对象

// 创建一个Observer对象,为person对象添加getter和setter方法
function Observer(obj) {
  if(!obj || typeof obj !== 'object') {
    return;
  }

  Object.keys(obj).forEach(key => {
    defineReactive(obj, key, obj[key]);
  });
}

// 为对象添加getter和setter方法,来实现响应式
function defineReactive(obj, key, val) {
  // 在getter中将Watcher添加到依赖数组中
  const dep = new Dep();

  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function() {
      if (Dep.target) {
        dep.addDep(Dep.target);
      }
      return val;
    },
    set: function(newVal) {
      if (newVal === val) {
        return;
      }
      // 在setter中将值更新,并通知依赖更新
      val = newVal;
      dep.notify();
    }
  });
}

// 收集依赖
class Dep {
  constructor() {
    this.deps = [];
  }

  addDep(dep) {
    this.deps.push(dep);
  }

  notify() {
    this.deps.forEach(dep => {
      dep.update();
    });
  }
}

// 观察者
class Watcher {
  constructor(obj, key, cb) {
    // 相当于Vue中的v-model指令
    this.obj = obj;
    this.key = key;
    this.cb = cb;
    this.value = this.get(); // 将自己添加到Dep.target
  }

  get() {
    Dep.target = this;
    const value = this.obj[this.key]; // 触发getter,将当前Watcher添加到依赖中
    Dep.target = null;
    return value;
  }

  update() {
    this.value = this.get(); // 触发getter,更新value
    this.cb.call(this.obj, this.value); // 执行回调函数,更新data
  }
}

// 测试
const person = {
  name: 'Tom',
  age: 18
};

Observer(person);

new Watcher(person, 'name', function(newVal) {
  console.log(`Name changed to ${newVal}`);
});

person.name = 'Jerry'; // 触发name属性的setter方法

示例2:响应式数组

// 为数组添加getter和setter方法,来实现响应式
const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto);

const methodsToPatch = [
  'push',
  'pop',
  'unshift',
  'shift',
  'splice',
  'sort',
  'reverse'
];

methodsToPatch.forEach(function (method) {
  const original = arrayProto[method];
  Object.defineProperty(arrayMethods, method, {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function mutator(...args) {
      const result = original.apply(this, args);
      const ob = this.__ob__;
      let inserted;
      // 每当数组发生变化时,需要将新加入的值变成一个响应式对象
      switch (method) {
        case 'push':
          inserted = args;
          break;
        case 'unshift':
          inserted = args;
          break;
        case 'splice':
          inserted = args.slice(2);
          break;
      }
      if (inserted) {
        ob.observeArray(inserted);
      }
      ob.dep.notify();
      return result;
    }
  });
});

// 创建一个Observer对象,为数组对象添加getter和setter方法
function observeArray(arr) {
  Object.setPrototypeOf(arr, arrayMethods);
  // 递归为数组元素添加响应式
  for (let i = 0, l = arr.length; i < l; i++) {
    observe(arr[i]);
  }
}

// 测试
const arr = [1, 2, 3];

observeArray(arr);

new Watcher(arr, function (newVal) {
  console.log(`Array changed to ${newVal}`);
});

arr.push(4); // 触发数组的push方法

总结

以上就是实现Vue的响应式(对象观测)的完整攻略。Vue采用Object.defineProperty()实现响应式数据绑定,核心思想是依靠数据劫持和发布-订阅模式来实现。

在实现过程中,需要创建Observer对象、收集依赖、派发更新、为数组添加getter和setter方法等步骤。通过上述两个示例,我们可以更加深入地理解Vue的响应式原理和实现方式,对于Vue应用的开发将有一定的帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:一步一步实现Vue的响应式(对象观测) - Python技术站

(0)
上一篇 2023年5月27日
下一篇 2023年5月27日

相关文章

  • Vue3新状态管理工具实例详解

    Vue3新状态管理工具实例详解 Vue.js是一个基于MVVM模式的前端框架,目前Vue.js的使用非常普及和流行。在Vue.js的应用开发中,状态管理是必不可少的一部分,因此Vue.js提供了Vuex状态管理工具来帮助我们进行管理和组织应用中的状态数据。而最新的Vue.js版本——Vue3也推出了新的状态管理工具——@vue/reactivity。 什么是…

    Vue 2023年5月29日
    00
  • node.js从前端到全栈的必经之路

    Node.js从前端到全栈的必经之路 在现代Web开发中,Node.js技术越来越重要,它作为一个轻量级的解决方案,可以帮助前端开发者从一个只能生产HTML、CSS和JavaScript的Web开发者,逐步变成一个能够为整个Web应用程序提供优质服务的全栈开发者。以下是一个从前端到全栈的Node.js学习路线和攻略: 1. 初步认识Node.js Node.…

    Vue 2023年5月28日
    00
  • vue引用js文件的多种方式(推荐)

    当我们使用Vue进行开发时,我们经常需要引入一些第三方库来辅助我们完成开发。这时候我们需要了解几种Vue引用JS文件的方式。 1. 直接使用script标签引入 使用script标签以最原始的方式引入JS文件,这是所有前端开发者都很熟悉的引用方式。在Vue中,我们同样可以使用这种方式。比如我们要引入jQuery库: <!DOCTYPE html>…

    Vue 2023年5月29日
    00
  • 可能是vue中使用axios最详细教程

    可能是vue中使用axios最详细教程 什么是axios axios是一个基于Promise的HTTP客户端,可以用于浏览器和node.js中,它的特点如下: 从浏览器中创建XMLHttpRequest 从node.js创建 http请求 支持Promise API 拦截请求和响应 转换请求和响应数据 自动转换JSON数据 安装axios 要使用axios,…

    Vue 2023年5月28日
    00
  • Vue路由模式中的hash和history模式详细介绍

    Vue路由模式中的hash和history模式详细介绍 背景知识 在前端开发中,路由是必不可少的一环,能够支持路由的前端框架也因此非常的流行。Vue框架内部也实现了一个基于组件的路由系统——Vue Router。 Vue Router Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。…

    Vue 2023年5月27日
    00
  • v-html渲染组件问题

    简介: 在Vue.js开发中,v-html指令可以让我们插入HTML代码,有时我们会遇到将一个组件作为HTML输入到v-html指令中的需求。但是这样做存在一些问题,比如组件不会被实例化,无法正常响应数据等。下面是具体的解决方法。 步骤: 1.理解v-html的作用 v-html指令用来动态的输出已经被渲染成 HTML 的字符串,而不是DOM元素。可以将一个…

    Vue 2023年5月28日
    00
  • 详解Vue-cli中的静态资源管理(src/assets和static/的区别)

    Vue-cli中的静态资源管理是一项非常重要的功能,包含两个目录:src/assets和static/。在实际开发中,了解这两个目录的区别对于我们合理使用静态资源、提高开发效率非常有帮助。 一、src/assets src/assets 目录用于存放应用程序中需要在代码中 import 的静态资源文件,如 .css、 .scss、 .js、 图片、字体、sv…

    Vue 2023年5月27日
    00
  • vue组件代码分块和懒加载讲解

    我们来详细讲解“vue组件代码分块和懒加载讲解”的攻略。 概述 首先,我们需要明确一个概念:Vue.js 是一个渐进式的JavaScript框架,其中的组件化是一个非常重要的特点,可以让我们的代码更加易维护和协作。但是,当项目规模非常大时,组件的数量也会变得非常多,这时就会导致页面加载速度慢的问题。因此,为了优化项目的性能,我们可以通过将代码分块和懒加载来实…

    Vue 2023年5月29日
    00
合作推广
合作推广
分享本页
返回顶部