vue的双向绑定原理_vue的双向绑定原理及实现

vue的双向绑定原理_vue的双向绑定原理及实现前置:弟弟也是小白一个,看源码以小萌新角度分析可能适合一些跟我一样的小白去理解,有讲不对的请大佬多多海涵和指点首先我觉得理解vue双向绑定原理应该要有略懂一下发布订阅者模式,我略带过一下。与观察者模式不同的是,发布订阅者多了一个中间调度中心而已。下面给两个比较好的例子观察者模式:观察者(Observer)直接订阅(Subscribe)主题(Subject),而当主题被激活的时候,会触发(FireEvent)观察者里的事件(用网上比较好的例子,忘记作者链接了,如果打扰到您请联系我删了)。.

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

前置:弟弟也是小白一个,看源码以小萌新角度分析可能适合一些跟我一样的小白去理解,有讲不对的请大佬多多海涵和指点

首先我觉得理解vue双向绑定原理应该要有略懂一下发布订阅者模式,我略带过一下。与观察者模式不同的是,发布订阅者多了一个中间调度中心而已。下面给两个比较好的例子

观察者模式:观察者(Observer)直接订阅(Subscribe)主题(Subject),而当主题被激活的时候,会触发(Fire Event)观察者里的事件(用网上比较好的例子,忘记作者链接了,如果打扰到您请联系我删了)。

1.png

2.png

大白话:
大概意思就是观察者(爸爸妈妈)订阅主题(宝宝的行为),一旦主题改变(宝宝发生了某个行为,比如说饿了),便会通知观察者里的事件(爸爸妈妈各自的行为去做某些事)。最常见就是你页面上的按钮事件,等你点击便会通知对应的方法。

发布订阅模式:订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Event Channel),当发布者(Publisher)发布该事件(Publish Event)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码(用网上比较好的例子,忘记作者链接了,如果打扰到您请联系我删了)。

3.png

4.png

大白话:

  1. 发布订阅者模式与观察者模式很像,但是区别的就是,缺少多个主题。
  2. 发布订阅者模式多了个调度中心,该调度中心主要收录不同的类型,比如说宝宝尿床了, 宝宝饿了
  3. 根据不同类型让不同订阅者去执行对应的方法,比如尿床了就让爸爸去洗裤子,饿了就让妈妈喂奶,vue就是用订阅发布模式实现的。

接下来就讲下vue的双向绑定原理,先喵一下这几个东西:

  1. observe
  2. watch
  3. Dep

observe: 在实例化时,先触发observe,递归地对所有data中的变量进行订阅,并且,每次订阅之前,都会生成一个dep实例。

dep(调度中心): 大白话解释就是一个容器,打比分你定义了一个data中定义了name属性,那就会有一个name的dep(调度中心), 主要作用就是存放watch实例,也就是你的html上用到name的地方的,{
{name}} v-modle:name 等等。

watch: 主要是用来更新模板的,但是值得注意的是每个变量引用的地方都会生成一个watch实例,{
{name}} v-modle:name 会生成两个, 这样当更新数据的时候dep会去循环调用watch实例的回调方法(更新html模板的方法)就行。

`D@J58N4IA@R{NAG}5(VJAD.jpg

看完这三个的作用后,我们看看是怎么关联起来去实现双向绑定的:

image.png

解析一下:observe 这个方法就是去递归data中的数据进行订阅,你可以看到在171行有个

  • let dep = new Dep();
    这个就是刚才所说的,每个属性都会添加一个dep调度中心;
    然后下面有个判断
  • if(Dep.target)
    主要是看Dep中target是否有值,target值存的是变量watcher实例,其实刚开始的时候,我没看懂这写法是怎么来的,不应该是new Dep后获取他的实例,然后设置target属性吗?
    后来早上查文档看到别的博主分享,才知道它是Dep的静态属性,只能通过Dep去修改值,实例化是改不了它的值的,这样也可以使得他是惟一

它的工作原理是这样的,我们在defineProperty的get事件被触发时会进行依赖收集(现在不明白依赖收集没关系),你会经常触发get事件,但我们现在指定——你如果想要拿到这块砖,只能从我手上取,而且我的手上经常是空的,当创建一个watcher时,就把这个watcher放到我的手上,然后告诉你,“嘿,可以拿了!”,这样你才能拿到,等你把依赖收集完了,我就把砖从手上扔掉,因此你虽然经常会触发get事件,但其实你什么都拿不到。

image.png

至于compiler的话,我想说下里面比较重要的一个方法,bindWatcherAndDep 和它中文意思差不多,就是绑定Dep与watcher的,其实就是在这里实例化watcher实例,绑定dep与watcher其实是在watcher这个类里面进行的,下面会讲

image.png

  • updateFn && updateFn(node, this.getDeepValue(exp))
    这也是第一次用vue.$data的内容去同步视图view中的信息,这不就是从model 到view的更新吗?这些更新函数可以被重复利用,这也是为什么选择把他们抽离出来的理由。第一次同步完成了,这时候vue.$data的信息就和view中的内容同步了。

接下来讲下watcher中是如何与dep联系起来的,先看代码

image.png

  • 主要是留意下141的代码
    this.value = this.getDeepValue();

这里不是去访问this.vm.$data的属性吗?这样不就是触发了属性的get方法了吗
当编译html代码时,我们碰到了一个需要收集的变量,现在为其创建一个watcher,并在watcher内部与dep建立联系。我们称这步为依赖收集,我们可以看到,在构造函数的最后一行,triggerDepCollection()意味这个watcher自己触发依赖收集,这个函数先把我们先前提到的Dep.target设为watcher自身,就是把自己作为一块砖头放在手上,然后getDeepValue()这里你只需要知道去访问了一次exp变量,这就触发了exp变量的get事件,就是提醒exp的dep,“你可以收集我了”,get事件的主要内容就是收集这个依赖,然后再结合最开始提到的代码,触发dep.depend(),收集依赖。

image.png

  • 说的比较乱,主要是想解释一下这几个东西的区别和作用,我们来总结下
    首先的话初始化的时候,递归vue中的变量数据,将它转为get,set。
  • get主要的作用是初始化该主题(属性)的一个调度中心dep,并往其中添加html上所有用到该的主题(属性)的依赖(watcher)
  • set 主要是去更新视图,当数据发生变化的时候,循环调用dep中的数组,去触发用到该主题(属性)的地方更新

至于什么时候收集到依赖,我个人理解是解析html文档的时候,遇到需要收集的变量,会在bindWatcherAndDep这里实例化一个watcher实例,在实例化的过程中,不是在构造函数上有this.triggerDepCollection()吗?triggerDepCollection()这个就会去执行获取一次data中的属性,就在这里调用了该属性的get方法,将依赖加到dep调度中心中。
小白见解,有说的不对的地方,请各位大佬海涵指点下我~

参考文章:

https://blog.csdn.net/swallowblank/article/details/107542882

前置:弟弟也是小白一个,看源码以小萌新角度分析可能适合一些跟我一样的小白去理解,有讲不对的请大佬多多海涵和指点

首先我觉得理解vue双向绑定原理应该要有略懂一下发布订阅者模式,我略带过一下。与观察者模式不同的是,发布订阅者多了一个中间调度中心而已。下面给两个比较好的例子

观察者模式:观察者(Observer)直接订阅(Subscribe)主题(Subject),而当主题被激活的时候,会触发(Fire Event)观察者里的事件(用网上比较好的例子,忘记作者链接了,如果打扰到您请联系我删了)。

1.png

2.png

大白话:
大概意思就是观察者(爸爸妈妈)订阅主题(宝宝的行为),一旦主题改变(宝宝发生了某个行为,比如说饿了),便会通知观察者里的事件(爸爸妈妈各自的行为去做某些事)。最常见就是你页面上的按钮事件,等你点击便会通知对应的方法。

发布订阅模式:订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Event Channel),当发布者(Publisher)发布该事件(Publish Event)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码(用网上比较好的例子,忘记作者链接了,如果打扰到您请联系我删了)。

3.png

4.png

大白话:

  1. 发布订阅者模式与观察者模式很像,但是区别的就是,缺少多个主题。
  2. 发布订阅者模式多了个调度中心,该调度中心主要收录不同的类型,比如说宝宝尿床了, 宝宝饿了
  3. 根据不同类型让不同订阅者去执行对应的方法,比如尿床了就让爸爸去洗裤子,饿了就让妈妈喂奶,vue就是用订阅发布模式实现的。

接下来就讲下vue的双向绑定原理,先喵一下这几个东西:

  1. observe
  2. watch
  3. Dep

observe: 在实例化时,先触发observe,递归地对所有data中的变量进行订阅,并且,每次订阅之前,都会生成一个dep实例。

dep(调度中心): 大白话解释就是一个容器,打比分你定义了一个data中定义了name属性,那就会有一个name的dep(调度中心), 主要作用就是存放watch实例,也就是你的html上用到name的地方的,{
{name}} v-modle:name 等等。

watch: 主要是用来更新模板的,但是值得注意的是每个变量引用的地方都会生成一个watch实例,{
{name}} v-modle:name 会生成两个, 这样当更新数据的时候dep会去循环调用watch实例的回调方法(更新html模板的方法)就行。

`D@J58N4IA@R{NAG}5(VJAD.jpg

看完这三个的作用后,我们看看是怎么关联起来去实现双向绑定的:

image.png

解析一下:observe 这个方法就是去递归data中的数据进行订阅,你可以看到在171行有个

  • let dep = new Dep();
    这个就是刚才所说的,每个属性都会添加一个dep调度中心;
    然后下面有个判断
  • if(Dep.target)
    主要是看Dep中target是否有值,target值存的是变量watcher实例,其实刚开始的时候,我没看懂这写法是怎么来的,不应该是new Dep后获取他的实例,然后设置target属性吗?
    后来早上查文档看到别的博主分享,才知道它是Dep的静态属性,只能通过Dep去修改值,实例化是改不了它的值的,这样也可以使得他是惟一

它的工作原理是这样的,我们在defineProperty的get事件被触发时会进行依赖收集(现在不明白依赖收集没关系),你会经常触发get事件,但我们现在指定——你如果想要拿到这块砖,只能从我手上取,而且我的手上经常是空的,当创建一个watcher时,就把这个watcher放到我的手上,然后告诉你,“嘿,可以拿了!”,这样你才能拿到,等你把依赖收集完了,我就把砖从手上扔掉,因此你虽然经常会触发get事件,但其实你什么都拿不到。

image.png

至于compiler的话,我想说下里面比较重要的一个方法,bindWatcherAndDep 和它中文意思差不多,就是绑定Dep与watcher的,其实就是在这里实例化watcher实例,绑定dep与watcher其实是在watcher这个类里面进行的,下面会讲

image.png

  • updateFn && updateFn(node, this.getDeepValue(exp))
    这也是第一次用vue.$data的内容去同步视图view中的信息,这不就是从model 到view的更新吗?这些更新函数可以被重复利用,这也是为什么选择把他们抽离出来的理由。第一次同步完成了,这时候vue.$data的信息就和view中的内容同步了。

接下来讲下watcher中是如何与dep联系起来的,先看代码

image.png

  • 主要是留意下141的代码
    this.value = this.getDeepValue();

这里不是去访问this.vm.$data的属性吗?这样不就是触发了属性的get方法了吗
当编译html代码时,我们碰到了一个需要收集的变量,现在为其创建一个watcher,并在watcher内部与dep建立联系。我们称这步为依赖收集,我们可以看到,在构造函数的最后一行,triggerDepCollection()意味这个watcher自己触发依赖收集,这个函数先把我们先前提到的Dep.target设为watcher自身,就是把自己作为一块砖头放在手上,然后getDeepValue()这里你只需要知道去访问了一次exp变量,这就触发了exp变量的get事件,就是提醒exp的dep,“你可以收集我了”,get事件的主要内容就是收集这个依赖,然后再结合最开始提到的代码,触发dep.depend(),收集依赖。

image.png

  • 说的比较乱,主要是想解释一下这几个东西的区别和作用,我们来总结下
    首先的话初始化的时候,递归vue中的变量数据,将它转为get,set。
  • get主要的作用是初始化该主题(属性)的一个调度中心dep,并往其中添加html上所有用到该的主题(属性)的依赖(watcher)
  • set 主要是去更新视图,当数据发生变化的时候,循环调用dep中的数组,去触发用到该主题(属性)的地方更新

至于什么时候收集到依赖,我个人理解是解析html文档的时候,遇到需要收集的变量,会在bindWatcherAndDep这里实例化一个watcher实例,在实例化的过程中,不是在构造函数上有this.triggerDepCollection()吗?triggerDepCollection()这个就会去执行获取一次data中的属性,就在这里调用了该属性的get方法,将依赖加到dep调度中心中。
小白见解,有说的不对的地方,请各位大佬海涵指点下我~

参考文章:

https://blog.csdn.net/swallowblank/article/details/107542882

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/180747.html原文链接:https://javaforall.net

(0)
上一篇 2022年10月18日 上午8:46
下一篇 2022年10月18日 上午8:46


相关推荐

  • Pycharm 输出中文或打印中文乱码现象的解决办法

    Pycharm 输出中文或打印中文乱码现象的解决办法使用 Pycharm 有时候会在 Console 终端输出乱码 比如下面这样 问题原因 这是什么原因呢 这是因为程序开始部分的编码不一致造成 比如说程序中使用 gbk 编码 coding gbk 但是 Pycharm 中确使用 utf 8 编码 并保存为 utf 8 的格式 解决办法 File setting FileEncoding ID

    2026年3月27日
    2
  • n8n飞书webhook配置(飞书机器人、飞书bot、feishu bot)Crypto节点、js timestamp代码、Crypto node

    n8n飞书webhook配置(飞书机器人、飞书bot、feishu bot)Crypto节点、js timestamp代码、Crypto node

    2026年3月16日
    3
  • 【STM32】STM32 CubeMx使用教程一–安装教程

    【STM32】STM32 CubeMx使用教程一–安装教程一、STM32CubeMX简介1、STM32CubeMX是ST意法半导体近几年来大力推荐的STM32芯片图形化配置工具,目的就是为了方便开发者,允许用户使用图形化向导生成C初始化代码,可以大大减轻开发工作,时间和费用,提高开发效率。STM32CubeMX几乎覆盖了STM32全系列芯片。在CubeMX上,通过傻瓜化的操作便能实现相关配置,最终能够生成C语言代码,支持…

    2022年4月28日
    54
  • 极限思想之芝诺悖论[通俗易懂]

    极限思想之芝诺悖论[通俗易懂]芝诺悖论是古希腊哲学家芝诺提出的一组悖论。芝诺是一个很有学问,同时也很好玩的人(淘气)。他如果在中国出生,估计很难大学毕业,只能跟池子(脱口秀演员~)一样,高中教室门外面站三年课,然后去讲脱口秀糊口。阿基里斯,大家都知道。古希腊神话中的战神。无论是力量,速度,耐力,格斗技巧,都是巅峰级别的。一夜睡三女,第二天依然可以血染特洛伊的男人。芝诺就提出:在跑步比赛中,如果跑得最慢的乌龟一开始领先…

    2022年6月18日
    39
  • python3.8安装scrapy_python没安装成功怎么办

    python3.8安装scrapy_python没安装成功怎么办直接安装scrapy各种报错,后来各种百度终于解决了,如下是亲身的经历。pipinstallscrapy这样直接会报错。第一步:先安装wheelpipinstallwheel第二步:安装twiste,事先下载好Twisted-17.9.0-cp36-cp36m-win32.whl,我用的是32位,切换到twisted路径下安装,这上有http://www.lfd.uci.edu/~g…

    2026年1月18日
    4
  • 使用AMD CPU实例部署千问Qwen-Audio-Chat

    使用AMD CPU实例部署千问Qwen-Audio-Chat

    2026年3月12日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号