亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

Vue偵測相關api的實現方法

2019-11-19 11:30:15
字體:
來源:轉載
供稿:網友

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

實現方式是:

  1. 將被訪問到的數據 dep 收集到 watchs 實例對象上,通過 this.deps 存起來
  2. 將被訪問到的數據 dep.id 收集到 watchs 實例對象上,通過 this.depIds 存起來
  3. 最后通過 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

需要明白的是

  1. 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)  }}

分析

  1. window.target = this ,寄存依賴
  2. let value = this.getter.call(vm, vm) 訪問當前val,并執行 get

的 dep.depend() ,如果發現 val 為數組,則將依賴加入到 observer 的 dep 中,也就實現了對當前數組的攔截

  1. traverse(value) 也就是執行 _traverse(val, seenObjects) ;核心就是對被 Observer 的 val 通過 val[i] 通過這種操作,間接觸發 get ,將依賴添加到當前數值的 dep 中,這樣也就實現了,當內部數據發生變化,也會循環 subs 執行依賴的 update ,從而觸發回調;當是數組時,只需進行遍歷,看內部是否有 Object 對象即可,因為在第二步的時候,會對 val 進行判斷是否是數組,變改變七個方法的value,在遍歷;所以這邊只要是內部數組都會進行攔截操作,添加依賴,即對象 {} 這種沒沒添加依賴。
  2. seenObjects.clear() 當內部所以類型數據都添加好其依賴后,就清空。
  3. window.target = undefined 消除依賴

vm.$set

用法: vm.$set(target, key, value)

作用

  1. 對于數組,進行 set 則是添加新元素,并需要觸發依賴更新
  2. 對于對象,如果 key 值存在,則是修改 value ;不存在,則是添加新元素,需新元素要進行響應式處理,以及觸發更新
  3. 對于對象本身不是響應式,則直接添加 key-value ,無需處理
Vue.prototype.$set = function (target, key, val) {  if(Array.isArray(target) && isValidArrayIndex(key)) {  //是數組并且key有效    target.length = Math.max(target.length, key)  //處理key > target.length    target.splice(key, 1, val)  //添加新元素,并輸出依賴更新同時新元素也會進行`Obsever`處理    return val  }  if(key in targert && !(key in Object.prototype) { //能遍歷并且是自身key    target[key] = val  //觸發set,執行依賴更新    return val  }  const ob = target._ob_  if(target.isVue || (ob && ob.vm.Count) { //不是vue實例也不是vue實例的根對象(即不是this.$data跟對象)    //觸發警告    return  }  if(!ob) {  //只添加    target[key] = val    return val  }  defineReactive(ob.value, key, val) //進行響應式處理  ob.dep.notify() //觸發依賴更新  returnv val}

vm.$delete

用法: vm.$delete( target, key)

作用

  1. 對于數組,進行 delete 則是刪除新元素,并需要觸發依賴更新
  2. 對于對象,如果 key 值不存在,直接 return ,存在,刪除元素,
  3. 對于對象本身不是響應式,則只刪除 key-value ,無需其他處理
Vue.prototype.$delete = function (target, key) {  if(Array.isArray(target) && isValidArrayIndex(key)) {    target.splice(key, 1)    return  }  const ob = target._ob_  if(target.isVue || (ob && ob.vm.Count) { //不是vue實例也不是vue實例的根對象(即不是this.$data跟對象)    //觸發警告    return  }  if(!hasOwn(target, key)) {    return  }  delete target[key]  if(!ob) {    return  }  ob.dep.notify()}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲黄色有码视频| 日韩午夜在线视频| 美女久久久久久久| 精品成人69xx.xyz| 日韩欧美高清在线视频| 热99在线视频| 亚洲精品国产精品国自产观看浪潮| 国产欧美精品久久久| 91久久精品一区| 亚洲国产精彩中文乱码av| 亚洲性视频网址| 亚洲欧美中文日韩v在线观看| 亚洲视频在线看| 日韩精品久久久久| 亚洲丝袜av一区| 欧美日韩国产精品专区| 成人h视频在线观看播放| 九九热精品在线| 国产一区红桃视频| 国产精品欧美在线| 久久欧美在线电影| 欧美一级淫片videoshd| 日本成人黄色片| 91亚洲国产成人精品性色| 91啪国产在线| 黄色一区二区在线| 国产伊人精品在线| 日韩综合中文字幕| 欧美在线一区二区视频| 欧美精品999| 韩剧1988免费观看全集| 一区二区三区 在线观看视| 97视频在线观看亚洲| 亚洲韩国青草视频| 欧美日韩中文字幕在线视频| 亚洲国产日韩欧美在线动漫| 日韩激情在线视频| 国产视频自拍一区| 97人人模人人爽人人喊中文字| 丝袜一区二区三区| 高清欧美一区二区三区| 亚洲字幕一区二区| 欧美一区二区三区……| 色偷偷av一区二区三区乱| 国产一区二区香蕉| 国产九九精品视频| 国产日韩精品在线播放| 国产精品电影网| 欧美裸体xxxx极品少妇| 久久久久久久久久久人体| 国产欧美久久一区二区| 亚洲一区二区三区四区视频| 超碰日本道色综合久久综合| 久久久久久久香蕉网| 亚洲成人网av| 亚洲色图校园春色| 国产精品99久久久久久久久久久久| 久久久久一本一区二区青青蜜月| 国产精品第2页| 日韩av在线一区二区| 久久久久久久亚洲精品| 97视频免费在线观看| 国产日韩av在线播放| 国产精品第10页| 日韩在线欧美在线| 精品动漫一区二区三区| 日韩成人在线免费观看| 91九色国产视频| 538国产精品视频一区二区| 91视频免费在线| 国产偷国产偷亚洲清高网站| 综合网中文字幕| 不卡av日日日| 这里只有视频精品| 欧美黑人xxx| 热re91久久精品国99热蜜臀| 色综合久久久久久中文网| 一区二区欧美激情| 久久视频在线观看免费| 亚洲品质视频自拍网| 国产成人91久久精品| 色999日韩欧美国产| 97在线视频观看| 久久久免费高清电视剧观看| 亚洲欧美制服综合另类| 欧美黑人狂野猛交老妇| 国产精品久久久久久av| 久久久视频免费观看| 日韩最新中文字幕电影免费看| 91亚洲精品在线| 国产精品海角社区在线观看| 欧美性开放视频| 亚洲欧洲一区二区三区在线观看| 亚洲欧美日本另类| 91久久中文字幕| 懂色av中文一区二区三区天美| 国产视频综合在线| 国产精品免费一区豆花| 成人免费xxxxx在线观看| 欧美疯狂xxxx大交乱88av| 日韩亚洲一区二区| 亚洲男女自偷自拍图片另类| 亚洲国产91精品在线观看| 亚洲男人天堂九九视频| 亚洲国产日韩欧美综合久久| 欧美www视频在线观看| 亚洲成人av中文字幕| 免费91麻豆精品国产自产在线观看| 欧美成人免费全部| 亚洲美女喷白浆| 久久久久久中文字幕| 亚洲欧美日本精品| 国产丝袜一区二区| 亚洲国产成人精品女人久久久| 欧美性猛交xxxx偷拍洗澡| 狠狠躁天天躁日日躁欧美| 久久久国产精彩视频美女艺术照福利| 国产精品专区h在线观看| 欧美另类xxx| 91精品在线观| 精品福利一区二区| 777精品视频| 亚洲自拍欧美色图| 福利视频第一区| 国产成人精品视频在线观看| 欧美一级大片在线观看| 国产精品高潮呻吟久久av野狼| 久久精品国产亚洲精品| 日本精品免费一区二区三区| 亚洲男人天堂2024| 高清亚洲成在人网站天堂| 日本高清视频一区| 精品久久久久久久久久国产| 亚洲二区在线播放视频| 欧美日韩美女在线观看| 国产精品极品尤物在线观看| 成人免费高清完整版在线观看| 国产精品久久久999| 国产精品久久久久久久久粉嫩av| 日韩精品免费在线视频| 91免费精品国偷自产在线| 欧美一区二粉嫩精品国产一线天| www.亚洲成人| 26uuu久久噜噜噜噜| 国产成人精品一区二区| 亚洲综合在线小说| 欧美孕妇与黑人孕交| 中文综合在线观看| 欧美性资源免费| 国产精品偷伦视频免费观看国产| 久久天堂电影网| 国语自产精品视频在线看| 九九精品在线观看| 亚洲成人免费网站| 欧美孕妇毛茸茸xxxx| 成人网在线视频| 国产精品夜色7777狼人| 91a在线视频| 国产亚洲精品美女久久久| 成人xvideos免费视频| 懂色aⅴ精品一区二区三区蜜月| 欧美孕妇毛茸茸xxxx| 欧美成人在线免费视频| 亚洲欧洲午夜一线一品|