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

首頁 > 編程 > JavaScript > 正文

ES6 Proxy實現Vue的變化檢測問題

2019-11-19 11:21:43
字體:
來源:轉載
供稿:網友

Vue變化檢測Object使用DefineProperty、數組使用方法攔截實現。最近,Vue3.0將采用ES6 Proxy的形式重新實現Vue的變化檢測,在官方還沒給出新方法之前,我們先實現一個基于Proxy的變化檢測。

模塊劃分

參照之前Vue變化檢測的代碼,將Vue 變化檢測的功能分為以下幾個部分。

  • Observer
  • Dep
  • Watcher
  • Utils

首先,我們要確定的問題是,將Dep依賴搜集存在哪里。Vue 2.x里,Object的依賴收集放在defineRactive,Array的依收集存入到Observer中。ES6 Proxy里,考慮到讓handler訪問dep,我們將依賴放入到Observer中。

Observer

observer.js功能代碼如下:

import Dep from './dep';import { isObject } from './utils';export default class Observer {  constructor (value) {    // 遞歸處理子元素    this.obeserve(value);    // 實現當前元素的代理    this.value = this.proxyTarget(value);  }  proxyTarget (targetBefore, keyBefore) {    const dep = new Dep();    targetBefore.__dep__ = dep;    let self = this;    const filtersAtrr = val => ['__dep__', '__parent__'].indexOf(val) > -1;    return new Proxy(targetBefore, {      get: function(target, key, receiver){        if (filtersAtrr(key)) return Reflect.get(target, key, receiver);        if (!Array.isArray(target)) {          dep.depend(key);        }        // sort/reverse等不改變數組長度的,在get里觸發        if (Array.isArray(target)) {          if ((key === 'sort' || key === 'reverse') && target.__parent__) {            target.__parent__.__dep__.notify(keyBefore);          }        }         return Reflect.get(target, key, receiver);      },      set: function(target, key, value, receiver){        if (filtersAtrr(key)) return Reflect.set(target, key, value, receiver);        // 新增元素,需要proxy        const { newValue, isChanged } = self.addProxyTarget(value, target, key, self);        // 設置key為新元素        Reflect.set(target, key, newValue, receiver);        // notify        self.depNotify(target, key, keyBefore, dep, isChanged);        return true;      },    });  }  addProxyTarget(value, target, key, self) {    let newValue = value;    let isChanged = false;    if (isObject(value) && !value.__parent__) {      self.obeserve(newValue);      newValue = self.proxyTarget(newValue, key);      newValue.__parent__ = target;      isChanged = true;    }    return {      newValue,      isChanged,    }  }  depNotify(target, key, keyBefore, dep, isChanged) {    if (isChanged && target.__parent__) {      target.__parent__.__dep__.notify(keyBefore);      return;    }    if (Array.isArray(target)) {      if (key === 'length' && target.__parent__) {        target.__parent__.__dep__.notify(keyBefore);      }    } else {      dep.notify(key);    }  }  obeserve(target) {    // 只處理對象類型,包括數組、對象    if (!isObject(target)) return;    for (let key in target) {      if (isObject(target[key]) && target[key] !== null) {        this.obeserve(target[key]);        target[key] = this.proxyTarget(target[key], key);        // 設置__parent__,方便子元素調用        target[key].__parent__ = target;      }    }  }}

在Observer中,針對對象,只需要執行 dep.depend(key) 、 dep.notify(key) 即可。添加 key 是為了能正確的觸發收集,不知道怎么說明白為什么要這樣做,只能一切盡在不言中了。

Array, 如何實現依賴的收集和觸發那。依賴收集與Object類似, dep.depend(key) 完成數組的收集。關于觸發,可以分為兩個方面,一是改變數組長度、二未改變數組長度的。改變數組長度的,在set里,通過長度屬性的設置觸發父級元素的notify。為什么要使用父級元素的notify那?我們可以分析以下,在你設置數組的長度時,這時候的target/key/value分別是[]/length*, 這個時候,數組的依賴收集是沒有的,你watcher的是數組,并不是數組本身。這個時候只能通過 target.__parent__.__dep__.notify(keyBefore) 觸發父級的收集,完成數據變化的檢測。二對于未改變數組長度的,這里的做法,雖然是直接 target.__parent__.__dep__.notify(keyBefore) 觸發依賴,但是有個嚴重的問題,實際上更新的數據不是最新的,這個地方暫時還沒想到比較好的方法,歡迎大家討論。

Dep

Dep.js

let uid = 0;export default class Dep {  constructor () {    this.subs = {};    this.id = uid++;  }  addSub(prop, sub) {    this.subs[prop] = this.subs[prop] || [];    this.subs[prop].push(sub);  }  removeSub(prop, sub) {    this.remove(this.subs[prop] || [], sub);  }  depend(prop) {    if (Dep.target) {      // 傳入的是當前依賴      Dep.target.addDep(prop, this)    }  }  notify(prop) {    const subs = (this.subs[prop] || []).slice();    for (let i = 0, l = subs.length; i < l; i++) {      subs[i].update();    }  }  remove(arr, item) {    if (arr.length) {      const index = arr.indexOf(item);      if (index > -1) {        return arr.splice(index, 1);      }    }  }}Dep.target = nullconst targetStack = []export function pushTarget (_target) {  if (Dep.target) targetStack.push(Dep.target)  Dep.target = _target}export function popTarget () {  Dep.target = targetStack.pop()}

dep 添加prop實現類型的綁定,為什么要這么做那?使用proxy代理后,你假如wahcter對象下的幾個元素,此時的deps將同時存在這幾個元素,你觸發依賴的時候,這些依賴都會執行。因此,通過key值綁定觀察事件,觸發時,能完成對象的正確觸發。

watcher、utils

import { parsePath } from './utils';import { pushTarget, popTarget } from './dep'export default class Watcher {  constructor(vm, expOrFn, cb) {    // dep id集合    this.depIds = new Set();    this.vm = vm;    this.getter = parsePath(expOrFn);    this.cb = cb;    this.value = this.get();  }  get () {    pushTarget(this);    let value = this.getter.call(this.vm, this.vm);    popTarget();    return value;  }  update() {    const oldValue = this.value;    this.value = this.get();    this.cb.call(this.vm, this.value, oldValue);  }  addDep (prop, dep) {    const id = dep.id;    if (!this.depIds.has(id)) {      this.depIds.add(id);      dep.addSub(prop, this);    }  }}

utils.js

/** * 解析簡單路徑 */const bailRE = /[^/w.$]/;export function parsePath (path) {  if (bailRE.test(path)) {    return;  }  const segments = path.split('.');  return function (obj) {    for (let i = 0; i < segments.length; i++) {      if (!obj) return;      obj = obj[segments[i]];    }    return obj;  };}/** * Define a property. */export function def (obj, key, val, enumerable) {  Object.defineProperty(obj, key, {    value: val,    enumerable: !!enumerable,    writable: true,    configurable: true  })}/** * Quick object check - this is primarily used to tell * Objects from primitive values when we know the value * is a JSON-compliant type. */export function isObject (obj) {  return obj !== null && typeof obj === 'object'}/** * Check whether an object has the property. */const hasOwnProperty = Object.prototype.hasOwnPropertyexport function hasOwn (obj, key) { return hasOwnProperty.call(obj, key)}

Utils.js/Watchers.js與Vue 2.x類似,這里就不多介紹了。

測試一下

test.js

import Observer from './observer';import Watcher from './watcher';let data = {  name: 'lijincai',  password: '***********',  address: {    home: '安徽亳州譙城區',  },  list: [{    name: 'lijincai',    password: 'you know it Object',  }], };const newData = new Observer(data);let index = 0;const watcherName = new Watcher(newData, 'value.name', (newValue, oldValue) => {  console.log(`${index++}: name newValue:`, newValue, ', oldValue:', oldValue);});const watcherPassword = new Watcher(newData, 'value.password', (newValue, oldValue) => {  console.log(`${index++}: password newValue:`, newValue, ', oldValue:', oldValue);});const watcherAddress = new Watcher(newData, 'value.address', (newValue, oldValue) => {  console.log(`${index++}: address newValue:`, newValue, ', oldValue:', oldValue);});const watcherAddressHome = new Watcher(newData, 'value.address.home', (newValue, oldValue) => {  console.log(`${index++}: address.home newValue:`, newValue, ', oldValue:', oldValue);});const watcherAddProp = new Watcher(newData, 'value.addProp', (newValue, oldValue) => {  console.log(`${index++}: addProp newValue:`, newValue, ', oldValue:', oldValue);});const watcherDataObject = new Watcher(newData, 'value.list', (newValue, oldValue) => {  console.log(`${index++}: newValue:`, newValue, ', oldValue:', oldValue);});newData.value.name = 'resetName';newData.value.password = 'resetPassword';newData.value.name = 'hello world name';newData.value.password = 'hello world password';newData.value.address.home = 'hello home';newData.value.address.home = 'hello home2';newData.value.addProp = 'hello addProp';newData.value.addProp ={  name: 'ceshi',};newData.value.addProp.name = 'ceshi2';newData.value.list.push('1');newData.value.list.splice(0, 1);newData.value.list.sort();newData.value.list.reverse();newData.value.list.push('1');newData.value.list.unshift({name: 'nihao'});newData.value.list[0] = {  name: 'lijincai',  password: 'you know it Array',};newData.value.list[0].name = 'you know it array after';newData.value.list.pop();newData.value.list.shift();newData.value.list.length = 1;

我們使用對象、數組測試一下我們的ES6 Proxy檢測。

20:17:44.725 index.js?afc7:20 0: name newValue: resetName , oldValue: lijincai20:17:44.725 index.js?afc7:24 1: password newValue: resetPassword , oldValue: ***********20:17:44.725 index.js?afc7:20 2: name newValue: hello world name , oldValue: resetName20:17:44.725 index.js?afc7:24 3: password newValue: hello world password , oldValue: resetPassword20:17:44.726 index.js?afc7:32 4: address.home newValue: hello home , oldValue: 安徽亳州譙城區20:17:44.726 index.js?afc7:32 5: address.home newValue: hello home2 , oldValue: hello home20:17:44.726 index.js?afc7:36 6: addProp newValue: hello addProp , oldValue: undefined20:17:44.727 index.js?afc7:36 7: addProp newValue: Proxy {name: "ceshi", __dep__: Dep, __parent__: {…}} , oldValue: hello addProp20:17:44.727 index.js?afc7:40 0: newValue: Proxy {0: Proxy, 1: "1", __dep__: Dep, __parent__: {…}} , oldValue: Proxy {0: Proxy, 1: "1", __dep__: Dep, __parent__: {…}}20:17:44.728 index.js?afc7:40 1: newValue: Proxy {0: "1", __dep__: Dep, __parent__: {…}} , oldValue: Proxy {0: "1", __dep__: Dep, __parent__: {…}}20:17:44.729 index.js?afc7:40 2: newValue: Proxy {0: "1", __dep__: Dep, __parent__: {…}} , oldValue: Proxy {0: "1", __dep__: Dep, __parent__: {…}}20:17:44.731 index.js?afc7:40 3: newValue: Proxy {0: "1", __dep__: Dep, __parent__: {…}} , oldValue: Proxy {0: "1", __dep__: Dep, __parent__: {…}}20:17:44.734 index.js?afc7:40 4: newValue: Proxy {0: "1", 1: "1", __dep__: Dep, __parent__: {…}} , oldValue: Proxy {0: "1", 1: "1", __dep__: Dep, __parent__: {…}}20:17:44.735 index.js?afc7:40 5: newValue: Proxy {0: Proxy, 1: "1", 2: "1", __dep__: Dep, __parent__: {…}} , oldValue: Proxy {0: Proxy, 1: "1", 2: "1", __dep__: Dep, __parent__: {…}}20:17:44.735 index.js?afc7:40 6: newValue: Proxy {0: Proxy, 1: "1", 2: "1", __dep__: Dep, __parent__: {…}} , oldValue: Proxy {0: Proxy, 1: "1", 2: "1", __dep__: Dep, __parent__: {…}}20:17:44.736 index.js?afc7:40 7: newValue: Proxy {0: Proxy, 1: "1", 2: "1", __dep__: Dep, __parent__: {…}} , oldValue: Proxy {0: Proxy, 1: "1", 2: "1", __dep__: Dep, __parent__: {…}}20:17:44.737 index.js?afc7:40 8: newValue: Proxy {0: Proxy, 1: "1", __dep__: Dep, __parent__: {…}} , oldValue: Proxy {0: Proxy, 1: "1", __dep__: Dep, __parent__: {…}}20:17:44.738 index.js?afc7:40 9: newValue: Proxy {0: "1", __dep__: Dep, __parent__: {…}} , oldValue: Proxy {0: "1", __dep__: Dep, __parent__: {…}}20:17:44.738 index.js?afc7:40 10: newValue: Proxy {0: "1", __dep__: Dep, __parent__: {…}} , oldValue: Proxy {0: "1", __dep__: Dep, __parent__: {…}}

我們看到了ES6 Proxy后實現了Object/Array的檢測,雖然還存在一些問題,但是基本的偵測變化的功能都已經具備了。

總結

以上所述是小編給大家介紹的ES6 Proxy實現Vue的變化檢測問題,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對武林網網站的支持!
如果你覺得本文對你有幫助,歡迎轉載,煩請注明出處,謝謝!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
一个人看的www欧美| 国产成人精品网站| 国产中文日韩欧美| 日韩中文字幕免费| 国产网站欧美日韩免费精品在线观看| www高清在线视频日韩欧美| 欧美xxxx18性欧美| 亚洲人在线观看| 在线成人激情视频| 在线观看欧美视频| 中文字幕综合一区| 久久久视频免费观看| 国产香蕉精品视频一区二区三区| 国产精品久久久精品| 亚洲影院色无极综合| 亚洲少妇中文在线| 亚洲片av在线| 91亚洲精品在线| 日韩在线视频国产| 国产精品夫妻激情| 国产亚洲激情视频在线| 久久精品99久久久久久久久| 亚洲男人天堂2023| 尤物tv国产一区| 91国偷自产一区二区三区的观看方式| 自拍偷拍亚洲一区| 欧美成人免费全部观看天天性色| 亚洲一区制服诱惑| 欧美黑人一级爽快片淫片高清| 日韩中文综合网| 深夜精品寂寞黄网站在线观看| 日韩视频欧美视频| 欧美wwwwww| 中文字幕精品影院| 91亚洲人电影| 久久香蕉国产线看观看网| 7m精品福利视频导航| 欧美福利视频在线观看| 欧美成人午夜剧场免费观看| 亚洲aa中文字幕| 精品视频久久久| 久久网福利资源网站| 欧洲亚洲在线视频| 日韩中文理论片| 亚洲激情在线观看| 成人a级免费视频| 欧美肥老妇视频| 国产精品视频yy9099| 亚洲自拍中文字幕| 国产精品成人一区| 亚洲国产精品系列| 国产偷亚洲偷欧美偷精品| 国产精品成人av性教育| 亚洲精品国产精品乱码不99按摩| 亚洲一区二区免费在线| 色哟哟入口国产精品| 久久久久久久国产| 中文字幕亚洲专区| 国产不卡在线观看| 日韩一级裸体免费视频| 国产91精品黑色丝袜高跟鞋| 欧美性xxxxxxx| 国产精品视频导航| 欧美极品少妇xxxxⅹ喷水| 精品视频久久久久久久| 一区二区三区视频在线| 国产精品久久久久久久久久99| 91av福利视频| 国产精品91一区| 欧美一区二区三区图| 国产精品视频久久久久| 久久精品久久久久电影| 亚洲japanese制服美女| 国产精品久久久久久久久久久久久久| 国产精品视频导航| 日本精品久久中文字幕佐佐木| 一个人看的www欧美| 国内免费久久久久久久久久久| 一夜七次郎国产精品亚洲| 欧美大片免费看| 精品女同一区二区三区在线播放| 亚洲伊人久久大香线蕉av| 欧美一区二区色| 欧美视频免费在线| 亚洲精品国产精品国自产观看浪潮| 亚洲精品日韩激情在线电影| 尤物九九久久国产精品的分类| 欧美精品在线看| 欧美日韩国产一中文字不卡| 日韩在线观看成人| 青草成人免费视频| 韩剧1988在线观看免费完整版| 一区二区三区国产视频| 亚洲欧美日韩精品久久奇米色影视| 亚洲一区二区三区成人在线视频精品| 国产精品综合网站| 亚洲第一综合天堂另类专| 久久久伊人日本| 精品一区二区亚洲| 久久久中精品2020中文| 欧美亚洲成人精品| 久久久久国产精品www| 久久人人爽人人爽爽久久| 国产精品欧美一区二区| 8050国产精品久久久久久| 欧美性生活大片免费观看网址| 欧美性感美女h网站在线观看免费| 国产大片精品免费永久看nba| 国产精品久久久久久久久久久不卡| 国产精品盗摄久久久| 欧美成人亚洲成人日韩成人| 国产精品一区二区三区毛片淫片| 日韩hd视频在线观看| 亚洲字幕一区二区| 欧美黑人性猛交| xvideos成人免费中文版| 久久偷看各类女兵18女厕嘘嘘| 精品国产一区二区三区久久狼黑人| 久久中文字幕在线视频| 久久精品国产96久久久香蕉| 成人综合国产精品| 国内精品国产三级国产在线专| 91精品久久久久久久久不口人| 国产精品777| 亚洲欧美一区二区三区在线| 一本色道久久88亚洲综合88| 91精品视频在线| 国产精品免费久久久久久| 中文字幕欧美国内| 国产激情综合五月久久| 日韩国产欧美精品一区二区三区| 欧美日韩加勒比精品一区| 亚洲欧美日韩高清| 欧美日韩国产在线| 日韩69视频在线观看| 国产精品久久久久免费a∨| 国模精品视频一区二区三区| 精品亚洲一区二区三区四区五区| 日韩av电影在线免费播放| 国产精品成人播放| 亚洲一区二区三区视频播放| 久久久国产精品亚洲一区| 欧美大片免费观看| 91av在线看| 亚洲国产精品福利| 色999日韩欧美国产| 亚洲视频axxx| 欧美日韩国产精品| 日韩免费av一区二区| 在线观看91久久久久久| 久久久久国产精品免费| 国产亚洲视频在线| 日韩在线观看免费| 欧美激情三级免费| 成人免费观看网址| 日韩av中文在线| 日韩禁在线播放| 26uuu国产精品视频| 国产噜噜噜噜噜久久久久久久久| 久久精品视频播放| 久久中文字幕国产| 国产欧美韩国高清| 成人免费淫片aa视频免费| 国产日韩在线播放|