国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 語言 > JavaScript > 正文

Vue偵測相關api的實現方法

2024-05-06 15:39:08
字體:
來源:轉載
供稿:網友

vm.$watch

用法: vm.$watch( expOrFn, callback, [options] ) ,返回值為 unwatch 是一個函數用來取消觀察;下面主要理解 options 中的兩個參數 deep 和 immediate 以及 unwatch

Vue.prototype.$watch = function (expOrFn, cb, options) {  const vm = this  options = options || {}  const watcher = new Watcher(vm, expOrFn, cb, options)   if(options.immediate) {    cb.call(vm, watcher,.value)  }  return function unwatchFn() {    watcher.teardown()  }}

immediate

從上面代碼中可以看出當 immediate 為 true 時,就會直接進行執行回調函數

unwatch

實現方式是:

    將被訪問到的數據 dep 收集到 watchs 實例對象上,通過 this.deps 存起來 將被訪問到的數據 dep.id 收集到 watchs 實例對象上,通過 this.depIds 存起來 最后通過 watchs 實例對象的 teardown 進行刪除
class Watcher {  constructor (vm, expOrFn, cb) {    this.vm = vm    this.deps = []    this.depIds = new Set()    if(typeof expOrFn === 'function') {      this.getter = expOrFn    }else {      this.getter = parsePath(expOrFn)    }    this.cb = cb    this.value = this.get()  }  ....  addDep (dep) {    const id = dep.id       //參數dep是Dep實例對象    if(!this.depIds.has(id)) {  //判斷是否存在避免重復添加      this.depIds.add(id)          this.deps.push(dep)      dep.addSub(this)     //this 是依賴    }  }  teardown () {    let i = this.deps.length    while (i--) {      this.deps[i].removeSub(this)    }  }}let uid = 0class Dep {  constructor () {    this.id = uid++    ...  }  ...  depend () {    if(window.target) {      window.target.addDep(this)  //將this即當前dep對象加入到watcher對象上    }  }  removeSub (sub) {    const index = this.subs.indexOf(sub)    if(index > -1) {      return this.subs.splice(index, 1)    }  }}

分析

當執行 teardown() 時需要循環;因為例如 expOrFn = function () { return this.name + this.age } ,這時會有兩個 dep 分別是 name 與 age 分別都加入了 watcher 依賴( this ),都會加入到 this.deps 中,所以需要循環將含有依賴的 dep 都刪除其依賴

deep

需要明白的是

    deep 干啥用的,例如 data = {arr: [1, 2, {b: 6]} ,當我們只是監聽 data.arr 時,在 [1, 2, {b: 66}] 這個數值內部發生變化時,也需要觸發,即 b = 888

怎么做呢?

class Watcher {  constructor (vm, expOrFn, cb, options) {    this.vm = vm    this.deps = []    this.depIds = new Set()    if(typeof expOrFn === 'function') {      this.getter = expOrFn    }else {      this.getter = parsePath(expOrFn)    }    if(options) {          //取值      this.deep = !!options.deep    }else {      this.deep = false    }    this.cb = cb    this.value = this.get()  }  get () {    window.target = this    let value = this.getter.call(vm, vm)    if(this.deep) {      traverse(value)    }    window.target = undefined    return value  }  ...}const seenObjects = new Set()function traverse (val) {  _traverse(val, seenObjects)  seenObjects.clear()}function _traverse(val, seen) {  let i, keys  const isA = Array.isArray(val)  if((!isA && isObject(val)) || Object.isFrozen(val)) { //判斷val是否是對象或者數組以及是否被凍結    return  }  if(val._ob_) {    const depId = val._ob_.dep.id   //可以看前面一篇我們對Observer類添加了this.dep = new Dep(),所以能訪問其dep.id    if(seen.has(depId)) {      return    }    seen.add(depId)  }  if(isA) {    i = val.length    while (i--) _traverse(val[i], seen)  } else {    keys = Object.keys(val)    i = keys.length    while (i--) _traverse(val[i], seen)  }}            
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

主站蜘蛛池模板: 三河市| 临泽县| 遂昌县| 舟山市| 民勤县| 石柱| 平武县| 揭东县| 大姚县| 四子王旗| 浪卡子县| 长治县| 敖汉旗| 江西省| 黄龙县| 拉萨市| 崇信县| 蚌埠市| 长治市| 江北区| 德庆县| 黄浦区| 平定县| 金门县| 泰来县| 长垣县| 赤城县| 泾阳县| 伊通| 瓮安县| 阳江市| 嘉义市| 沂南县| 肥城市| 伊川县| 佳木斯市| 乌鲁木齐县| 都昌县| 英山县| 肥西县| 东平县|