VUE2双向绑定的原理

文章目录

  • VUE2双向绑定的原理
  • 1. 什么是双向绑定
  • 2. 双向绑定的原理
    • 2.1 ViewModel的重要作用
    • 2.2 双向绑定的流程
  • 3. 双向绑定的实现
    • 3.1 data响应化处理
    • 3.2 Compile编译
    • 3.3 依赖收集

VUE2双向绑定的原理

1. 什么是双向绑定

  • 讲双向绑定先讲单项绑定,啥叫单项绑定,就是一句话就是通过Model去改变View,再直白点,就是通过js代码把数据改变后,html视图也跟着变化
  • 那双项绑定就很好理解了,在单项绑定的基础上,如果view改变了,Model也能同步变化
  • 一句话概括就是,Model变化View跟着跟新,View跟新,Model跟着变化,这就是双向绑定

2. 双向绑定的原理

  • 其实我们可以很容易想到一点就是,如果A变化了想要B跟着变化,最简单的方式就是,A变化的时候通知一下B就行,这就是基本思路
  • 在VUE2 中,双向绑定由三个重要部分构成
  1. 数据层(Model),应用的数据及业务逻辑
  2. 视图层(View),应用的展示效果,理解为UI组件
  3. 业务逻辑层(ViewModel),框架封装的核心,他主要负责把数据层和视图层关联起来,这就是MVVM模型

2.1 ViewModel的重要作用

  • ViewModel主要干两件事
  1. 数据变化后,更新视图
  2. 视图变化后,更新数据
  • 那么问题来了,怎么通知呢,我们怎么知道数据变化后,通知哪些视图呢
  • 这要依赖ViewModel的两个重要部件
  1. 监听器(Observer),对所有数据的属性进行监听
  2. 解析器(Compiler),对元素节点的指令进行扫描跟解析,根据指令模板替换数据,以及绑定相应的更新函数

2.2 双向绑定的流程

  • 双向绑定的流程
  1. 我们在new Vue()时,执行初始化,对data执行相应化处理,这个过程发生在Observer中
  2. 同时对模板执行编译,找到其中动态绑定的数据,从data中获取并初始化视图,这个过程发生在Compiler中
  3. 同时定义一个更新函数和Watcher,将来对应数据变化时,Watcher会调用更新函数
  4. 由于data中的数据的某个key可能出现在视图的多处,所以每个key都需要一个管家Dep来管理多个Watcher
  5. 将来数据一旦发生变化,会首先找到对应的Dep,通过Dep李曼的所有Watcher执行更新函数
    在这里插入图片描述

3. 双向绑定的实现

3.1 data响应化处理

  • 我们来创建一个构造函数,执行初始化,对data数据执行响应化处理
class Vue{
    constrcutor(options){
        this.$options=options;
        this.$data=options.data;
        //对data选项做响应式处理
        Observe(this.$data)
        //代理data到vm上
        proxy(this)
        // 执行编译
        new Compile(options.el,this)
    }
}
function Observe(obj){
    if(typeof obj!=='object' || obj===null){
        return;
    }
    new Observer(obj)
}
class Observer{
    constructor(value){
        this.value=value;
        this.walk(value)
    }
    walk(obj){
        Object.keys(obj).forEach((key)=>{
            defineReactive(obj,key,obj[key])//内部是Object.defineProperty实现,后面会讲
        })
    }
}

3.2 Compile编译

  • 对元素节点的指令机型扫描跟解析,根据指令模板替换数据,以及绑定相应的更新函数
class Compile{
    constructor(el,vm){
        this.$vm=vm;
        this.$el=document.querySelector(el);//获取DOM
        if(this.$el)this.compile(this.#el)
        
    }
    compile(el){
        const childNodes=el.ChildNodes;
        Array.from(childNodes).forEach((node)=>{//遍历子元素
            if(this.isElement(node)){//判断是否为节点
                /*编译元素*/
            }else if(this.inInterpolation(node)){//是否为差值文本
                /*编译差值文本*/
            }
            if(node.childNodes && node.childNodes.length>0){
                this.compile(node)
            }
        })
    }
    isElement(node){
        return node.nodeType===1
    }
    isInterpolation(node){
        return node.nodeType===3 && /\{\{(.*)\}\}/.test(node.textContent)
    }
}

3.3 依赖收集

  • 视图中会用到data中的某个key,这被称为依赖,一个key可能出现在视图中的多个位置,每次都需要收集出来用一个Watcher来维护他们,这个过程被称为依赖收集,很多歌Watcher需要一个Dep来管理,需要更新时由Dep统一通知
    在这里插入图片描述

  • 基本思路

  1. defineReactive为每一个key创建一个Dep,比如data1创建Dep1
  2. 初始化视图时,读取某个key,例如data1,就创建一个watcher1
  3. 由于读取key时触发getter方法,边疆watcher1天假到data1的Dep1中份
  4. 当data1更新时,触发setter,通过Dep1通知所有的watcher更新
class Wacther{
    constructor(vm,key,updater){
        this.$vm=vm;
        this.$key=key;
        this.updaterFn=updater;
        //创建实例时,把当前实例指定到Dep.target静态属性上
        Dep.target=this;
        vm[key]//读一下key,触发get
        Dep.target=null
        update(){
            this.updaterFn.call(this.$vm,this.$vm[this.$key])
        }
    }
}
class Dep{
    constructor(){
       this.deps=[];//依赖管理 
    }
    addDep(dep){
        this.deps.push(dep)
    }
    notify(){
        this.deps.forEach((dep)=>{
            dep.update()
        })
    }
}
// 创建Watcher时触发getter
function defineReactive(obj,key,val){
    this.observe(val)
    const dep=new Dep()
    Object.defineProperty(obj,key,{
        get (){
            Dep.target && dep.addDep(Dep.target)//Dep.target就是Watcher实例
            return val
        },
        set(newVal){
          if(newVal===val)return
          dep.notify()//通知dep执行更新方法  
        }
    })
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/965036.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

入行FPGA设计工程师需要提前学习哪些内容?

FPGA作为一种灵活可编程的硬件平台,广泛应用于嵌入式系统、通信、数据处理等领域。很多人选择转行FPGA设计工程师,但对于新手来说,可能在学习过程中会遇到一些迷茫和困惑。为了帮助大家更好地准备,本文将详细介绍入行FPGA设计工程…

Mac M1 ComfyUI 中 AnyText插件安装问题汇总?

Q1:NameError: name ‘PreTrainedTokenizer’ is not defined ? 该项目最近更新日期为2024年12月,该时间段的transformers 版本由PyPI 上的 transformers 页面 可知为4.47.1. A1: transformers 版本不满足要求,必须降级transformors &#…

深度学习 Pytorch 神经网络的学习

本节将从梯度下降法向外拓展,介绍更常用的优化算法,实现神经网络的学习和迭代。在本节课结束将完整实现一个神经网络训练的全流程。 对于像神经网络这样的复杂模型,可能会有数百个 w w w的存在,同时如果我们使用的是像交叉熵这样…

Java 大视界 -- 深度洞察 Java 大数据安全多方计算的前沿趋势与应用革新(52)

💖💖💖亲爱的朋友们,热烈欢迎你们来到 青云交的博客!能与你们在此邂逅,我满心欢喜,深感无比荣幸。在这个瞬息万变的时代,我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

Docker使用指南(二)——容器相关操作详解(实战案例教学,创建/使用/停止/删除)

目录 1.容器操作相关命令​编辑 案例一: 案例二: 容器常用命令总结: 1.查看容器状态: 2.删除容器: 3.进入容器: 二、Docker基本操作——容器篇 1.容器操作相关命令 下面我们用两个案例来具体实操一…

【C++】STL——list的使用

目录 💕1.带头双向链表List 💕2.list用法介绍 💕3.list的初始化 💕4.size函数与resize函数 💕5.empty函数 💕6.front函数与back函数 💕7.push_front,push_back,pop_front,pop_back函数…

Java面试题集合篇5:10道基础面试题

文章目录 前言41、多线程使用 ArrayList42、List 和 Set 区别43、HashSet 实现原理44、HashSet检查重复和保证数据不可重复45、BlockingQueue46、Map接口46.1、HashMap实现原理46.2、HashMap在JDK1.7和JDK1.8中不同点46.3、JDK1.7 VS JDK1.8 比较 47、HashMap的put方法流程48、…

控件【QT】

文章目录 控件QWidgetenabledgeometrysetGeometry qrcwindowOpacityQPixmapfonttoolTipfocusPolicystyleSheetQPushButtonRadio ButtionCheck Box显示类控件QProgressBarcalendarWidget 控件 Qt中已经提供了很多内置的控件了(按钮,文本框,单选按钮,复选按钮,下拉框…

docker pull Error response from daemon问题

里面填写 里面解决方案就是挂代理。 以虚拟机为例,将宿主机配置端口设置,https/http端口设为7899 配置虚拟机的http代理: vim /etc/systemd/system/docker.service.d/http-proxy.conf里面填写,wq保存 [Service] Environment…

linux 进程补充

环境变量 基本概念 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数 如:我们在编写C/C代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪 里,但是照样可以链接成功&#…

一文解释pytorch 中的 squeeze() 和 unsqueeze()函数(全网最详细版)

🌈 个人主页:十二月的猫-CSDN博客 🔥 系列专栏: 🏀零基础入门PyTorch框架_十二月的猫的博客-CSDN博客 💪🏻 十二月的寒冬阻挡不了春天的脚步,十二点的黑夜遮蔽不住黎明的曙光 目录 …

QT:对象树

1.概念 Qt 中的对象树是一种以树形结构组织 Qt 对象的方式。当创建一个QObject(Qt 中大多数类的基类)或其派生类的对象时,可以为其指定一个父对象(parent)。这个对象就会被添加到其父对象的子对象列表中,形…

labview通过时间计数器来设定采集频率

在刚接触labview的时候,笔者通常用定时里的等待函数来实现指令的收发,但是当用到的收发消息比较多时就出现了卡顿,卡死的情况,这是因为当用队列框架时,程序卡在了其中的一个分支里,等通过相应的延时后才可以…

2024最新前端面试题(附答案及解析)

文章目录 HTML篇1、HTML5有哪些新特性?2、介绍下 BFC 及其应用3、内元素和块级元素的区别?4、Doctype作用?标准模式与混杂模式如何区分?5、引入样式时,link和import的区别?6、介绍一下你对浏览器内核的理解…

Linux:文件系统(软硬链接)

目录 inode ext2文件系统 Block Group 超级块(Super Block) GDT(Group Descriptor Table) 块位图(Block Bitmap) inode位图(Inode Bitmap) i节点表(inode Tabl…

Java基础面试题50题

1&#xff0c;""空字符串的作用 package com.neuedu.nineteen;public class Test {public static void main(String[] args) {String s"";for (char i a; i < d; i) {ssi;//输出abc // sis;//输出cba}System.out.println(s);} }如题所示&…

【技海登峰】Kafka漫谈系列(二)Kafka高可用副本的数据同步与选主机制

【技海登峰】Kafka漫谈系列(二)Kafka高可用副本的数据同步与选主机制 一. 数据同步 在之前的学习中有了副本Replica的概念,解决了数据备份的问题。我们还需要面临一个设计难题即:如何处理分区中Leader与Follwer节点数据同步不匹配问题所带来的风险,这也是保证数据高可用的…

GB/T 44721-2024 与 L3 自动驾驶:自动驾驶新时代的基石与指引

1.前言 在智能网联汽车飞速发展的当下&#xff0c;自动驾驶技术成为了行业变革的核心驱动力。从最初的辅助驾驶功能&#xff0c;到如今不断迈向高度自动化的征程&#xff0c;每一步都凝聚着技术的创新与突破。而在这一进程中&#xff0c;标准的制定与完善对于自动驾驶技术的规…

大语言模型的个性化综述 ——《Personalization of Large Language Models: A Survey》

摘要&#xff1a; 本文深入解读了论文“Personalization of Large Language Models: A Survey”&#xff0c;对大语言模型&#xff08;LLMs&#xff09;的个性化领域进行了全面剖析。通过详细阐述个性化的基础概念、分类体系、技术方法、评估指标以及应用实践&#xff0c;揭示了…

SpringBoot使用 easy-captcha 实现验证码登录功能

文章目录 一、 环境准备1. 解决思路2. 接口文档3. redis下载 二、后端实现1. 引入依赖2. 添加配置3. 后端代码实现4. 前端代码实现 在前后端分离的项目中&#xff0c;登录功能是必不可少的。为了提高安全性&#xff0c;通常会加入验证码验证。 easy-captcha 是一个简单易用的验…