实现vue2.0响应式的基本思路

注意,这里只是实现思路的还原,对于里面各种细节的实现,比如说数组里面数据的操作的监听,以及对象嵌套这些细节本实例都不会涉及到,如果想了解更加细节的实现,可以通过阅读源码 observer文件夹以及instance文件夹里面的state文件具体了解。

首先,我们先定义好实现vue对象的结构

 

class Vue {constructor(options) {this.$options = options;this._data = options.data;this.$el = document.querySelector(options.el);}
}

  第一步:将data下面的属性变为observable

使用Object.defineProperty对数据对象做属性get和set的监听,当有数据读取和赋值操作时则调用节点的指令,这样使用最通用的=等号赋值就可以触发了。

//数据劫持,监控数据变化
function observer(value, cb){Object.keys(value).forEach((key) => defineReactive(value, key, value[key] , cb))
}function defineReactive(obj, key, val, cb) {Object.defineProperty(obj, key, {enumerable: true,configurable: true,get: ()=>{return val},set: newVal => {if(newVal === val)returnval = newVal}})
}

  第二步:实现一个消息订阅器

很简单,我们维护一个数组,这个数组,就放订阅者,一旦触发notify,订阅者就调用自己

的update方法

class Dep {constructor() {this.subs = []}add(watcher) {this.subs.push(watcher)}notify() {this.subs.forEach((watcher) => watcher.cb())}
}

  

每次set函数,调用的时候,我们触发notify,实现更新

那么问题来了。谁是订阅者。对,是Watcher。。一旦 dep.notify()就遍历订阅者,也就是Watcher,并调用他的update()方法

function defineReactive(obj, key, val, cb) {const dep = new Dep()Object.defineProperty(obj, key, {enumerable: true,configurable: true,get: ()=>{return val},set: newVal => {if(newVal === val)returnval = newValdep.notify()}})
}

  第三步:实现一个 Watcher

Watcher的实现比较简单,其实就是执行数据变化时我们要执行的操作

class Watcher {constructor(vm, cb) {this.cb = cbthis.vm = vm}update(){this.run()}run(){this.cb.call(this.vm)} 
}

  第四步:touch拿到依赖

上述三步,我们实现了数据改变可以触发更新,现在问题是我们无法将watcher与我们的数据联系到一起。

我们知道data上的属性设置defineReactive后,修改data 上的值会触发 set。那么我们取data上值是会触发 get了。所以可以利用这一点,先执行以下render函数,就可以知道视图的更新需要哪些数据的支持,并把它记录为数据的订阅者。

function defineReactive(obj, key, val, cb) {const dep = new Dep()Object.defineProperty(obj, key, {enumerable: true,configurable: true,get: ()=>{if(Dep.target){dep.add(Dep.target)}return val},set: newVal => {if(newVal === val)returnval = newValdep.notify()}})
}

  最后我们来看用一个代理实现将我们对data的数据访问绑定在vue对象上

 _proxy(key) {const self = thisObject.defineProperty(self, key, {configurable: true,enumerable: true,get: function proxyGetter () {return self._data[key]},set: function proxySetter (val) {self._data[key] = val}})
}Object.keys(options.data).forEach(key => this._proxy(key))

  下面就是整个实例的完整代码

class Vue {constructor(options) {this.$options = options;this._data = options.data;this.$el =document.querySelector(options.el);Object.keys(options.data).forEach(key => this._proxy(key))observer(options.data)watch(this, this._render.bind(this), this._update.bind(this))}_proxy(key) {const self = thisObject.defineProperty(self, key, {configurable: true,enumerable: true,get: function proxyGetter () {return self._data[key]},set: function proxySetter (val) {self._data[key] = val}})}_update() {console.log("我需要更新");this._render.call(this)}_render() {this._bindText();}_bindText() {let textDOMs=this.$el.querySelectorAll('[v-text]'),bindText;for(let i=0;i<textDOMs.length;i++){bindText=textDOMs[i].getAttribute('v-text');let data = this._data[bindText];if(data){textDOMs[i].innerHTML=data;}      }}
}function observer(value, cb){Object.keys(value).forEach((key) => defineReactive(value, key, value[key] , cb))
}function defineReactive(obj, key, val, cb) {const dep = new Dep()Object.defineProperty(obj, key, {enumerable: true,configurable: true,get: ()=>{if(Dep.target){dep.add(Dep.target)}return val},set: newVal => {if(newVal === val)returnval = newValdep.notify()}})
}
function watch(vm, exp, cb){Dep.target = new Watcher(vm,cb);return exp()
}class Watcher {constructor(vm, cb) {this.cb = cbthis.vm = vm}update(){this.run()}run(){this.cb.call(this.vm)} 
}class Dep {constructor() {this.subs = []}add(watcher) {this.subs.push(watcher)}notify() {this.subs.forEach((watcher) => watcher.cb())}
}
Dep.target = null;
var demo = new Vue({
el: '#demo',
data: {
text: "hello world"
}
})setTimeout(function(){
demo.text = "hello new world"}, 1000)

  

  <body><div id="demo"><div v-text="text"></div></div></body>

  上面就是整个vue数据驱动部分的整个思路。如果想深入了解更细节的实现,建议深入去看vue这部分的代码。

感谢vue慕课响应式手记

 

转载于:https://www.cnblogs.com/smzd/p/8621729.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/249933.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTML标签类型及特点

一、 概述 HTML&#xff08;Hyper Text Markup Language &#xff09;作为一种标记语言&#xff0c;网页所有的内容均书写在标签内部&#xff0c;标签是组成Html页面的基本元素&#xff0c;因此对标签特性的理解在HTML的学习过程中比较重要。 二、基本分类 HTML中的标签从闭…

打开页面

*<a href"javascript:void(0)" title"google" οnclick"window.parent.addTab(, 测试, Admin/UserRole, 100000)">测试444</a>*转载于:https://www.cnblogs.com/niyl/p/10196528.html

python 大量使用json 存储数据时,格式化输出的方式

import json, pprintdic {name: 234, user_name: yan xia ting yu , list: [ds, a, 2], 你好这是键: 檐下听雨}print(dic)pprint.pprint(dic)print(json.dumps(dic))print(json.dumps(dic, indent2))# {name: 234, user_name: yan xia ting yu , list: [ds, a, 2], 你好这是键…

vue computed 源码分析

我们来看看computed的实现。最简单的一个demo如下&#xff1a; <html> <head><meta http-equiv"Content-Type" content"text/html; charsetutf-8" /> </head> <body> <div id"app"><div name"test&…

软件开发文档整理(之)一张示意图 | 清晰明了

在整个软件开发周期&#xff0c;开发文档是必不可少的资料&#xff0c;它们贯穿于整个开发周期&#xff0c;用来评估计划、规划进度、项目管理、软件测试、软件发布&#xff0c;可以说至关重要。   开发文档必须归档&#xff0c;没有归档的文档作用大打折扣&#xff0c;时效性…

java大数BinInteger

当我们遇到long不行的时候就要考虑这个BinInteger了&#xff0c;因为这是只要你内存够大&#xff0c;就能输入很大的数&#xff0c;用这个处理高精度问题&#xff0c;是很容易的一件事&#xff0c;对于我这刚学java的萌新来说&#xff0c;长见识了&#xff0c;确实比C方便 BigI…

HTML页面提交TABLE

在HTML页面里&#xff0c;提交一个TABLE需要把TABLE的值传入变量或json格式&#xff0c;然后submit到服务端的。 思路描述&#xff1a;将table里的值取出&#xff0c;放在json中&#xff0c;赋给一个input&#xff0c;通过一个input来实现table表数据提交到服务器&#xff0c;就…

生成条形码

https://packagist.org/packages/picqer/php-barcode-generator转载于:https://www.cnblogs.com/pansidong/p/9334224.html

3.GDScript(1)概览

GDScript 是上面提到的用于Godot的主要语言。和其他语言相比&#xff0c;它与Godot高度整合&#xff0c;有许多优点&#xff1a; 简单&#xff0c;优雅&#xff0c;设计上为Lua、Python、Squirrel等语言用户所熟悉。加载和编译速度飞快。编辑器集成非常令人愉快&#xff0c;有节…

Web 前端框架分类解读

Web前端框架可以分为两类&#xff1a; JS的类库框架 JQuery.JS Angular.JS&#xff08;模型&#xff0c; scope作用域&#xff0c;controller&#xff0c;依赖注入&#xff0c;MVVM&#xff09;&#xff1a;前端MVC Vue.JS&#xff08;MVVM&#xff09;***** Reat.JS &…

async / await对异步的处理

虽然co是社区里面的优秀异步解决方案&#xff0c;但是并不是语言标准&#xff0c;只是一个过渡方案。ES7语言层面提供async / await去解决语言层面的难题。目前async / await 在 IE edge中已经可以直接使用了&#xff0c;但是chrome和Node.js还没有支持。幸运的是&#xff0c;b…

《SQL Server 2008从入门到精通》--20180717

目录 1.触发器1.1.DDL触发器1.2.DML触发器1.3.创建触发器1.3.1.创建DML触发器1.3.2.创建DDL触发器1.3.3.嵌套触发器1.3.4.递归触发器1.4.管理触发器1.触发器 触发器是一种特殊的存储过程&#xff0c;与表紧密关联。 1.1.DDL触发器 当服务器或数据库中发生数据定义语言&#xff…

主成分分析原理解释(能力工场小马哥)

主成分分析&#xff08;Principal components analysis&#xff09;-最大方差解释 在这一篇之前的内容是《Factor Analysis》&#xff0c;由于非常理论&#xff0c;打算学完整个课程后再写。在写这篇之前&#xff0c;我阅读了PCA、SVD和LDA。这几个模型相近&#xff0c;却都有自…

div/div作用

<div></div>主要是用来设置涵盖一个区块为主&#xff0c;所谓的区块是包含一行以上的数据&#xff0c;所以在<div></div>的开始之前与结束后&#xff0c;浏览都会自动换行&#xff0c;所以夹在<div></div>间的数据&#xff0c;自然会与其前…

路由懒加载优化

首先得需要插件支持&#xff1a;syntax-dynamic-import import Vue from vue import VueRouter from vue-router /*import First from /components/First import Second from /components/Second*/Vue.use(VueRouter) //方案1 const first ()>import(/* webpackChunkName: &…

vue全面介绍--全家桶、项目实例

简介 “简单却不失优雅&#xff0c;小巧而不乏大匠”。 2016年最火的前端框架当属Vue.js了&#xff0c;很多使用过vue的程序员这样评价它&#xff0c;“vue.js兼具angular.js和react.js的优点&#xff0c;并剔除了它们的缺点”。授予了这么高的评价的vue.js&#xff0c;也是开…

关于Keychain

1、Keychain 浅析 2、iOS的密码管理系统 Keychain的介绍和使用 3.iOS开发中&#xff0c;唯一标识的解决方案之keyChainUUID 转载于:https://www.cnblogs.com/KiVen2015/p/9341224.html

算法群模拟面试记录

第一场&#xff1a;2018年12月30日&#xff08;周日&#xff09;&#xff0c;北京时间早上五点。 写在最前面&#xff1a;好不容易五点爬了起来围观mock&#xff0c;结果早上周赛睡过去了&#xff0c;唉。orz。 面试官&#xff1a;wisdompeak&#xff0c;同学&#xff1a;littl…

js对象排序

Object.keys(objs).sort()可以获取到排好序的keysvar objs {f: {id: 2,name: 2}, a: {id: 3,name: 3}, c: {id: 1,name: 1} }; // 自定义排序规则&#xff0c;按对象的id排序 var sortedObjKeys Object.keys(objs).sort(function(a, b) {return objs[b].id - objs[a].id; });…

吴恩达机器学习笔记 —— 9 神经网络学习

本章讲述了神经网络的起源与神经元模型&#xff0c;并且描述了前馈型神经网络的构造。 更多内容参考 机器学习&深度学习 在传统的线性回归或者逻辑回归中&#xff0c;如果特征很多&#xff0c;想要手动组合很多有效的特征是不现实的&#xff1b;而且处理这么大的特征数据量…