广告
返回顶部
首页 > 资讯 > 前端开发 > node.js >Vue2.0怎么实现双向绑定
  • 964
分享到

Vue2.0怎么实现双向绑定

2024-04-02 19:04:59 964人浏览 泡泡鱼
摘要

这篇文章主要介绍了Vue2.0怎么实现双向绑定,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、实现双向绑定的做法前端MVVM最令人激动的就

这篇文章主要介绍了Vue2.0怎么实现双向绑定,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

一、实现双向绑定的做法

前端MVVM最令人激动的就是双向绑定机制了,实现双向数据绑定的做法大致有如下三种:

1.发布者-订阅者模式(backbone.js)

思路:使用自定义的data属性在html代码中指明绑定。所有绑定起来的javascript对象以及DOM元素都将“订阅”一个发布者对象。任何时候如果JavaScript对象或者一个HTML输入字段被侦测到发生了变化,我们将代理事件到发布者-订阅者模式,这会反过来将变化广播并传播到所有绑定的对象和元素。

2.脏值检查(angular.js)

思路:angular.js 是通过脏值检测的方式比对数据是否有变更,来决定是否更新视图,最简单的方式就是通过 setInterval() 定时轮询检测数据变动,angular只有在指定的事件触发时进入脏值检测,大致如下:

  • DOM事件,譬如用户输入文本,点击按钮等。( ng-click )

  • XHR响应事件 ( $Http )

  • 浏览器Location变更事件 ( $location )

  • Timer事件( $timeout , $interval )

  • 执行 $digest() 或 $apply()

3.数据劫持(Vue.js)

思路: vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

由此可见,Object.defineProperty() 这个api是Vue实现双向数据绑定的关键,我们先简单了解下这个API,了解更多戳这里

二、Object.defineProperty()

简单例子:

  var obj = {};
  Object.defineProperty(obj, 'hello', {
    get: function() {
      console.log('get val:'+ val);
      return val;
     },
    set: function(newVal) {
      val = newVal;
      console.log('set val:'+ val);
    }
  });
  obj.hello;
  obj.hello='111';

结果:

Vue2.0怎么实现双向绑定

如果去掉 obj.hello=‘111' 这行代码,则get的返回值val会报错val is not defined。可见Object.defineProperty() 监控对数据的操作,可以自动触发数据同步。下面我们先用Object.defineProperty()来实现一个非常简单的双向绑定。

三、实现简单的双向绑定

 最简单例子:

<!DOCTYPE html>
 <head></head>
 <body>
 <div id="app">
  <input type="text" id="a">
  <span id="b"></span>
 </div>

 <script type="text/javascript">
  var obj = {};
  Object.defineProperty(obj, 'hello', {
    get: function() {
      console.log('get val:'+ val);
      return val;
    },
    set: function(newVal) {
      val = newVal;
      console.log('set val:'+ val);
      document.getElementById('a').value = val;
      document.getElementById('b').innerHTML = val;
    }
  });
  document.addEventListener('keyup', function(e) {
   obj.hello = e.target.value;
  });
  </script>
 </body>
</html>

实现效果如下:

Vue2.0怎么实现双向绑定

上面例子直接用了dom操作改变了文本节点的值,而且是在我们知道是哪个id的情况下,通过document.getElementById 获取到相应的文本节点,然后直接修改文本节点的值,这种做法是最简单粗暴的。

封装成一个框架,肯定不能是这种做法,所以我们需要一个解析dom,并能修改dom中相应的变量的模块。

四、实现简单Compile

首先我们需要获取文本中真实的dom节点,然后再分析节点的类型,根据节点类型做相应的处理。

在上面例子我们多次操作了dom节点,为提高性能和效率,会先将所有的节点转换城文档碎片fragment进行编译操作,解析操作完成后,再将fragment添加到原来的真实dom节点中。

<!DOCTYPE html>
 <head></head>
 <body>
 <div id="app">
  <input type="text" id="a" v-model="text">
  {{text}}
 </div>
 <script type="text/javascript">
  function Compile(node, vm) {
   if(node) {this.$frag = this.nodeToFragment(node, vm);
    return this.$frag;
   }
  }
  Compile.prototype = {
   nodeToFragment: function(node, vm) {
    var self = this;
    var frag = document.createDocumentFragment();
    var child;

    while(child = node.firstChild) {
     self.compileElement(child, vm);
     frag.append(child); // 将所有子节点添加到fragment中,child是指向元素首个子节点的引用。将child引用指向的对象append到父对象的末尾,原来child引用的对象就跳到了frag对象的末尾,而child就指向了本来是排在第二个的元素对象。如此循环下去,链接就逐个往后跳了
    }
    return frag;
   },
   compileElement: function(node, vm) {
    var reg = /\{\{(.*)\}\}/;

    //节点类型为元素
    if(node.nodeType === 1) {
     var attr = node.attributes;
     // 解析属性
     for(var i = 0; i < attr.length; i++ ) {
      if(attr[i].nodeName == 'v-model') {
       var name = attr[i].nodeValue; // 获取v-model绑定的属性名
       node.addEventListener('input', function(e) {
        // 给相应的data属性赋值,进而触发该属性的set方法
         vm.data[name]= e.target.value;
       });
       node.value = vm.data[name]; // 将data的值赋给该node
       node.removeAttribute('v-model');
      }
     };
    }
    //节点类型为textif(node.nodeType === 3) {
     if(reg.test(node.nodeValue)) {
      var name = RegExp.$1; // 获取匹配到的字符串
      name = name.trim();
      node.nodeValue = vm.data[name]; // 将data的值赋给该node
     }
    }
   },
  }
   function Vue(options) {
   this.data = options.data;
   var data = this.data;
   var id = options.el;
   var dom =new Compile(document.getElementById(id),this);
   // 编译完成后,将dom返回到app中
   document.getElementById(id).appendChild(dom);
  }
  var vm = new Vue({
   el: 'app',
   data: {
    text: 'hello world'
   }
  });
 </script>
 </body>
</html>

结果:

Vue2.0怎么实现双向绑定

到这,我们做到了获取文本中真实的dom节点,然后分析节点的类型,并能处理节点中相应的变量如上面代码中的{{text}},最后渲染到页面中。接着我们需要和双向绑定联系起来,实现{{text}}响应式的数据绑定。

五、实现简单observe

简单的observe定义如下:

Vue2.0怎么实现双向绑定

需要监控data的属性值,这个对象的某个值赋值,就会触发setter,这样就能监听到数据变化。然后注意vm.data[name]属性将改为vm[name]

Vue2.0怎么实现双向绑定

完整代码如下:

<!DOCTYPE html>
 <head></head>
 <body>
 <div id="app">
  <input type="text" id="a" v-model="text">
  {{text}}
 </div>
<script type="text/javascript">
  function Compile(node, vm) {
   if(node) {
    this.$frag = this.nodeToFragment(node, vm);
    return this.$frag;
   }
  }
  Compile.prototype = {
   nodeToFragment: function(node, vm) {
    var self = this;
    var frag = document.createDocumentFragment();
    var child;

    while(child = node.firstChild) {
     self.compileElement(child, vm);
     frag.append(child); // 将所有子节点添加到fragment中
    }
    return frag;
   },
   compileElement: function(node, vm) {
    var reg = /\{\{(.*)\}\}/;

    //节点类型为元素
    if(node.nodeType === 1) {
     var attr = node.attributes;
     // 解析属性
     for(var i = 0; i < attr.length; i++ ) {
      if(attr[i].nodeName == 'v-model') {
       var name = attr[i].nodeValue; // 获取v-model绑定的属性名
       node.addEventListener('input', function(e) {
        // 给相应的data属性赋值,进而触发该属性的set方法
         vm[name]= e.target.value;
       });
       node.value = vm[name]; // 将data的值赋给该node
       node.removeAttribute('v-model');
      }
     };
    }
    //节点类型为text
    if(node.nodeType === 3) {
     if(reg.test(node.nodeValue)) {
      var name = RegExp.$1; // 获取匹配到的字符串
      name = name.trim();
      node.nodeValue = vm[name]; // 将data的值赋给该node
      // new Watcher(vm, node, name);
     }
    }
   },
  }
  function defineReactive (obj, key, val) {
   Object.defineProperty(obj, key, {
    get: function() {
     return val;
    },
    set: function (newVal) {
     if(newVal === val) return;
     val = newVal;
     console.log(val);
    }
   })
  }
  function observe(obj, vm) {
   Object.keys(obj).forEach(function(key) {
    defineReactive(vm, key, obj[key]);
   })
  }
   function Vue(options) {
   this.data = options.data;
   var data = this.data;
   observe(data, this);
   var id = options.el;
   var dom =new Compile(document.getElementById(id),this);
   // 编译完成后,将dom返回到app中
   document.getElementById(id).appendChild(dom);
  }
  var vm = new Vue({
   el: 'app',
   data: {
    text: 'hello world'
   }
  });
 </script>
 </body>
</html>

结果:

Vue2.0怎么实现双向绑定

到这,虽然set方法触发了,但是文本节点{{text}}的内容没有变化,要让绑定的文本节点同步变化,我们需要引入订阅发布模式。

六、订阅发布模式

订阅发布模式(又称观察者模式)定义了一种一对多的关系,让多个观察者同时监听某一个主题对象,这个主题对象的状态发生改变时就会通知所有观察者对象。

发布者发出通知 => 主题对象收到通知并推送给订阅者 => 订阅者执行相应操作

首先我们要一个收集订阅者的容器,定义一个Dep作为主题对象

Vue2.0怎么实现双向绑定

然后定义订阅者Watcher

Vue2.0怎么实现双向绑定

添加订阅者Watcher到主题对象Dep,发布者发出通知放到属性监听里面

Vue2.0怎么实现双向绑定

最后需要订阅的地方

Vue2.0怎么实现双向绑定

至此,比较简单地实现了我们第三步用dom操作实现的双向绑定效果,代码:

<!DOCTYPE html>
 <head></head>
 <body>
 <div id="app">
  <input type="text" id="a" v-model="text">
  {{text}}
 </div>
 <script type="text/javascript">
  function Compile(node, vm) {
   if(node) {
    this.$frag = this.nodeToFragment(node, vm);
    return this.$frag;
   }
  }
  Compile.prototype = {
   nodeToFragment: function(node, vm) {
    var self = this;
    var frag = document.createDocumentFragment();
    var child;

    while(child = node.firstChild) {
     self.compileElement(child, vm);
     frag.append(child); // 将所有子节点添加到fragment中
    }
    return frag;
   },
   compileElement: function(node, vm) {
    var reg = /\{\{(.*)\}\}/;

    //节点类型为元素
    if(node.nodeType === 1) {
     var attr = node.attributes;
     // 解析属性
     for(var i = 0; i < attr.length; i++ ) {
      if(attr[i].nodeName == 'v-model') {
       var name = attr[i].nodeValue; // 获取v-model绑定的属性名
       node.addEventListener('input', function(e) {
        // 给相应的data属性赋值,进而触发该属性的set方法
         vm[name]= e.target.value;
       });
       // node.value = vm[name]; // 将data的值赋给该node
       new Watcher(vm, node, name, 'value');
      }
     };
    }
    //节点类型为text
    if(node.nodeType === 3) {
     if(reg.test(node.nodeValue)) {
      var name = RegExp.$1; // 获取匹配到的字符串
      name = name.trim();
      // node.nodeValue = vm[name]; // 将data的值赋给该node
      new Watcher(vm, node, name, 'nodeValue');
     }
    }
   },
  }
  function Dep() {
   this.subs = [];
  }
  Dep.prototype = {
   addSub: function(sub) {
    this.subs.push(sub);
   },
   notify: function() {
    this.subs.forEach(function(sub) {
     sub.update();
    })
   }
  }
  function Watcher(vm, node, name, type) {
   Dep.target = this;
   this.name = name;
   this.node = node;
   this.vm = vm;
   this.type = type;
   this.update();
   Dep.target = null;
  }

  Watcher.prototype = {
   update: function() {
    this.get();
    this.node[this.type] = this.value; // 订阅者执行相应操作
   },
   // 获取data的属性值
   get: function() {
    this.value = this.vm[this.name]; //触发相应属性的get
   }
  }
  function defineReactive (obj, key, val) {
   var dep = new Dep();
   Object.defineProperty(obj, key, {
    get: function() {
      //添加订阅者watcher到主题对象Dep
     if(Dep.target) {
      // JS的浏览器单线程特性,保证这个全局变量在同一时间内,只会有同一个监听器使用
      dep.addSub(Dep.target);
     }
     return val;
    },
    set: function (newVal) {
     if(newVal === val) return;
     val = newVal;
     console.log(val);
     // 作为发布者发出通知
     dep.notify();
    }
   })
  }
  function observe(obj, vm) {
   Object.keys(obj).forEach(function(key) {
    defineReactive(vm, key, obj[key]);
   })
  }

   function Vue(options) {
   this.data = options.data;
   var data = this.data;
   observe(data, this);
   var id = options.el;
   var dom =new Compile(document.getElementById(id),this);
   // 编译完成后,将dom返回到app中
   document.getElementById(id).appendChild(dom);
  }
  var vm = new Vue({
   el: 'app',
   data: {
    text: 'hello world'
   }
  });
 </script>
 </body>
</html>

七、总结

关于双向绑定的实现,看了网上很多资料,开始看到是对Vue源码的解析,看的过程似懂非懂。后来找到参考资料1,然后自己跟着实现一遍,才理解许多。感谢这篇文章的作者,写的由浅入深,比较好理解。为了加深自己的理解,于是自己顺着这个思路写下这个笔记。本文主要了解了几种双向绑定的做法,然后先用原生JS,dom操作实现一个最简单双向绑定,在这个基础上进行改装,为减少dom操作,实现简单的Compile(编译HTML);接着为了实现数据监听,实现observe;最后为了实现数据的双向绑定实现订阅发布模式。

虽然实现的比较简单,有很多功能没有考虑,不过这个过程还是可以理解到Vue实现双向绑定的原理。过程中,有思考:

1. Vue的源代码中,用了文档碎片fragment作为真实节点的存储吗?

之前有听说用VDOM,在Vue源代码中,也找过是否有创建文档碎片,结果没找到。看了参考资料4中,VDOM的介绍,好像是把节点用JS对象模拟。类似:

模板

<ul id='list'>
 <li class='item'>Item 1</li>
 <li class='item'>Item 2</li>
 <li class='item'>Item 3</li>
</ul>

js对象

var element = {
 tagName: 'ul', // 节点标签名
 props: { // DOM的属性,用一个对象存储键值对
  id: 'list'
 },
 children: [ // 该节点的子节点
  {tagName: 'li', props: {class: 'item'}, children: ["Item 1"]},
  {tagName: 'li', props: {class: 'item'}, children: ["Item 2"]},
  {tagName: 'li', props: {class: 'item'}, children: ["Item 3"]},
 ]
}

感谢你能够认真阅读完这篇文章,希望小编分享的“Vue2.0怎么实现双向绑定”这篇文章对大家有帮助,同时也希望大家多多支持编程网,关注编程网node.js频道,更多相关知识等着你来学习!

--结束END--

本文标题: Vue2.0怎么实现双向绑定

本文链接: https://www.lsjlt.com/news/71057.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Vue2.0怎么实现双向绑定
    这篇文章主要介绍了Vue2.0怎么实现双向绑定,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、实现双向绑定的做法前端MVVM最令人激动的就...
    99+
    2022-10-19
  • Vue2.0中怎么实现数据的双向绑定
    这篇文章给大家介绍Vue2.0中怎么实现数据的双向绑定,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。实现组件双向数据绑定在上一节中最后的示例使用的是Vue 1.0版本中的 .sync ...
    99+
    2022-10-19
  • Vue2.0/3.0双向数据绑定的实现原理是什么
    这篇文章给大家分享的是有关Vue2.0/3.0双向数据绑定的实现原理是什么的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。vue是什么Vue是一套用于构建用户界面的渐进式JavaScript框架,Vue与其它大型框...
    99+
    2023-06-14
  • Vue2.0/3.0双向数据绑定的实现原理详解
    Vue2.0/3.0 双向数据绑定的实现原理 双向数据绑定简意 即数据的改变能让页面重新渲染 Vue2.0 ES5的原理: Object.defineProperty 对数据进行拦...
    99+
    2022-11-12
  • wpf双向绑定怎么实现
    WPF双向绑定可以通过以下步骤实现:1. 首先,在XAML中,将需要进行双向绑定的控件的`Mode`属性设置为`TwoWay`,例如...
    99+
    2023-09-06
    wpf
  • vue2.0双向数据绑定的方法是什么
    这篇文章主要介绍“vue2.0双向数据绑定的方法是什么”,在日常操作中,相信很多人在vue2.0双向数据绑定的方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”vue2.0双向数据绑定的方法是什么”的疑...
    99+
    2023-06-27
  • 利用js实现Vue2.0中数据的双向绑定功能
    Object.defineProperty了解 语法: Object.defineProperty(obj, prop, descriptor) obj  ...
    99+
    2022-11-12
  • 如何用js实现Vue2.0中数据的双向绑定功能
    这篇文章主要介绍了如何用js实现Vue2.0中数据的双向绑定功能的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇如何用js实现Vue2.0中数据的双向绑定功能文章都会有所收获,下...
    99+
    2022-10-19
  • react表单双向绑定怎么实现
    React中实现表单双向绑定可以通过以下步骤:1. 使用`useState`钩子或者类组件的`state`来维护表单数据的状态。2....
    99+
    2023-09-13
    react
  • MVVMLight怎么实现双向数据绑定
    这篇文章主要介绍“MVVMLight怎么实现双向数据绑定”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“MVVMLight怎么实现双向数据绑定”文章能帮助大家解决问题。第一步:先写一个Model,里面...
    99+
    2023-06-29
  • vue双向数据绑定怎么实现
    Vue的双向数据绑定是通过v-model指令来实现的。1. v-model是Vue提供的一个指令,用于在表单元素上实现双向数据绑定。...
    99+
    2023-08-09
    vue
  • Vue 3.0 中怎么实现双向绑定
    本篇文章为大家展示了Vue 3.0 中怎么实现双向绑定,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。双向绑定由两个单向绑定组成:模型 &mdash;>...
    99+
    2022-10-19
  • angular双向数据绑定怎么实现
    Angular双向数据绑定可以通过以下步骤来实现:1. 在HTML模板中使用双大括号({{}})将数据绑定到HTML元素上。例如:{...
    99+
    2023-09-21
    angular
  • vue 数据双向绑定怎么实现
    这篇文章给大家分享的是有关vue 数据双向绑定怎么实现的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1. 前言实现简易版的数据双向绑定2. 代码实现2.1 目的分析本文要实现的效果如下图所示:本文用到的HTML和...
    99+
    2023-06-06
  • 如何利用js实现Vue2.0中数据的双向绑定功能
    本篇内容主要讲解“如何利用js实现Vue2.0中数据的双向绑定功能”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何利用js实现Vue2.0中数据的双向绑定功能”吧!Object.defineP...
    99+
    2023-06-20
  • Vue中怎么实现数据双向绑定
    这篇文章主要介绍了Vue中怎么实现数据双向绑定的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Vue中怎么实现数据双向绑定文章都会有所收获,下面我们一起来看看吧。在我们使用vue的时候,当数据发生了改变,界面也会...
    99+
    2023-07-04
  • vue.js中怎么实现双向绑定操作
    这期内容当中小编将会给大家带来有关vue.js中怎么实现双向绑定操作,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。首先在页面引入vue.js以及其他需要用到的或者可能要用...
    99+
    2022-10-19
  • Vue 中怎么实现数据双向绑定
    本篇文章给大家分享的是有关 Vue 中怎么实现数据双向绑定,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。MVVM 架构的优点低耦合。视图(Vi...
    99+
    2022-10-19
  • vue中双向数据绑定怎么实现
    vue中双向数据绑定是通过数据劫持结合发布订阅模式的方式来实现的,其核心方法是Object.defineProperty()方法。实现双向数据绑定的示例:<!DOCTYPE html><html><h...
    99+
    2022-10-11
  • proxy怎么实现数据的双向绑定
    本篇内容介绍了“proxy怎么实现数据的双向绑定”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!写在前面随着 vue3.x 的消息越来越多,p...
    99+
    2023-06-03
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作