iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >Vue2.x 的双向绑定原理及实现
  • 341
分享到

Vue2.x 的双向绑定原理及实现

2024-04-02 19:04:59 341人浏览 八月长安
摘要

目录1、实现过程2、显示一个 Observer3、实现 Watcher4、实现 Compile5、添加解析事件6、完整版 myVueVue 是利用的 Object.definePro

Vue 是利用的 Object.defineProperty() 方法进行的数据劫持,利用 set、get 来检测数据的读写。

https://jsrun.net/RMIKp/embedded/all/light

MVVM 框架主要包含两个方面,数据变化更新视图,视图变化更新数据。

视图变化更新数据,如果是像 input 这种标签,可以使用 oninput 事件..

数据变化更新视图可以使用 Object.definProperty() set 方法可以检测数据变化,当数据改变就会触发这个函数,然后更新视图。

1、实现过程

我们知道了如何实现双向绑定了,首先要对数据进行劫持监听,所以我们需要设置一个 Observer 函数,用来监听所有属性的变化。

如果属性发生了变化,那就要告诉订阅者 watcher 看是否需要更新数据,如果订阅者有多个,则需要一个 Dep 来收集这些订阅者,然后在监听器 observer watcher 之间进行统一管理。

还需要一个指令解析器 compile,对需要监听的节点和属性进行扫描和解析。

因此,流程大概是这样的:

  • 实现一个监听器 Observer,用来劫持并监听所有属性,如果发生变动,则通知订阅者。
  • 实现一个订阅者 Watcher,当接到属性变化的通知时,执行对应的函数,然后更新视图,使用 Dep 来收集这些 Watcher
  • 实现一个解析器 Compile,用于扫描和解析的节点的相关指令,并根据初始化模板以及初始化相应的订阅器。

2、显示一个 Observer

Observer 是一个数据监听器,核心方法是利用 Object.defineProperty() 通过递归的方式对所有属性都添加 settergetter 方法进行监听。


var library = {
  book1: {
    name: "",
  },
  book2: "",
};
observe(library);
library.book1.name = "vue权威指南"; // 属性name已经被监听了,现在值为:“vue权威指南”
library.book2 = "没有此书籍"; // 属性book2已经被监听了,现在值为:“没有此书籍”

// 为数据添加检测
function defineReactive(data, key, val) {
  observe(val); // 递归遍历所有子属性
  let dep = new Dep(); // 新建一个dep
  Object.defineProperty(data, key, {
    enumerable: true,
    configurable: true,
    get: function() {
      if (Dep.target) {
        // 判断是否需要添加订阅者,仅第一次需要添加,之后就不用了,详细看Watcher函数
        dep.addSub(Dep.target); // 添加一个订阅者
      }
      return val;
    },
    set: function(newVal) {
      if (val == newVal) return; // 如果值未发生改变就return
      val = newVal;
      console.log(
        "属性" + key + "已经被监听了,现在值为:“" + newVal.toString() + "”"
      );
      dep.notify(); // 如果数据发生变化,就通知所有的订阅者。
    },
  });
}

// 监听对象的所有属性
function observe(data) {
  if (!data || typeof data !== "object") {
    return; // 如果不是对象就return
  }
  Object.keys(data).forEach(function(key) {
    defineReactive(data, key, data[key]);
  });
}
// Dep 负责收集订阅者,当属性发生变化时,触发更新函数。
function Dep() {
  this.subs = {};
}
Dep.prototype = {
  addSub: function(sub) {
    this.subs.push(sub);
  },
  notify: function() {
    this.subs.forEach((sub) => sub.update());
  },
};

思路分析中,需要有一个可以容纳订阅者消息订阅器 Dep,用于收集订阅者,在属性发生变化时执行对应的更新函数。

从代码上看,将订阅器 Dep 添加在 getter 里,是为了让 Watcher 初始化时触发,,因此,需要判断是否需要订阅者。

setter 中,如果有数据发生变化,则通知所有的订阅者,然后订阅者就会更新对应的函数。

到此为止,一个比较完整的 Observer 就完成了,接下来开始设计 Watcher.

3、实现 Watcher

订阅者 Watcher 需要在初始化的时候将自己添加到订阅器 Dep 中,我们已经知道监听器 Observer 是在 get 时执行的 Watcher 操作,所以只需要在 Watcher 初始化的时候触发对应的 get 函数去添加对应的订阅者操作即可。

那给如何触发 get 呢?因为我们已经设置了 Object.defineProperty() , 所以只需要获取对应的属性值就可以触发了。

我们只需要在订阅者 Watcher 初始化的时候,在 Dep.target 上缓存下订阅者,添加成功之后在将其去掉就可以了。


function Watcher(vm, exp, cb) {
  this.cb = cb;
  this.vm = vm;
  this.exp = exp;
  this.value = this.get(); // 将自己添加到订阅器的操作
}

Watcher.prototype = {
  update: function() {
    this.run();
  },
  run: function() {
    var value = this.vm.data[this.exp];
    var oldVal = this.value;
    if (value !== oldVal) {
      this.value = value;
      this.cb.call(this.vm, value, oldVal);
    }
  },
  get: function() {
    Dep.target = this; // 缓存自己,用于判断是否添加watcher。
    var value = this.vm.data[this.exp]; // 强制执行监听器里的get函数
    Dep.target = null; // 释放自己
    return value;
  },
};

到此为止, 简单的额 Watcher 设计完毕,然后将 Observer Watcher 关联起来,就可以实现一个简单的的双向绑定了。

因为还没有设计解析器 Compile,所以可以先将模板数据写死。

将代码转化为 es6 构造函数的写法,预览试试。

Https://jsrun.net/8SIKp/embed...

这段代码因为没有实现编译器而是直接传入了所绑定的变量,我们只在一个节点上设置一个数据(name)进行绑定,然后在页面上进行 new MyVue,就可以实现双向绑定了。

并两秒后进行值得改变,可以看到,页面也发生了变化。


// MyVue
proxyKeys(key) {
    var self = this;
    Object.defineProperty(this, key, {
        enumerable: false,
        configurable: true,
        get: function proxyGetter() {
            return self.data[key];
        },
        set: function proxySetter(newVal) {
            self.data[key] = newVal;
        }
    });
}

上面这段代码的作用是将 this.data 的 key 代理到 this 上,使得我可以方便的使用 this.xx 就可以取到 this.data.xx

4、实现 Compile

虽然上面实现了双向数据绑定,但是整个过程都没有解析 DOM 节店,而是固定替换的,所以接下来要实现一个解析器来做数据的解析和绑定工作。

解析器 compile 的实现步骤:

  • 解析模板指令,并替换模板数据,初始化视图。
  • 将模板指定对应的节点绑定对应的更新函数,初始化相应的订阅器。

为了解析模板,首先需要解析 DOM 数据,然后对含有 DOM 元素上的对应指令进行处理,因此整个 DOM 操作较为频繁,可以新建一个 fragment 片段,将需要的解析的 DOM 存入 fragment 片段中在进行处理。


function nodeToFragment(el) {
  var fragment = document.createDocumentFragment();
  var child = el.firstChild;
  while (child) {
    // 将Dom元素移入fragment中
    fragment.appendChild(child);
    child = el.firstChild;
  }
  return fragment;
}

接下来需要遍历各个节点,对含有相关指令和模板语法的节点进行特殊处理,先进行最简单模板语法处理,使用正则解析“{{变量}}”这种形式的语法。


function compileElement (el) {
    var childNodes = el.childNodes;
    var self = this;
    [].slice.call(childNodes).forEach(function(node) {
        var reg = /\{\{(.*)\}\}/; // 匹配{{xx}}
        var text = node.textContent;
        if (self.isTextNode(node) && reg.test(text)) {  // 判断是否是符合这种形式{{}}的指令
            self.compileText(node, reg.exec(text)[1]);
        }
        if (node.childNodes && node.childNodes.length) {
            self.compileElement(node);  // 继续递归遍历子节点
        }
    });
},
function compileText (node, exp) {
    var self = this;
    var initText = this.vm[exp];
    updateText(node, initText);  // 将初始化的数据初始化到视图中
    new Watcher(this.vm, exp, function (value) {  // 生成订阅器并绑定更新函数
        self.updateText(node, value);
    });
},
function updateText (node, value) {
    node.textContent = typeof value == 'undefined' ? '' : value;
}

获取到最外层的节点后,调用 compileElement 函数,对所有的子节点进行判断,如果节点是文本节点切匹配{{}}这种形式的指令,则进行编译处理,初始化对应的参数。

然后需要对当前参数生成一个对应的更新函数订阅器,在数据发生变化时更新对应的 DOM。

这样就完成了解析、初始化、编译三个过程了。

接下来改造一个 myVue 就可以使用模板变量进行双向数据绑定了。

https://jsrun.net/K4IKp/embed...

5、添加解析事件

添加完 compile 之后,一个数据双向绑定就基本完成了,接下来就是在 Compile 中添加更多指令的解析编译,比如 v-modelv-onv-bind 等。

添加一个 v-model 和 v-on 解析:


function compile(node) {
  var nodeAttrs = node.attributes;
  var self = this;
  Array.prototype.forEach.call(nodeAttrs, function(attr) {
    var attrName = attr.name;
    if (isDirective(attrName)) {
      var exp = attr.value;
      var dir = attrName.substring(2);
      if (isEventDirective(dir)) {
        // 事件指令
        self.compileEvent(node, self.vm, exp, dir);
      } else {
        // v-model 指令
        self.compileModel(node, self.vm, exp, dir);
      }
      node.removeAttribute(attrName); // 解析完毕,移除属性
    }
  });
}
// v-指令解析
function isDirective(attr) {
  return attr.indexOf("v-") == 0;
}
// on: 指令解析
function isEventDirective(dir) {
  return dir.indexOf("on:") === 0;
}

上面的 compile 函数是用于遍历当前 dom 的所有节点属性,然后判断属性是否是指令属性,如果是在做对应的处理(事件就去监听事件、数据就去监听数据..)

6、完整版 myVue

MyVue 中添加 mounted 方法,在所有操作都做完时执行。


class MyVue {
  constructor(options) {
    var self = this;
    this.data = options.data;
    this.methods = options.methods;
    Object.keys(this.data).forEach(function(key) {
      self.proxyKeys(key);
    });
    observe(this.data);
    new Compile(options.el, this);
    options.mounted.call(this); // 所有事情处理好后执行mounted函数
  }
  proxyKeys(key) {
    // 将this.data属性代理到this上
    var self = this;
    Object.defineProperty(this, key, {
      enumerable: false,
      configurable: true,
      get: function getter() {
        return self.data[key];
      },
      set: function setter(newVal) {
        self.data[key] = newVal;
      },
    });
  }
}

然后就可以测试使用了。

https://jsrun.net/Y4IKp/embed...

总结一下流程,回头在哪看一遍这个图,是不是清楚很多了。

可以查看的代码地址:Vue2.x 的双向绑定原理及实现

到此这篇关于Vue2.x 的双向绑定原理及实现的文章就介绍到这了,更多相关Vue 数据双向绑定原理内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Vue2.x 的双向绑定原理及实现

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

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

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

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

下载Word文档
猜你喜欢
  • Vue2.x 的双向绑定原理及实现
    目录1、实现过程2、显示一个 Observer3、实现 Watcher4、实现 Compile5、添加解析事件6、完整版 myVueVue 是利用的 Object.definePro...
    99+
    2024-04-02
  • Vue2.x中双向绑定的实现原理是什么
    Vue2.x中双向绑定的实现原理是什么,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。 Vue 数据双向绑定原理Vue...
    99+
    2024-04-02
  • vue2.x双向数据绑定原理解析
    目录前言一、index.html文件二、vue.js文件1.proxy代理发生了什么?2.observer监听数据3.订阅者Watcher4.订阅器Dep5.编译器Compiler三...
    99+
    2023-02-27
    vue2.x双向数据绑定 vue2.x双向绑定
  • vue2.x双向数据绑定原理是什么
    这篇文章主要介绍了vue2.x双向数据绑定原理是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇vue2.x双向数据绑定原理是什么文章都会有所收获,下面我们一起来看看吧。前言双向数据绑定原理主要运用了发布订阅...
    99+
    2023-07-05
  • Vue双向绑定原理及实现方法
    目录双向绑定示例vue3双向绑定双向绑定 Vue 的双向绑定是通过数据劫持和发布-订阅模式实现的。 当 Vue 实例初始化时,它会对 data 选项中的每个属性使用 Object.d...
    99+
    2023-05-17
    Vue双向绑定 Vue3双向绑定实现
  • 详解Vue中双向绑定原理及简单实现
    目录监听器订阅器双向绑定构造函数编译器(1)Compile类(2)node2Fragment函数(3)compile函数总结效果完整代码代码缺陷监听器 vue实现双向绑定时,首先要实...
    99+
    2023-05-19
    Vue双向绑定原理 Vue实现双向绑定 Vue双向绑定
  • Vue2 与 Vue3 的数据绑定原理及实现
    目录介绍Object.definePropertyProxy介绍 数据绑定是一种把用户界面元素(控件)的属性绑定到特定对象上面并使其同步的机制,使开发人员免于编写同步视图模型和视图的...
    99+
    2024-04-02
  • proxy实现vue3数据双向绑定原理
    目录一、proxy对比Object.defineProperty的优点二、、proxy监听对象的简单实现1.代理对象简单实现2.补充知识 Reflect3.proxy方法三、手写vu...
    99+
    2024-04-02
  • vue2和vue3双向绑定实例分析
    这篇文章主要介绍“vue2和vue3双向绑定实例分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“vue2和vue3双向绑定实例分析”文章能帮助大家解决问题。vue2和vue3中双向绑定的区别是:v...
    99+
    2023-06-29
  • vue双向数据绑定原理分析、vue2和vue3原理的不同点
    目录Vue数据双向绑定原理(一)Vue2双向数据绑定原理(一)Vue3双向数据绑定原理受疫情影响,今年各行业不景气,各岗位的跳槽形势也不是很高。所以趁此机会好好蓄力,复习面试题吧。现...
    99+
    2022-12-08
    vue双向数据 vue数据绑定原理 vue2和vue3原理
  • vue双向绑定原理实例分析
    这篇文章主要介绍了vue双向绑定原理实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇vue双向绑定原理实例分析文章都会有所收获,下面我们一起来看看吧。自定义vue类vue最少需要两个参数:模板和data。...
    99+
    2023-06-29
  • Vue2.0/3.0双向数据绑定的实现原理详解
    Vue2.0/3.0 双向数据绑定的实现原理 双向数据绑定简意 即数据的改变能让页面重新渲染 Vue2.0 ES5的原理: Object.defineProperty 对数据进行拦...
    99+
    2024-04-02
  • Vue2.0/3.0双向数据绑定的实现原理是什么
    这篇文章给大家分享的是有关Vue2.0/3.0双向数据绑定的实现原理是什么的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。vue是什么Vue是一套用于构建用户界面的渐进式JavaScript框架,Vue与其它大型框...
    99+
    2023-06-14
  • 浅谈vue实现双向事件绑定v-model的原理
    目录解释: 总结 补充 与js或者jquery直接改变操作dom不同,vue使用v-model实现数据的双向绑定,它会根据控件类型自动选取正确的方法来更新元素。 v-model就是v...
    99+
    2024-04-02
  • 如何实现JS原生数据双向绑定
    这篇文章主要介绍如何实现JS原生数据双向绑定,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!代码如下:<span  deep="7">...
    99+
    2024-04-02
  • Android数据双向绑定原理实现和应用场景
    目录一、使用databinding类二、双向绑定安卓的数据双向绑定类似Vue这种前端框架,只要修改模型的数据,页面上显示的数据也会跟着变化,不需要取出控件来赋值。 一、使用datab...
    99+
    2023-05-17
    Android数据双向绑定 Android数据绑定 Android双向绑定
  • vue.js实现双向绑定的方式
    Vue.js是一种流行的前端框架,它能够快速构建交互式Web应用程序和用户界面。Vue.js中最主要的特性之一就是双向数据绑定。本文将深入探讨Vue.js是如何实现双向数据绑定的以及它是如何与视图同步的。什么是双向数据绑定双向绑定是一种数据...
    99+
    2023-05-24
  • 浅谈React双向数据绑定原理
    目录什么是双向数据绑定实现双向数据绑定数据影响视图视图影响数据如果已经学过Vue,并且深入了解过Vue的双向数据绑定的话,就会明白 Vue 2.0 双向数据绑定的核心其实是通过Obj...
    99+
    2024-04-02
  • Vue2.0怎么实现双向绑定
    这篇文章主要介绍了Vue2.0怎么实现双向绑定,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、实现双向绑定的做法前端MVVM最令人激动的就...
    99+
    2024-04-02
  • Vue如何实现双向绑定
    这篇文章主要介绍Vue如何实现双向绑定,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!原理当你把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作