最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue如何實現(xiàn)observer和watcher源碼解析

 更新時間:2017年03月09日 10:33:05   作者:楊川寶  
這篇文章主要為大家詳細介紹了vue如何實現(xiàn)observer和watcher源碼的相關資料,分析vue的observe實現(xiàn)源碼,聊聊如何一步一步實現(xiàn)$watch,具有一定的參考價值,感興趣的小伙伴們可以參考一下

本文能幫你做什么?好奇vue雙向綁定的同學,可以部分緩解好奇心,還可以幫你了解如何實現(xiàn)$watch。

前情回顧

我之前寫了一篇沒什么干貨的文章,并且刨了一個大坑。
今天,打算來填一天,并再刨一個。

不過話說說回來了,看本文之前,如果不知道Object.defineProperty,還必須看看解析神奇的Object.defineProperty
不得不感慨vue的作者,人長得帥,碼寫的也好,本文是根據(jù)作者源碼,摘取出來的

本文將實現(xiàn)什么

正如上一篇許下的承諾一樣,本文要實現(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)//如果新賦值的值是個復雜類型。再遞歸它,加上set/get。。
 }
 })
}


export function observe (value, vm) {
 if (!value || typeof value !== 'object') {
 return
 }
 return new Observer(value)
}

代碼很簡單,就給每個屬性(包括子屬性)都加上get/set,這樣的話,這個對象的,有任何賦值,就會觸發(fā)set方法。。
所以,我們是不是應該寫一個消息-訂閱器呢?

這樣的話,一觸發(fā)set方法,我們就發(fā)一個通知出來,然后,訂閱這個消息的,就會怎樣?對咯。、收到消息、觸發(fā)回調(diào)。

2. 消息-訂閱器

很簡單,我們維護一個數(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)用的時候,我們是不是應該,觸發(fā)notify,對吧。所以我們把代碼補充完整

 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()方法

3. 實現(xiàn)一個Watcher
我們想象這個Watcher,應該用什么東西。update方法,嗯這個毋庸置疑,還有呢。

v.$watch("a",()=>console.log("哈哈,$watch成功"))

對表達式(就是那個“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加進去呢。
我們發(fā)現(xiàn)var dep = new Dep() 處于閉包當中,我們又發(fā)現(xiàn)Watcher的構造函數(shù)里會調(diào)用this.get,所以,我們可以在上面動動手腳,修改一下Object.defineProperty的get要調(diào)用的函數(shù),判斷是不是Watcher的構造函數(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(),代碼補充一下

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 = null

4. 實現(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)在,在我們只考慮最簡單情況下,整個流程終于跑通了??隙〞泻芏郻ug,本文主要目的是展示整個工作流,幫助讀者理解。
代碼在https://github.com/georgebbbb...,

我是一萬個不想展示自己代碼,因為很多槽點,還請見諒

下一篇,有兩個方向,將聊一聊如何實現(xiàn)雙向綁定,或者是如何watch數(shù)組。

關于vue2.0的新文章

100行代碼,理解和分析vue2.0的響應式架構

本文已被整理到了《Vue.js前端組件學習教程》,歡迎大家學習閱讀。

關于vue.js組件的教程,請大家點擊專題vue.js組件學習教程進行學習。

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • vue中向data添加新屬性的三種方式小結

    vue中向data添加新屬性的三種方式小結

    這篇文章主要介紹了vue中向data添加新屬性的三種方式小結,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • Vue使用wangEditor實現(xiàn)自定義粘貼功能

    Vue使用wangEditor實現(xiàn)自定義粘貼功能

    這篇文章主要為大家詳細介紹了Vue如何使用wangEditor實現(xiàn)自定義粘貼功能,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2024-12-12
  • vue實現(xiàn)input輸入模糊查詢的三種方式

    vue實現(xiàn)input輸入模糊查詢的三種方式

    本文主要介紹了vue實現(xiàn)input輸入模糊查詢的三種方式嗎,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-08-08
  • vue中常見的問題及解決方法總結(推薦)

    vue中常見的問題及解決方法總結(推薦)

    這篇文章主要給大家介紹了關于vue中常見的問題及解決方法的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-04-04
  • Vue如何接入hls/m3u8的直播視頻詳解

    Vue如何接入hls/m3u8的直播視頻詳解

    項目中有一個需求,需要實現(xiàn)直播功能,后端接口返回的是m3u8數(shù)據(jù)流,下面這篇文章主要給大家介紹了關于Vue如何接入hls/m3u8直播視頻的相關資料,需要的朋友可以參考下
    2022-07-07
  • antd table按表格里的日期去排序操作

    antd table按表格里的日期去排序操作

    這篇文章主要介紹了antd table按表格里的日期去排序操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • 基于Vue實現(xiàn)的多條件篩選功能的詳解(類似京東和淘寶功能)

    基于Vue實現(xiàn)的多條件篩選功能的詳解(類似京東和淘寶功能)

    這篇文章主要介紹了Vue多條件篩選功能,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-05-05
  • vue如何實現(xiàn)跨頁面?zhèn)鬟f與接收數(shù)組并賦值

    vue如何實現(xiàn)跨頁面?zhèn)鬟f與接收數(shù)組并賦值

    這篇文章主要介紹了vue如何實現(xiàn)跨頁面?zhèn)鬟f與接收數(shù)組并賦值,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • Vue3實現(xiàn)列表無限滾動的示例詳解

    Vue3實現(xiàn)列表無限滾動的示例詳解

    這篇文章主要為大家詳細介紹了如何使用Vue3實現(xiàn)列表無限滾動的效果,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-07-07
  • vue實現(xiàn)彈窗拖拽效果

    vue實現(xiàn)彈窗拖拽效果

    這篇文章主要為大家詳細介紹了vue實現(xiàn)彈窗拖拽效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-09-09

最新評論

南陵县| 杭锦旗| 谷城县| 南涧| 泰顺县| 桃江县| 徐闻县| 沾益县| 荣昌县| 万州区| 淮阳县| 黑龙江省| 新蔡县| 闽清县| 抚宁县| 泽普县| 东安县| 唐河县| 宜兴市| 库车县| 遂川县| 虎林市| 沛县| 务川| 广汉市| 宝丰县| 台州市| 阿合奇县| 香河县| 永平县| 三门县| 白玉县| 徐汇区| 博白县| 军事| 曲阜市| 长岭县| 青河县| 云阳县| 黄陵县| 株洲市|