vue双向数据绑定

什么是双向数据绑定?

Vue 是一个 MVVM 框架,数据绑定简单来说,就是当数据发生变化时,相应的视图会进行更新,当视图更新时,数据也会跟着变化。

Vue.js 则是通过数据劫持以及结合发布者-订阅者来实现的,数据劫持是利用 ES5 的 Object.defineProperty(obj, key, val)来劫持各个属性的的 setter 以及 getter,在数据变动时发布消息给订阅者,从而触发相应的回调来更新视图。

1.实现最基础的数据绑定

 <div id="app">
        <input type="text" v-model="inp">
        输入的值为:{{inp}}
        <div>
            <input type="text" v-model="inp">
        </div>
    </div>
    <script>
        var vm = new MVue({
            el: '#app',
            data: {
                inp: 'hello world'
            }
        })
    </script>

实现思路:

1、输入框以及文本节点和 data 中的数据进行绑定

2、输入框内容变化时,data 中的对应数据同步变化,即 view => model

3、data 中数据变化时,对应的文本节点内容同步变化 即 model => view

双向数据绑定原理图
vue.png

2、实现 Compile

compile 主要做的事情是解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图,如图所示:

vue2.png

function compile(node, vm) {
  let reg = /\{\{(.*)\}\}/;
  // 元素节点
  if (node.nodeType === 1) {
    var attrs = node.attributes;
    for (let attr of attrs) {
      if (attr.nodeName === 'v-model') {
        // 获取v-model指令绑定的data属性
        var name = attr.nodeValue;
        // 绑定事件
        node.addEventListener('input', function(e) {
          vm.$data[name] = e.target.value;
        });
        // 初始化数据绑定
        node.value = vm.$data[name];
        // 移除v-model 属性
        node.removeAttribute('v-model');
      }
    }
  }

  // 文本节点
  if (node.nodeType === 3) {
    if (reg.test(node.nodeValue)) {
      var name = RegExp.$1 && RegExp.$1.trim();
      // 绑定数据到文本节点中
      node.nodeValue = node.nodeValue.replace(
        new RegExp('\\{\\{\\s*(' + name + ')\\s*\\}\\}'),
        vm.$data[name]
      );
    }
  }
}

修改下 MVue 构造函数,增加模板编译:

function MVue(options) {
  this.$el = options.el;
  this.$data = options.data;

  // 模板编译
  let elem = document.querySelector(this.$el);
  elem.appendChild(nodeToFragment(elem, this));
}

3.实现 watcher

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() {
    console.log(1);
    this.value = this.vm[this.name]; //触发相应属性的get
  }
};

4.实现 Dep 来为每个属性添加订阅者

function Dep() {
  this.subs = [];
}
Dep.prototype = {
  addSub: function(sub) {
    this.subs.push(sub);
  },
  notify: function() {
    this.subs.forEach(function(sub) {
      sub.update();
    });
  }
};
10 声望
1 粉丝
0 条评论
推荐阅读
内置对象string的方法
在js中,String和Array是同级的,都是js中的内置对象。因此String也像Array那样有很多操作的方法。注意:String对象的涵盖范围,它包含所有的字符串。1. 字符串对象的属性length(1) 表示字符串的长度。(就是这个...

王影阅读 901

ESlint + Stylelint + VSCode自动格式化代码(2023)
安装插件 ESLint,然后 File -&gt; Preference-&gt; Settings(如果装了中文插件包应该是 文件 -&gt; 选项 -&gt; 设置),搜索 eslint,点击 Edit in setting.json

谭光志34阅读 20.7k评论 9

vue UI框架比较
最好基于vue2.0PC端:因为用过的是饿了么UI,所以比较以饿了么UI为基础element UI 饿了么UI支持vue2.x80分优点:组件的API方法、属性等封装的较为完善缺点:样式有些生硬,不够炫酷美观N3 N3支持vue2.x70分优点:...

chinawzc22阅读 39.8k评论 17

【已结束】SegmentFault 思否写作挑战赛!
SegmentFault 思否写作挑战赛 是思否社区新上线的系列社区活动在 2 月 8 日 正式面向社区所有用户开启;挑战赛中包含多个可供作者选择的热门技术方向,根据挑战难度分为多个等级,快来参与挑战,向更好的自己前进!

SegmentFault思否20阅读 5.6k评论 10

封面图
Vue2 导出excel
2020-07-15更新 excel导出安装 {代码...} src文件夹下新建一个libs文件夹,新建一个excel.js {代码...} vue页面中使用 {代码...} ===========================以下为早期的文章今天在开发的过程中需要做一个Vue的...

原谅我一生不羁放歌搞文艺14阅读 20k评论 9

用了那么久的 SVG,你还没有入门吗?
其实在大部分的项目中都有 直接 或 间接 使用到 SVG 和 Canvas,但是在大多数时候我们只是选择 简单了解 或 直接跳过,这有问题吗?没有问题,毕竟砖还是要搬的!

熊的猫17阅读 1.6k评论 2

封面图
嘿,vue中keep-alive有个「大坑」你可能还不知道
背景是这样的,我们使用vue2开发一个在线客服使用的IM应用,基本布局是左边是访客列表,右边是访客对话,为了让对话加载更友好,我们将对话的路由使用&lt;keep-alive&gt;缓存起来。但是如果将所有对话都缓存,未...

wuwhs12阅读 2.6k

封面图
10 声望
1 粉丝
宣传栏