欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

Vue偵測相關api的實現

Vue偵測相關api的實現?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。

創(chuàng)新互聯自2013年創(chuàng)立以來,公司以成都網站設計、做網站、成都外貿網站建設公司、系統開發(fā)、網絡推廣、文化傳媒、企業(yè)宣傳、平面廣告設計等為主要業(yè)務,適用行業(yè)近百種。服務企業(yè)客戶上千多家,涉及國內多個省份客戶。擁有多年網站建設開發(fā)經驗。為企業(yè)提供專業(yè)的網站建設、創(chuàng)意設計、宣傳推廣等服務。 通過專業(yè)的設計、獨特的風格,為不同客戶提供各種風格的特色服務。

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 時,就會直接進行執(zhí)行回調函數

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 = 0
class 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)
    }
  }
}

分析

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

deep

需要明白的是

  1. deep 干啥用的,例如 data = {arr: [1, 2, {b: 6]} ,當我們只是監(jiān)聽 data.arr 時,在 [1, 2, {b: 66}] 這個數值內部發(fā)生變化時,也需要觸發(fā),即 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,并執(zhí)行 get

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

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

  2. seenObjects.clear() 當內部所以類型數據都添加好其依賴后,就清空。

  3. window.target = undefined 消除依賴

vm.$set

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

作用

  1. 對于數組,進行 set 則是添加新元素,并需要觸發(fā)依賴更新

  2. 對于對象,如果 key 值存在,則是修改 value ;不存在,則是添加新元素,需新元素要進行響應式處理,以及觸發(fā)更新

  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  //觸發(fā)set,執(zhí)行依賴更新
    return val
  }
  const ob = target._ob_
  if(target.isVue || (ob && ob.vm.Count) { //不是vue實例也不是vue實例的根對象(即不是this.$data跟對象)
    //觸發(fā)警告
    return
  }
  if(!ob) {  //只添加
    target[key] = val
    return val
  }
  defineReactive(ob.value, key, val) //進行響應式處理
  ob.dep.notify() //觸發(fā)依賴更新
  returnv val
}

vm.$delete

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

作用

  1. 對于數組,進行 delete 則是刪除新元素,并需要觸發(fā)依賴更新

  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跟對象)
    //觸發(fā)警告
    return
  }
  if(!hasOwn(target, key)) {
    return
  }
  delete target[key]
  if(!ob) {
    return
  }
  ob.dep.notify()
}

看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注創(chuàng)新互聯行業(yè)資訊頻道,感謝您對創(chuàng)新互聯的支持。

本文名稱:Vue偵測相關api的實現
分享網址:http://www.chinadenli.net/article42/jogghc.html

成都網站建設公司_創(chuàng)新互聯,為您提供商城網站營銷型網站建設Google關鍵詞優(yōu)化軟件開發(fā)企業(yè)建站

廣告

聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯

成都網站建設公司