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>
相关推荐
amy_jork4 分钟前
android studio打包vue
android·vue.js·android studio
前端小巷子8 分钟前
前端工程化——Webpack
前端·javascript·面试
结城15 分钟前
聊聊原生 CSS 变量:让样式更灵活的“魔法”
前端·css
小屁孩大帅-杨一凡18 分钟前
如何使用markdownify库将HTML转换为Markdown?
开发语言·前端·python·html
啃火龙果的兔子3 小时前
修改 Lucide-React 图标样式的方法
前端·react.js·前端框架
前端 贾公子3 小时前
为何在 Vue 的 v-model 指令中不能使用可选链(Optional Chaining)?
前端·javascript·vue.js
潘多拉的面3 小时前
Vue的ubus emit/on使用
前端·javascript·vue.js
遗憾随她而去.3 小时前
js面试题 高频(1-11题)
开发语言·前端·javascript
hqxstudying6 小时前
J2EE模式---前端控制器模式
java·前端·设计模式·java-ee·状态模式·代码规范·前端控制器模式
Microsoft Word6 小时前
用户中心项目实战(springboot+vue快速开发管理系统)
vue.js·spring boot·后端