软件教程 2025年08月6日
0 收藏 0 点赞 694 浏览 3732 个字
摘要 :

文章目录 一、双向数据绑定原理 二、双向数据绑定的实现方式 (一)监听器的实现 (二)Compile模板解析 双向数据绑定是Vue的重要功能之一,它让数据与视图之间的交互……




  • 一、双向数据绑定原理
  • 二、双向数据绑定的实现方式
    • (一)监听器的实现
    • (二)Compile模板解析

    双向数据绑定是Vue的重要功能之一,它让数据与视图之间的交互变得便捷,今天,咱们就来深入探讨一下Vue2和Vue3在双向数据绑定原理与实现上的差异

    一、双向数据绑定原理

    Vue实现双向数据绑定的核心依托于MVVM模式,该模式由三部分构成:

    • Model(数据层):在Vue里,它主要负责存储数据,是应用程序中数据的载体。比如说,一个待办事项列表应用中,待办事项的内容、完成状态等数据就存储在Model中。
    • View(视图层):这部分由HTML模板和Vue指令组成,也就是用户直接看到并与之交互的界面。用户在页面上看到的待办事项的展示、输入框等都属于View层。
    • ViewModel(业务逻辑层):它是Vue的核心部分,作为一个Vue实例,就像一座桥梁,连接着Model和View。当Model中的数据发生变化时,ViewModel能够监听到这些变化,并通过相应机制更新View;反之,当用户在View上进行操作(如输入内容、点击按钮等),ViewModel也能捕获这些事件,并将变化同步到Model中。

    在双向数据绑定的过程中,当数据发生变化时,监听器(Observer)会触发依赖通知,从而实现对视图层的更新;而当用户操作视图时,解析器(Compiler)会捕获相关事件(例如v-model指令下的输入操作),进而更新数据层。

    二、双向数据绑定的实现方式

    (一)监听器的实现

    在Vue中,监听器用于监听数据变化,主要有数据劫持和发布 – 订阅模式这两种实现方式。

    1. 数据劫持
      • Vue2的实现:Vue2利用Object.defineProperty方法来实现数据劫持。这个方法能够拦截对象属性的gettersetter操作。在getter中,会收集依赖,也就是记录哪些地方使用了这个数据;而在数据变化,即setter被调用时,通过触发之前收集依赖过程中记录的更新函数,来实现视图的更新。下面通过一个简单示例来理解:
    //示例
    const o = {};
    let bValue = 38;
    Object.defineProperty(o, \"b\", {
        get() {
            //收集依赖
            return bValue;
        },
        set(newValue) {
            bValue = newValue;
            // 触发视图更新
        },
    });
    

    在这个例子里,定义了一个对象o,并通过Object.defineProperty对其属性b进行劫持。当获取b的值时,会执行get函数,在这里可以进行依赖收集;当设置b的值时,set函数被调用,除了更新数据bValue,还可以在这个函数里添加触发视图更新的逻辑。
    Vue3的实现:Vue3则使用Proxy来替代Object.definePropertyProxy可以创建一个对象的代理,通过它能够方便地对对象的基本操作(如获取属性、设置属性等)进行拦截和自定义。当调用代理对象的get方法时,会进行依赖收集;调用set方法时,就会进行依赖更新。具体语法为const p = new Proxy(target, handler),其中target是要使用Proxy包装的目标对象,可以是各种类型的对象,包括数组、函数等;handler是一个包含各种函数的对象,这些函数定义了代理在执行不同操作时的行为。示例如下:

    //示例
    let products = new Proxy(
        {
            browsers: [\"Internet Explorer\", \"Netscape\"],
        },
        {
            get: function (obj, prop) {
                // 收集依赖
                return obj[prop];
            },
            set: function (obj, prop, value) {
                obj[prop] = value;
                // 触发视图更新,表示成功
                return true;
            },
        },
    );
    

    在这个示例中,创建了一个products的代理对象。当访问products的属性时,get函数会被调用进行依赖收集;当设置属性值时,set函数被调用,更新对象属性的同时触发视图更新。
    2. 发布 – 订阅模式
    Vue.js借助发布 – 订阅模式来管理组件和数据之间的依赖关系。简单来说,当数据发生变化时,依赖于这些数据的视图(可以理解为观察者)会收到通知并进行更新。下面通过一段代码来详细了解:

    // 1. 发布者类
    class Dep {
        constructor() {
            this.subscribers = [];
        }
        // 依赖收集
        depend() {
            if (Dep.target &&!this.subscribers.includes(Dep.target)) {
                this.subscribers.push(Dep.target);
            }
        }
        // 通知更新
        notify() {
            this.subscribers.forEach(sub => sub());
        }
    }
    
    // 2. 
    // ①数据劫持 Vue2-Start
    function defineReactive(obj, key, val) {
        const dep = new Dep();
        Object.defineProperty(obj, key, {
            get() {
                dep.depend();      // 收集依赖
                return val;
            },
            set(newVal) {
                val = newVal;
                dep.notify();      // 触发更新
            }
        });
    }
    // Vue2-End
    
    // ②响应式代理 Vue3-Start
    function reactive(obj) {
        const deps = new Map(); // 存储每个属性的依赖
    
        return new Proxy(obj, {
            get(target, key) {
                let dep = deps.get(key);
                if (!dep) {
                    dep = new Dep();
                    deps.set(key, dep);
                }
                if (Dep.currentEffect) {
                    dep.depend(Dep.currentEffect); // 收集依赖
                }
                return target[key];
            },
            set(target, key, value) {
                target[key] = value;
                deps.get(key)?.notify(); // 触发更新
                return true;
            }
        });
    }
    // Vue3-End
    
    // 3. 观察者函数
    function watch(effect) {
        Dep.target = effect;   // 标记当前依赖
        effect();              // 首次执行以触发getter
        Dep.target = null;     // 重置
    }
    
    // 使用示例
    const data = {};
    defineReactive(data, \'count\', 0);
    
    // 订阅数据变化
    watch(() => {
        console.log(\'Count updated:\', data.count);
    });
    
    // 触发更新
    data.count = 1; // 输出: \"Count updated: 1\"
    

    在这段代码中,Dep类充当发布者,它维护了一个订阅者数组subscribersdepend方法用于收集依赖,将相关的观察者添加到数组中;notify方法则用于通知所有订阅者进行更新。defineReactive函数是Vue2中结合发布 – 订阅模式实现数据劫持的关键,在getset操作中分别进行依赖收集和更新通知。Vue3中的reactive函数通过ProxyDep实现了类似的功能,不过在依赖管理上使用了Map来存储每个属性的依赖。watch函数则是一个简单的观察者函数示例,用于订阅数据变化并执行相应操作。

    (二)Compile模板解析

    Compile主要负责实现视图到数据的绑定,其过程分为以下两个阶段:

    1. 解析阶段:遍历DOM树,识别各种Vue指令,比如v-model{{}}插值等。针对每个指令,创建对应的更新函数,并将其绑定到相应的数据依赖上。例如,下面这个处理v-model指令的函数:
    function compileInput(node, data, key) {
        node.value = data[key]; // 初始化值
        node.addEventListener(\'input\', (e) => {
            data[key] = e.target.value; // View → Model
        });
        // 订阅数据变化,更新视图
        watch(key, (value) => node.value = value); // Model → View
    }
    

    在这个函数里,首先将数据绑定到输入框的初始值。然后,通过监听输入框的input事件,当用户在输入框中输入内容时,将输入的值同步到数据层(View → Model)。同时,通过watch函数订阅数据变化,当数据发生改变时,更新输入框的显示内容(Model → View)。
    2. 虚拟DOM优化:Vue会将模板转换为轻量级的虚拟DOM树。当数据发生变化时,会生成新的虚拟DOM,然后通过Diff算法比对新旧虚拟DOM的差异,只对真实DOM中发生变化的部分进行更新。这样做可以大大减少对真实DOM的操作次数,提高页面的性能和渲染效率。

    通过对Vue2和Vue3双向数据绑定原理与实现的深入分析,我们可以看到这两个版本在技术实现上的演进和优化。理解这些差异,有助于我们在实际项目中更好地选择和运用Vue框架,大家还是要掌握下为好哦。

微信扫一扫

支付宝扫一扫

版权: 转载请注明出处:https://www.zuozi.net/6980.html

管理员

相关推荐
2025-08-06

文章目录 一、Promise基础回顾 二、Promise 与 axios 结合使用场景及方法 (一)直接返回 axios …

269
2025-08-06

文章目录 一、模块初始化时的内部机制 二、常见导出写法的差异分析 (一)写法一:module.exports…

107
2025-08-06

文章目录 一、ResizeObserver详解 (一)ResizeObserver是什么 (二)ResizeObserver的基本用法 …

683
2025-08-06

文章目录 一、前期准备工作 (一)下载相关文件 (二)安装必要工具 二、处理扣子空间生成的文件…

338
2025-08-06

文章目录 一、官方文档 二、自动解包的数据类型 ref对象:无需.value即可访问 reactive对象:保持…

371
2025-08-06

文章目录 一、Hooks的工作原理 二、在if语句中使用Hook会出什么岔子? 三、React官方的Hook使用规…

843
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:08:00-23:00

客服QQ

122325244

客服电话

400-888-8888

客服邮箱

122325244@qq.com

扫描二维码

关注微信客服号