前言:本系列学习笔记从以下几个点展开

  • 什么是双向数据绑定
  • 双向数据绑定的好处
  • 怎么实现双向数据绑定
    • 实现双向数据数据绑定需要哪些知识点

      • 数据劫持
      • 发布订阅模式

先看看我们要实现的目标是什么,如下动图:

0、什么是双向数据绑定

  单向数据绑定:把Model 绑定到View上,当我们用js修改模型 Model 时候,视图View上对应的内容也会改动,这就是 数据动,页面动 。

  双向数据绑定:简言之 数据动 页面动,页面动,数据动, 典型的应用就是在做表单时候,输入框的内容改动后,跟该输入框的value 的值改动。

  

看vue 官网上的这个V-model  的演示案例:

1、双向数据绑定的好处

  要说出这个好处的时候,也只有在实际场景中才能对应的显示出来。比如我们需要实时显示数据,我们一边说话,一边实时显示我们说的话的文字内容,等等。这让我想起了去年参加云栖大会,台上的大佬一边说话,下面的字幕实时更新。(当然实现这个技术有很多技术点,我们不讨论这个内容,小编也才疏学浅,搞不懂)

以上的都是废话,我们直接看看怎么实现这个双向数据绑定。

一、实现原理

  Vue实现双向数据绑定的原理:数据劫持 + 发布订阅模式(有的也称为观察者模式)

  数据劫持的核心技术: Object.defineProperty()

  **vue 3.0 已经用的不是这个技术了,采用是 原生的 Proxy,据说速度能够提升100%,截张尤大的ppt,** 2018-11-21 修改本篇笔记

(香菇,刚研究会一点,就立马变了,这就是前端世界),Proxy 的方式将会在本系列笔记结束后,再记录这个技术点的使用

二、数据劫持的方法 Object.defineProperty()

  先上一个参照代码,它长这个样子:

var book = {
_year: ,
edition:
};
Object.defineProperty(book, "year", {
get: function(){
   console.log('访问year了,返回_year')
  return this._year;
},
set: function(newValue){
  if (newValue > ) {
    this._year = newValue;
     console.log('重新设置_year了,并返回edition')
    this.edition += newValue - ;
  }
}
});
book.year = ;
alert(book.edition); //2

---摘自 JavaScript高级程序设计

  Object.defineProperty() 的具体介绍,我们本文不做具体展开,查看我这里的一篇文章,Object.defineProperty。 我们这里先要知道这么一个事情。这个方法要传入三个参数,传入的数据对象data,属性key,描述符对象。其中,描述符(descriptor)对象的属 性必须是:configurable、enumerable、writable 和 value。设置其中的一或多个值,可以修改 对应的特性值。我们需要用的是这访问器属性。当我们在读取访问器属性时,会调用 getter 函数,这个函数负责返回有效的值;在写入访问器属性时,会调用 setter 函数并传入新值,这个函数负责决定如何处理数据。上文代码上的 get 方法,在读取属性时调用的函数,set方法,在写入属性时调用的函数。

三、发布订阅者模式

  我画了一个图,来理解这个模式,如下图:

  

代码解释:

//下面封装一个单例模式,内容是发布订阅模式
let event = {
eventList: [],
listener: function (key, fn) {
if (!this.eventList[key]) { //没有订阅过此类消息,创建一个缓存列表
this.eventList[key] = [];
}
this.eventList[key].push(fn)
},
trigger: function () {
let key = Array.prototype.shift.call(arguments); // marry
let fns = this.eventList[key];
if (!fns || fns.length == 0) { //没有订阅 则返回
return false;
}
for (let i = 0, fn; fn = fns[i++];) {
fn.apply(this, arguments)
// 调用 event.listen 里面的 fn 方法,通过apply将当前执行的对象指向当前的this,arguments 传进 fn 函数
}
},
remove: function (key, fn) { // 取消订阅
let fns = this.eventList[key];
if (!fns) {
return false;
}
if(!fn) {
fns && (fns.length = 0)
} else {
for (let l = fns.length-1; l>=0; l--) {
let _fn = fns[l];
if( _fn === fn) {
fns.splice(l, 1)
}
}
}
},
install: function (obj) {
for (let i in this) {
if (i === 'install') {
return false
}
obj[i] = this[i];
}
}
} let testMsg = {}
event.install(testMsg) // 上面方法 就会将event的方法 浅拷贝给 testMsg, 这样testMsg就有 event的方法和属性
testMsg.listener('rich', fn1 = (name) => {
console.log(`${name}知道你有钱了`)
})
testMsg.listener('borrowMoney', fn2 = (name) => {
console.log(`${name}想问你借钱`)
}) // listen方法将事件 放进队列
// testMsg.remove('rich', fn1) // 取消订阅 // trigger方法,处理事件队列的方法,调用listen的函数的里面的回调函数 fn
testMsg.trigger('rich', '张三')
testMsg.trigger('rich', '张三2')
testMsg.trigger('borrowMoney', '李四')
testMsg.trigger('borrowMoney', '李四2') // 代码总结:
// 订阅的事件具有对应的key
// 通过listener方法,将具体的事件队列保存到 eventList ,可以理解为缓存列表也可以是事件队列;
// 执行trigger 方法,将事件队列拿出来执行调用
// remove 方法根据对应的key值,删除对应的订阅事件
// 模式总结:封装一个单例event, 执行installEvent方法,将想要event对象拷贝到某个对象中去,
// 发布者trigger方法,监听者listen方法 ,trigger 发布一个东西,listen立马知道你要发布的东西

四、实现分解

  • 主函数入口

    •   

      function Myvue (options) {
      this.$options = options
      this.$el = document.querySelector(options.el);
      this.$data = options.data;
      Object.keys(this.$data).forEach(key => {
      this.$prop = key;
      })
      this.init()
      }
      Myvue.prototype.init = function () {
      // 监听数据变化
      observer(this.$data);
      // 获得值
      // let value = this.$data[this.$prop];
      // 不经过模板编译直接 通知订阅者更新dom
      // new Watcher(this,this.$prop,value => {
      // console.log(`watcher ${this.$prop}的改动,要有动静了`)
      // this.$el.textContent = value
      // })
      //通知模板编译来执行页面上模板变量替换
      new Compile(this)
      }
  • 主函数调用
    •   

      <script>
      const vm = new Myvue({
      el: "#app",
      data: {
      name: "vue 双向数据绑定test1"
      }
      });
      </script>
  • 监听器
  • 订阅者
  • 模板编译器

未完待续,错误之处,敬请指出,共同进步!

下一篇 vue 双向数据绑定的实现学习(二)-监听器的实现

文章参考:

  https://www.cnblogs.com/beevesnoodles/p/9844854.html

  https://github.com/youngwind/blog/issues/87

  https://juejin.im/post/5a9108b6f265da4e7527b1a4

后记:代码只做基本实现,不做代码健壮性处理,一些错误处理已经忽略

vue 双向数据绑定的实现学习(一)的更多相关文章

  1. vue 双向数据绑定的实现学习(二)- 监听器的实现

    废话:上一篇https://www.cnblogs.com/adouwt/p/9928278.html 提到了vue实现的基本实现原理:Object.defineProperty() -数据劫持 和  ...

  2. vue双向数据绑定的简单实现

    vue双向数据绑定的简单实现 参考教程:链接 <!DOCTYPE html> <html lang="en"> <head> <meta ...

  3. Vue双向数据绑定原理分析(转)

    add by zhj: 目前组里使用的是前端技术是jQuery + Bootstrap,后端使用的Django,Flask等,模板是在后端渲染的.前后端没有分离,这种做法有几个缺点 1. 模板一般是由 ...

  4. angular和vue双向数据绑定

    angular和vue双向数据绑定的原理(重点是vue的双向绑定) 我在整理javascript高级程序设计的笔记的时候看到面向对象设计那章,讲到对象属性分为数据属性和访问器属性,我们平时用的js对象 ...

  5. vue双向数据绑定最最最最最简单直观的例子

    vue双向数据绑定最最最最最简单直观的例子 一.总结 一句话总结:双向绑定既不仅model可以影响view的数据,view也可以影响model的数据 view model 数据 1.vue双向数据绑定 ...

  6. React 事件对象、键盘事件、表单事件、ref获取dom节点、react实现类似Vue双向数据绑定

    1.案例实现代码 import React, { Component } from 'react'; /** * 事件对象.键盘事件.表单事件.ref获取dom节点.react实现类似Vue双向数据绑 ...

  7. 详解 vue 双向数据绑定的原理,并实现一组双向数据绑定

    1:vue 双向数据绑定的原理: Object.defineProperty是ES5新增的一个API,其作用是给对象的属性增加更多的控制Object.defineProperty(obj, prop, ...

  8. vue双向数据绑定原理探究(附demo)

    昨天被导师叫去研究了一下vue的双向数据绑定原理...本来以为原理的东西都非常高深,没想到vue的双向绑定真的很好理解啊...自己动手写了一个. 传送门 双向绑定的思想 双向数据绑定的思想就是数据层与 ...

  9. Vue 双向数据绑定、事件介绍以及ref获取dom节点

    vue是一个MVVM的框架 M model V view MVVM  model改变会影响视图view,view改变会影响model 双向数据绑定必须在表单里面使用 //我发现在谷歌浏览器翻译后的网页 ...

随机推荐

  1. JSON获取地址

    JSON获取地址一: https://github.com/stleary/JSON-java JSON获取地址二: http://genson.io/ JSON获取地址一: https://code ...

  2. 关于npm安装报错 网络问题等等等

    最近需要安装taro 结果网络各种报错 解决方法 : 1重置网络 npm config rm proxynpm config rm https-proxy 2换淘宝镜像 npm config set ...

  3. Windows kafka_2.11-1.1.0安装

    #broker.id= #broker.list=,, listeners=PLAINTEXT://127.0.0.1:9092 advertised.listeners=PLAINTEXT://12 ...

  4. 4月22日MySQL学习

    前面学习的知识基本都是概念知识没有什么代码,然后还有图形界面来辅助学习. 今天学习了MySQL的存储引擎,最常用的两种 MYISAM:不支持事务,也不支持外键,但是访问速度快. INNODB:支持事务 ...

  5. JDK源代码学习-基础类

    一.概述 1.Java,是一套语言规范,例如规定了变量如何定义.控制语句如何写等,提供基本的语法规范.JDK是java自带的一套调用组件,是对基本java语法规范的进一步封装,jdk中都是使用java ...

  6. Linux下截取指定时间段日志并输出到指定文件

    sed -n '/2019-04-22 16:10:/,/2019-04-22 16:20:/p' log.log > bbb.txt

  7. POJ2960 S-Nim 【博弈论】

    Description Arthur and his sister Caroll have been playing a game called Nim for some time now. Nim ...

  8. 详解最大似然估计(MLE)、最大后验概率估计(MAP),以及贝叶斯公式的理解

    转载声明:本文为转载文章,发表于nebulaf91的csdn博客.欢迎转载,但请务必保留本信息,注明文章出处. 原文作者: nebulaf91 原文原始地址:http://blog.csdn.net/ ...

  9. seq2seq

    seq2seq: seq2seq就是将输入序列经过encoder-decoder变成目标序列. 如图所示,输入序列是 [A, B, C, <EOS>],输出序列是  [W, X, Y, Z ...

  10. Nginx 反向代理 负载均衡 虚拟主机

    Nginx 反向代理 负载均衡 虚拟主机配置 通过本章你将学会利用Nginx配置多台虚拟主机,清楚代理服务器的作用,区分正向代理和反向代理的区别,搭建使用Nginx反向搭理和负载均衡,了解Nginx常 ...