摘要:在原理中,最重要的部分就是如何实现数据的观测,依赖的收集,视图的更新。本文讲的就是这三个的简单实现。这样做代码似乎有点丑,我们在设置属性触发会发生函数,有没有一种更加智能的方式来实现通知变化呢。
在vue原理中,最重要的部分就是如何实现数据的观测,依赖的收集,视图的更新。本文讲的就是Observer, Dep, Watcher这三个的简单实现。
pub(publish)表示发布者,sub(subscribe)表示订阅者, cb(callback)表示回调函数
如果你觉得这篇讲的对你有所帮助,请帮我点个star
Observer的作用简单来说就是让object对象的属性都用Object.defineProperty()来进行定义,这样当获取object的属性,或者修改属性的时候,就能够触发get,set达到数据的观测的效果。
class Observer { constructor(value) { this.value = value this.walk(this.value) } walk (value) { // 递归遍历value的属性 Object.keys(value).forEach((key) = > { defineReactive(value, key, value[key]) }) } } function defineReactive(obj, key ,val) { let childOb = observe(val) Obeject.defineProperty(obj, key, { enumerable: true, configurable: true, get() { console.log("") return val }, set(newVal) { console.log("") val = newVal childOb = observe(val) } }) } function observe (value) { if (typeof value === "object" && !Array.isArray(value)) { value = new Observer(value) } }
defineReactive的作用就是给对象的属性进行简单的数据观测,一旦值获取或者设置就会触发一些行为.因为一个对象的属性可能还是对象,所以在这里我们添加observe函数来遍历值,让一个对象的属性的属性还是可以进行观测的,简单呢来说的意思就是让所有属性都可以进行忽略。当然在实际情况中,我们还需要考虑数组的情况,但都大同小异。
这样做代码似乎有点丑,我们在设置属性触发set会发生console.log()函数,有没有一种更加智能的方式来实现通知变化呢。这里我们就需要用消息订阅器来进行实现,这样做我们就不需要通过观察console.log()输出的值来看进行的情况,我们只需要在set方法里边加一个通知,一旦值发生变化,就通知外边值发生了改变
Dep的作用就是用来收集属性值的变化,一旦set方法触发的时候,就更新视图。那就准备一个数组来进行收集吧!
下面是Dep的实现:
class Dep { constructor() { this.subs = [] } addSub (sub) { this.subs.push(sub) } notify () { const subs = this.subs.slice() subs.forEach((sub) => { sub.update() // 视图更新 }) } }
上面就是Dep的简单实现,addSub的作用是增加订阅者,因为有很多订阅者,我们需要用一个数组将它进行存储,notify()函数的作用就是当set发生的时候,进行通知,update()这个函数待会在watcher中会讲到。实现了Dep我们是不是该更改了set()函数了呢,下面是defineReactive()修改后的代码
function defineReactive(obj, key ,val) { let dep = new Dep() // 毕竟要使用Dep的方法 let childOb = observe(val) Obeject.defineProperty(obj, key, { enumerable: true, configurable: true, get() { return val }, set(newVal) { val = newVal childOb = observe(val) dep.notify() // 因为数据改变了,我们就通知Dep } }) }
一旦触发set,就调用dep.notify(),notify的作用就是针对订阅者遍历进行更新。
Watcher的简单实现:watcher的作用,就是当状态发生改变的时候,更新视图,我们可以假设
class Watcher { constructor (vm, cb, expOrFn) { this.vm = vm // 这表示一个Vue的实例 this.cb = cb // 这里需要考虑expOrFn是字符串或者函数的情况 // 这里做一个简化,只考虑函数的情况 this.getter = expOrFn this.value = this.get() } get () { Dep.target = this const vm = this.vm value = this.getter.call(this.vm, vm) Dep.target = null return value } update () { this.run() } run () { const value = this.get() if (value !== this.value) { const oldValue = this.value this.value = value this.cb.call(this.vm, value, oldValue) } } }
Watcher的简单实现就完成了,在Dep()构造函数中,我们使用了sub.update()这行代码,而update函数是Watcher里边的方法,说明每一个sub都是Wathcer的实例,问题是我们应该如何通过addSub()这个方法,将Watcher加入到subs这个数组中尽心存储呢,答案还是在defineReactive()里边进行修改
function defineReactive(obj, key ,val) { let dep = new Dep() // 毕竟要使用Dep的方法 let childOb = observe(val) Obeject.defineProperty(obj, key, { enumerable: true, configurable: true, get() { if(Dep.target) { dep.addSub(Dep.target) } return val }, set(newVal) { val = newVal childOb = observe(val) dep.notify() // 因为数据改变了,我们就通知Dep } }) }
这样是不是就实现了往Dep里边加Watcher了,vue源码中比这个复杂的多,各种参数,看着头大。本文的宗旨就是通过简化让你了解内部原理,如果需要更深入了解就需要阅读源码了。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/92151.html
摘要:后端路由简介路由这个概念最先是后端出现的。前端路由模式随着的流行,异步数据请求交互运行在不刷新浏览器的情况下进行。通过这些就能用另一种方式来实现前端路由了,但原理都是跟实现相同的。 后端路由简介 路由这个概念最先是后端出现的。在以前用模板引擎开发页面时,经常会看到这样 http://www.xxx.com/login 大致流程可以看成这样: 浏览器发出请求 服务器监听到80端口(或4...
答案自己谷歌或百度找。 一、来源背景 面试题是来自微博@牛客网发布的真实大厂前端面经题目,我一直在收集题目长期一个一个的记录下来的,可能会有重复,但基本前端的面试大纲和需要掌握的知识都在其中了,面试题仅做学习参考,学习者阅后也要用心钻研其中的原理,重要知识需要系统学习、透彻学习,形成自己的知识链。 二、532道前端真实大厂面试题 express和koa的对比,两者中间件的原理,koa捕获异常多种情...
答案自己谷歌或百度找。 一、来源背景 面试题是来自微博@牛客网发布的真实大厂前端面经题目,我一直在收集题目长期一个一个的记录下来的,可能会有重复,但基本前端的面试大纲和需要掌握的知识都在其中了,面试题仅做学习参考,学习者阅后也要用心钻研其中的原理,重要知识需要系统学习、透彻学习,形成自己的知识链。 二、532道前端真实大厂面试题 express和koa的对比,两者中间件的原理,koa捕获异常多种情...
答案自己谷歌或百度找。 一、来源背景 面试题是来自微博@牛客网发布的真实大厂前端面经题目,我一直在收集题目长期一个一个的记录下来的,可能会有重复,但基本前端的面试大纲和需要掌握的知识都在其中了,面试题仅做学习参考,学习者阅后也要用心钻研其中的原理,重要知识需要系统学习、透彻学习,形成自己的知识链。 二、532道前端真实大厂面试题 express和koa的对比,两者中间件的原理,koa捕获异常多种情...
摘要:双向数据绑定指的是,将对象属性变化与视图的变化相互绑定。数据双向绑定已经了解到是通过数据劫持的方式来做数据绑定的,其中最核心的方法便是通过来实现对属性的劫持,达到监听数据变动的目的。和允许观察数据的更改并触发更新。 1 MVVM 双向数据绑定指的是,将对象属性变化与视图的变化相互绑定。换句话说,如果有一个拥有name属性的user对象,与元素的内容绑定,当给user.name赋予一个新...
阅读 1833·2021-09-22 15:23
阅读 3255·2021-09-04 16:45
阅读 1842·2021-07-29 14:49
阅读 2767·2019-08-30 15:44
阅读 1523·2019-08-29 16:36
阅读 1037·2019-08-29 11:03
阅读 1503·2019-08-26 13:53
阅读 503·2019-08-26 11:57