Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[vue] 什么是双向绑定?原理是什么? #226

Open
undefinedYu opened this issue Jun 11, 2019 · 7 comments
Open

[vue] 什么是双向绑定?原理是什么? #226

undefinedYu opened this issue Jun 11, 2019 · 7 comments
Labels
vue vue

Comments

@undefinedYu
Copy link
Contributor

[vue] 什么是双向绑定?原理是什么?

@undefinedYu undefinedYu added the vue vue label Jun 11, 2019
@MachineDream
Copy link

双向数据绑定个人理解就是存在data→view,view→data两条数据流的模式。其实可以简单的理解为change和bind的结合。目前双向数据绑定都是基于Object.defineProperty()重新定义get和set方法实现的。修改触发set方法赋值,获取触发get方法取值,并通过数据劫持发布信息.

@yelingfeng
Copy link

通过Observer 把数据劫持(Object.defineProperty()) 、加入到订阅器(Dep) 订阅器收集订阅者(Watcher )、视图通过编译(Compile)、解析指令(Directive)等一些列操作收集给订阅者 、最后通过触发数据变化update 通知所有订阅者完成数据驱动

@flashyy
Copy link

flashyy commented Feb 23, 2022

1.单向绑定(v-bind):数据只能从data流向页面。
2.双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data。

我们已经知道实现数据的双向绑定,首先要对数据进行劫持监听,所以我们需要设置一个监听器Observer,用来监听所有属性。如果属性发上变化了,就需要告诉订阅者Watcher看是否需要更新。因为订阅者是有很多个,所以我们需要有一个消息订阅器Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进行统一管理的。接着,我们还需要有一个指令解析器Compile,对每个节点元素进行扫描和解析,将相关指令对应初始化成一个订阅者Watcher,并替换模板数据或者绑定相应的函数,此时当订阅者Watcher接收到相应属性的变化,就会执行对应的更新函数,从而更新视图。因此接下去我们执行以下3个步骤,实现数据的双向绑定:

1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。

2.实现一个订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图。

3.实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。
https://www.cnblogs.com/libin-1/p/6893712.html 这篇很清楚!

@yxllovewq
Copy link

1、data->view,view->data
2. data->view:数据劫持+发布订阅设计模式,view->data:dom事件绑定,触发修改数据
3. 数据劫持;在vue2.0使用Object.defineProperty重新定义get和set方法,订阅和发布也是分别在get和set上触发,vue3.0使用了Proxy实现。

@lv107w
Copy link

lv107w commented Aug 9, 2022

1.什么是双向绑定

所谓的双向绑定就是数据驱动,数据驱动是vue.js最大的特点,在vue中,用户界面发生的变化,开发者不需要手动的去修改DOM。

比如,我们点击一个button,需要元素的文本做一个“是/否”的切换操作,在传统jQuery中,对于页面修改的流程通常是:对button绑定事件,然后获取文案对应元素的dom对象,最后根据切换来修改dom对象的文本值。
2.Vue实现数据驱动(双向绑定)原理

Vue实现数据双向绑定主要采用数据劫持,配合发布者-订阅者模式我,通过Object.defineProperty()来劫持各个属性的setter和getter,在数据变动时发布消息给订阅者,触发相应监听回调

当一个普通JavaScript对象传给Vuie实例作为他的data选项时,Vue将遍历它的属性,用Object.defineProperty将它们转为getter/setter。用户看不到getter/setter,但是在内部它们让vue追踪依赖,在属性被访问和修改时通知变化

vue的数据双向绑定将MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己Model的数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 => 视图更新;视图交互变化 => 数据model变更 双向绑定的效果
3.模拟vue数据驱动,实现input:v-model双向绑定

       <title>Document</title>  
      {{num}}  
 <script>    //发布者    class Dep {      constructor() {        this.subs = []     }      //注册订阅      addSub(sub) {        this.subs.push(sub)     }      //发布通知      notify() {        this.subs.map(sub => {          sub.update()       })     }   } ​    //订阅者    class Watcher {      constructor(vm, node, name) {        this.name = name        this.node = node        this.vm = vm        Dep.target = this        this.update()        Dep.target = null     }


     //订阅者接口
     update() {
       this.node.nodeValue = this.vm[this.name]
       this.node.value = this.vm[this.name]
    }
  }

   class Vue {
     constructor({el, data}) {
       this.data = data
       observe(this.data, this)
       let ele = document.querySelector(el)
       let dom = nodeToFragement(ele, this)
       ele.appendChild(dom)
    }
  }

   const app = new Vue({
     el: '#app',
     data: {
       num: 1
    }
  })

   //把vm.data的属性直接挂载到vm上,并对属性值进行代理检测
   function observe(obj, vm) {
     Object.entries(obj).map(([key, val]) => {
       defineReactive(vm, key, val)
    })
  }

   //代理检测
   function defineReactive(obj, key, val) {
     let dep = new Dep()
     Object.defineProperty(obj, key, {
       get() {
         console.log('读取数据', val);
         //TODO添加订阅者
         if(Dep.target) {
           dep.addSub(Dep.target)
        }
         return val
      },
       set(newVal) {
         if(newVal === val) {
           return
        }
         val = newVal
         //TODO通知订阅者
         dep.notify()
         console.log('更新数据', val);
      }
    })
  }


   function nodeToFragement(node, vm) {
     let flag = document.createDocumentFragment()
     let child
     while(child = node.firstChild) {
       compile(child, vm)
       flag.append(child)
    }
     return flag
  }

   //处理模板,提取{{插值}} 创建观察者
   function compile(node, vm) {
     let reg = /{{(.*)}}/
     //nodeType === 1 => 元素类型
     if(node.nodeType === 1) {
       let attrs = node.attributes
       for(let i = 0, len = attrs.length; i < len; i++) {
         if(attrs[i].nodeName === 'v-model') {
           let name = attrs[i].nodeValue
           //TODO创建观察者,等待通知
           new Watcher(vm, node, name)
           node.addEventListener('input', e => {
             console.log('123');
             //触发setter,联动发布者发布通知
             vm[name] = e.target.value
          })
           node.removeAttribute('v-model')
        }
      }
    }

     //nodeType === 3 text类型
     if(node.nodeType === 3) {
       if(reg.test(node.nodeValue)) {
         let name = RegExp.$1
         name = name.trim()
         //TODO创建观察者
         new Watcher(vm, node, name)
         //触发getter,联动订阅者添加
         node.nodeValue = vm[name]
      }
    }
  }
 </script>

@sc950828
Copy link

sc950828 commented Sep 23, 2022

都在说响应式原理,这里问的是双向绑定!

在vue里面双向绑定就是v-model

默认使用input事件和value作为属性。当用在自定义组件上可以使用model修改。

@Cai-zhiji
Copy link

双向绑定的定义

双向绑定是一种数据绑定的机制,它将数据模型(通常是视图模型)与用户界面保持同步。当数据模型的值发生变化时,界面会自动更新;反之,当用户在界面上进行交互并修改了数据时,数据模型也会相应地进行更新。

双向绑定的工作原理

双向绑定的原理是通过在数据模型和用户界面之间建立一个中间层来实现。这个中间层通常被称为观察者(Observer)或监听器(Watcher)。在双向绑定中,观察者会同时监测数据模型和界面的变化,并在两者之间进行数据的同步。

具体流程

初始化:当界面加载时,观察者会将界面上的初始值与数据模型进行绑定。
数据变化:当数据模型的值发生变化时,观察者会捕捉到这个变化,并通知界面进行更新。
用户交互:当用户在界面上进行交互时,例如输入框输入文字,观察者会监听到这个变化,并将变化的值更新到数据模型中。
数据同步:观察者会在数据模型和界面之间进行数据的双向同步,保证两者的值始终保持一致。

技术

数据劫持(Object.defineProperty)和事件监听
数据劫持用于监听数据模型的变化,当数据发生变化时触发相应的回调函数;事件监听用于监听用户界面上的交互事件,例如输入框的输入事件,当用户输入时触发相应的回调函数。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
vue vue
Projects
None yet
Development

No branches or pull requests

8 participants