摘要:所以,我們是不是應(yīng)該寫一個消息訂閱器呢這樣的話,一觸發(fā)方法,我們就發(fā)一個通知出來,然后,訂閱這個消息的,就會怎樣。。。截止到現(xiàn)在,在我們只考慮最簡單情況下。。關(guān)于的新文章行代碼,理解和分析的響應(yīng)式架構(gòu)
本文能幫你做什么?
。。好奇vue雙向綁定的同學(xué),
可以部分緩解好奇心
還可以幫你了解如何實現(xiàn)$watch
我之前寫了一篇沒什么干貨的文章。。并且刨了一個大坑。。
今天。。打算來填一天。。并再刨一個。。哈哈
不過話說說回來了.看本文之前,,
如果不知道Object.defineProperty,還必須看看解析神奇的 Object.defineProperty
不得不感慨vue的作者,人長得帥,碼寫的也好。
本文是根據(jù)作者源碼,摘取出來的
正如上一篇許下的承諾一樣,本文要實現(xiàn)一個 $wacth
const v = new Vue({ data:{ a:1, b:2 } }) v.$watch("a",()=>console.log("哈哈,$watch成功")) setTimeout(()=>{ v.a = 5 },2000) //打印 哈哈,$watch成功
為了幫助大家理清思路。。我們就做最簡單的實現(xiàn)。。只考慮對象不考慮數(shù)組
1. 實現(xiàn) observer思路:我們知道Object.defineProperty的特性了,
我們就利用它的set和get。。我們將要observe的對象,
通過遞歸,將它所有的屬性,包括子屬性的屬性,都給加上set和get,
這樣的話,給這個對象的某個屬性賦值,就會觸發(fā)set。。嗯。。開始吧
export default class Observer{ constructor(value) { this.value = value this.walk(value) } //遞歸。。讓每個字屬性可以observe walk(value){ Object.keys(value).forEach(key=>this.convert(key,value[key])) } convert(key, val){ defineReactive(this.value, key, val) } } export function defineReactive (obj, key, val) { var childOb = observe(val) Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: ()=>val, set:newVal=> { childOb = observe(newVal)//如果新賦值的值是個復(fù)雜類型。再遞歸它,加上set/get。。 } }) } export function observe (value, vm) { if (!value || typeof value !== "object") { return } return new Observer(value) }
代碼很簡單,就給每個屬性(包括子屬性)都加上get/set,
這樣的話,這個對象的,有任何賦值,就會觸發(fā)set方法。。
所以,我們是不是應(yīng)該寫一個消息-訂閱器呢?這樣的話,
一觸發(fā)set方法,我們就發(fā)一個通知出來,然后,訂閱這個消息的,
就會怎樣?。。。對咯。。收到消息。。。觸發(fā)回調(diào)。
很簡單,我們維護(hù)一個數(shù)組,,這個數(shù)組,就放訂閱著,一旦觸發(fā)notify,
訂閱者就調(diào)用自己的update方法
export default class Dep { constructor() { this.subs = [] } addSub(sub){ this.subs.push(sub) } notify(){ this.subs.forEach(sub=>sub.update()) } }
所以,每次set函數(shù),調(diào)用的時候,我們是不是應(yīng)該,觸發(fā)notify,對吧。所以
我們把代碼補(bǔ)充完整
export function defineReactive (obj, key, val) { var dep = new Dep() var childOb = observe(val) Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: ()=>val, set:newVal=> { var value = val if (newVal === value) { return } val = newVal childOb = observe(newVal) dep.notify() } }) }
那么問題來了。。誰是訂閱者。。對,是Watcher。。一旦 dep.notify()
就遍歷訂閱者,也就是Watcher,并調(diào)用他的update()方法
我們想象這個Watcher,應(yīng)該用什么東西。update方法,嗯這個毋庸置疑,
還有呢,
v.$watch("a",()=>console.log("哈哈,$watch成功"))
對表達(dá)式(就是那個“a”) 和 回調(diào)函數(shù),這是最基本的,所以我們簡單寫寫
export default class Watcher { constructor(vm, expOrFn, cb) { this.cb = cb this.vm = vm //此處簡化.要區(qū)分fuction還是expression,只考慮最簡單的expression this.expOrFn = expOrFn this.value = this.get() } update(){ this.run() } run(){ const value = this.get() if(value !==this.value){ this.value = value this.cb.call(this.vm) } } get(){ //此處簡化。。要區(qū)分fuction還是expression const value = this.vm._data[this.expOrFn] return value } }
那么問題來了,我們怎樣將通過addSub(),將Watcher加進(jìn)去呢。
我們發(fā)現(xiàn)var dep = new Dep() 處于閉包當(dāng)中,
我們又發(fā)現(xiàn)Watcher的構(gòu)造函數(shù)里會調(diào)用this.get
所以,我們可以在上面動動手腳,
修改一下Object.defineProperty的get要調(diào)用的函數(shù),
判斷是不是Watcher的構(gòu)造函數(shù)調(diào)用,如果是,說明他就是這個屬性的訂閱者
果斷將他addSub()中去,那問題來了,
我怎樣判斷他是Watcher的this.get調(diào)用的,而不是我們普通調(diào)用的呢。
對,在Dep定義一個全局唯一的變量,跟著思路我們寫一下
export default class Watcher { ....省略未改動代碼.... get(){ Dep.target = this //此處簡化。。要區(qū)分fuction還是expression const value = this.vm._data[this.expOrFn] Dep.target = null return value } }
這樣的話,我們只需要在Object.defineProperty的get要調(diào)用的函數(shù)里,
判斷有沒有值,就知道到底是Watcher 在get,還是我們自己在查看賦值,如果
是Watcher的話就addSub(),代碼補(bǔ)充一下
export function defineReactive (obj, key, val) { var dep = new Dep() var childOb = observe(val) Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: ()=>{ // 說明這是watch 引起的 if(Dep.target){ dep.addSub(Dep.target) } return val }, set:newVal=> { var value = val if (newVal === value) { return } val = newVal childOb = observe(newVal) dep.notify() } }) }
最后不要忘記,在Dep.js中加上這么一句
Dep.target = null4. 實現(xiàn)一個 Vue
還差一步就大功告成了,我們要把以上代碼配合Vue的$watch方法來用,
要watch Vue實例的屬性,算了,,不要理會我在說什么,,直接看代碼吧
import Watcher from "../watcher" import {observe} from "../observer" export default class Vue { constructor (options={}) { //這里簡化了。。其實要merge this.$options=options //這里簡化了。。其實要區(qū)分的 let data = this._data=this.$options.data Object.keys(data).forEach(key=>this._proxy(key)) observe(data,this) } $watch(expOrFn, cb, options){ new Watcher(this, expOrFn, cb) } _proxy(key) { var self = this Object.defineProperty(self, key, { configurable: true, enumerable: true, get: function proxyGetter () { return self._data[key] }, set: function proxySetter (val) { self._data[key] = val } }) } }
非常簡單。。兩件事,observe自己的data,代理自己的data,
使訪問自己的屬性,就是訪問子data的屬性。。
截止到現(xiàn)在,在我們只考慮最簡單情況下。。整個流程終于跑通了。。肯定會有
很多bug,本文主要目的是展示整個工作流,幫助讀者理解。。
代碼在https://github.com/georgebbbb...,
我是一萬個不想展示自己代碼。。因為很多槽點,還請見諒
下一篇,有兩個方向,將聊一聊如何實現(xiàn)雙向綁定,或者是如何watch數(shù)組。
關(guān)于vue2.0的新文章
100行代碼,理解和分析vue2.0的響應(yīng)式架構(gòu)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/78613.html
摘要:分析是如何實現(xiàn)數(shù)據(jù)響應(yīng)的前記現(xiàn)在回顧一下看數(shù)據(jù)響應(yīng)的原因之前看了和的源碼他們都有自己內(nèi)部的也就是實例使用的都是的響應(yīng)式數(shù)據(jù)特性及所以決定看一下的源碼了解是如何實現(xiàn)響應(yīng)式數(shù)據(jù)本文敘事方式為樹藤摸瓜順著看源碼的邏輯走一遍查看的的版本為目的明確 分析vue是如何實現(xiàn)數(shù)據(jù)響應(yīng)的. 前記 現(xiàn)在回顧一下看數(shù)據(jù)響應(yīng)的原因. 之前看了vuex和vue-i18n的源碼, 他們都有自己內(nèi)部的vm, 也就是...
摘要:中的觀察者模式觀察者模式一般包含發(fā)布者和訂閱者兩種角色顧名思義發(fā)布者負(fù)責(zé)發(fā)布消息,訂閱者通過訂閱消息響應(yīng)動作了。中主要有兩種類型的,一種是另外一種是是通過或者中的屬性定義的。結(jié)束好了,基本結(jié)束,如有錯漏,望指正。 碎碎念 四月份真是慵懶無比的一個月份,看著手頭上沒啥事干,只好翻翻代碼啥的,看了一會Vue的源碼,忽而有點感悟,于是便記錄一下。 Vue中的觀察者模式 觀察者模式一般包含發(fā)布...
摘要:巴拉巴拉省略大法,去除無關(guān)代碼巴拉巴拉省略大法,去除無關(guān)代碼核心就這一句話。文章鏈接源碼分析系列源碼分析系列之環(huán)境搭建源碼分析系列之入口文件分析源碼分析系列之響應(yīng)式數(shù)據(jù)一 前言 接著上一篇的初始化部分,我們細(xì)看initData中做了什么。 正文 initData function initData (vm: Component) { let data = vm.$options.d...
摘要:下面我們會向大家解釋清楚為什么這個這么重要,以及它和的響應(yīng)式數(shù)據(jù)流有什么關(guān)系。源碼前面鋪墊這么多就是希望大家能理解接下來要講的響應(yīng)式數(shù)據(jù)流。總結(jié)講到這里大家應(yīng)該都能夠明白的響應(yīng)式數(shù)據(jù)流是如何實現(xiàn)的。 Vue、React介紹 目前前端社區(qū)比較推崇的框架有Vue 和 React,公司內(nèi)部許多端都自發(fā)的將原有的老技術(shù)方案(widget + jQuery)遷移到 Vue / React上了。我...
摘要:分享前啰嗦我之前介紹過如何實現(xiàn)和。我們采用用最精簡的代碼,還原響應(yīng)式架構(gòu)實現(xiàn)以前寫的那篇源碼分析之如何實現(xiàn)和可以作為本次分享的參考。到現(xiàn)在為止,我們再看那張圖是不是就清楚很多了總結(jié)我非常喜歡,以上代碼為了好展示,都采用最簡單的方式呈現(xiàn)。 分享前啰嗦 我之前介紹過vue1.0如何實現(xiàn)observer和watcher。本想繼續(xù)寫下去,可是vue2.0橫空出世..所以 直接看vue2.0吧...
閱讀 1472·2021-09-30 09:57
閱讀 1481·2021-09-09 09:33
閱讀 2249·2021-09-04 16:40
閱讀 1812·2021-09-01 10:50
閱讀 3259·2021-09-01 10:31
閱讀 2552·2019-08-30 15:56
閱讀 2983·2019-08-30 15:44
閱讀 3486·2019-08-29 17:29