Vue2 和 Vue3 双向数据绑定原理

一、Vue的双向数据绑定原理

1.1双向数据绑定的流程

  1. new Vue()首先执行初始化,对data执行响应化处理,这个过程发生Observe
  2. 同时对模板执行编译,找到其中动态绑定的数据,从data中获取并初始化视图,这个过程发生在Compile
  3. 同时定义⼀个更新函数和Watcher,将来对应数据变化时Watcher会调用更新函数
  4. 由于data的某个key在⼀个视图中可能出现多次,所以每个key都需要⼀个管家Dep来管理多个Watcher
  5. 将来data中数据⼀旦发生变化,会首先找到对应的Dep,通知所有Watcher执行更新函数

流程图如下:

1.2 双向数据组成

我们都知道 Vue 是数据双向绑定的框架,双向绑定由三个重要部分构成

  • 数据层(Model):应用的数据及业务逻辑,对应data及methods

  • 视图层(View):应用的展示效果,各类UI组件

  • 业务逻辑层(ViewModel):框架封装的核心,它负责将数据与视图关联起来,就是

    数据变化后更新视图, 视图变化后更新数据

二、Vue2 双向数据绑定流程及实现

2.1 双向数据绑定原理

Vue2的双向数据绑定主要是通过Object.defineProperty()这个方法来实现的,就好像有一个小管家在帮你看着数据和页面。

  1. 数据监听:Object.defineProperty()能给对象的属性添加 getter(获取值的方法)和 setter(设置值的方法)。Vue2会遍历数据对象的所有属性,用这个方法把它们都变成"特殊属性"。比如有个数据对象data,里面有个属性message,Vue2就会给message加上getter和setter。当你读取message的值时,就会触发getter;当你给message赋值时,就会触发setter。这就好像小管家在你访问或修改数据的时候都能知道。
  2. 发布订阅模式:在Vue2里,还有一个叫做"观察者"的东西。数据变化时,setter会通知这些"观察者","观察者"再去通知依赖这个数据的视图进行更新。比如message的值变了,setter就告诉"观察者","观察者"再告诉页面上显示message的地方,让它更新显示的内容。同样,当用户在页面上修改了数据,比如在输入框里改了message的值,这个变化也会通过"观察者"传给数据对象,实现双向数据绑定。
  3. 虚拟DOM:Vue2会把真实的DOM结构抽象成一个虚拟DOM树,当数据变化时,不会马上更新真实DOM,而是先在虚拟DOM上进行计算和比较,找出哪些地方需要更新,最后再一次性更新真实DOM。这样可以减少对真实DOM的操作,提高更新效率。

2.2 Object.defineProperty()方法简介

javascript 复制代码
//直接在一个对象上定义一个新属性,或者修改一个已经存在的属性, 并返回这个对象
Object.defineProperty(obj,prop,descriptor)
//参数说明:obj:需要定义属性的对象,prop:需被定义或修改的属性名,descriptor:需被定义或修改的属性的描述符。
属性 默认值 说明
configurable false 描述属性是否可以被删除,默认为 false
enumerable false 描述属性是否可以被for...in或Object.keys枚举,默认为 false
writable false 描述属性是否可以修改,默认为 false
get undefined 当访问属性时触发该方法,默认为undefined
set undefined 当属性被修改时触发该方法,默认为undefined
value undefined 属性值,默认为undefined

2.3 用js实现一个最简单的双向数据绑定

xml 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>简化版双向绑定</title>
    <style>
        input {width: 100%;padding: 8px;margin-bottom: 10px;box-sizing: border-box;}
        .display {margin-top: 20px;padding: 10px;background: #f5f5f5;border-radius: 5px;}
    </style>
</head>
<body>
    <div class="container">
        <input type="text" id="inputField" placeholder="输入内容...">
        <div class="display" id="displayText"></div>
    </div>
​
    <script>
        // 1. 定义一个简单的数据对象
        const data = {
            message: ''
        };
        // 2. 使数据对象响应式
        Object.defineProperty(data, 'message', {
            get() {
                return this._message; //之所以不用this.message,是为了避免再次出发getter,发生无限循环,下划线前缀是一种常见的约定,表示这是一个内部属性,不应该直接从外部访问
            },
            set(newValue) {
                this._message = newValue;
                // 3. 数据变化时更新DOM
                document.getElementById('displayText').textContent = newValue;
                // document.getElementById('inputField').value = newValue;
            }
        });
​
        // 4. 监听输入框变化,更新数据
        document.getElementById('inputField').addEventListener('input', function(e) {
            data.message = e.target.value;
        });
        // 5. 初始化显示
        data.message = '试试输入内容...';
    </script>
</body>
</html>

三、Vue3 双向数据绑定流程及实现

3.1 双向数据绑定原理

Vue3的双向数据绑定原理和Vue2有些不同, Vue3 使用 JavaScript 的 Proxy 对象来实现响应式数据。Proxy 可以监听对象的所有操作,包括读取、写入、删除属性等,从而实现更加灵活和高效的响应式数据。

1、Proxy代理:Proxy可以用来创建一个对象的代理,对这个对象的所有操作进行拦截和处理。Vue3用Proxy来代理数据对象,它比Object.defineProperty()更强大,能直接监听整个对象的变化,而不是像Vue2那样要一个属性一个属性地监听。比如还是有个data对象和message属性,用Proxy代理data后,不管是访问还是修改data里的任何属性,Proxy都能知道,不需要像Vue2那样单独给每个属性设置getter和setter,就好像这个小管家能一下子管好多事情,不用一件一件去处理。

2、响应式系统:Vue3基于Proxy建立了一套响应式系统。当数据变化时,Proxy会拦截到变化,然后通知相关的组件进行更新。这个过程更加高效和灵活,能更好地处理复杂的数据结构和变化。

3、虚拟DOM:Vue3的虚拟DOM也有一些改进,它采用了更高效的算法来比较和更新虚拟DOM,比如静态提升、PatchFlag等技术,能更精准地找到需要更新的地方,进一步提高了更新效率。

3.2响应式系统

3.2.1 reactive函数

Vue3 提供了一个 reactive 函数来创建响应式对象,通过 reactive 函数包装的对象会变成响应式数据,Vue 会自动跟踪这些数据的变化。

javascript 复制代码
import { reactive } from 'vue';
const state = reactive({
    message: 'Hello Vue3'
});

3.2.2 ref 函数

对于基本数据类型,如字符串、数字等,Vue3 提供了 ref 函数来创建响应式数据,使用 ref 包装的值可以在模板中进行双向绑定

csharp 复制代码
import { ref } from 'vue';
const count = ref(0);

3.2.3 如何双向数据绑定

Vue3 中的双向绑定主要通过 v-model 指令来实现,适用于表单元素,如输入框、复选框等。以下是一个简单的示例:

xml 复制代码
<template>
    <input v-model="message" />
    <p>{{ message }}</p>
</template>
 
<script>
import { ref } from 'vue';
export default {
    setup() {
        const message = ref('');
        return {
            message
        }
    }
}
</script>
相关推荐
weixin_382395231 小时前
为小工厂量身打造:本地部署的物料管理系统带缺料计算
前端·制造
__zRainy__1 小时前
解决pnpm v10+不自动构建
前端·pnpm·工程化
猫猫不是喵喵.2 小时前
Vue3 Props 属性
前端·javascript·vue.js
醉城夜风~3 小时前
CSS元素显示模式(display)
前端·css
AI大模型-小华3 小时前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子6 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅6 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni6 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学7 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端