VUE - MVVM - part6 - Array
6925 ワード
この文章を読む前に、前の文章を見たことがなければ、文章の末尾に引っ張って前の文章を見ることができます.
レビュー
前のいくつかの呼び出し方法: 直接付与: 解決行為一
まず、配列の下のいくつかの方法が元の配列に影響を与えることを知っています.以下のいくつかがあります. push pop shift unshift splice sort reverse
これらの方法は総じていくつかの影響を及ぼします.配列長が変化する 配列内の要素の順序が変化する オブジェクトとは異なり、オブジェクトの
すなわち、いくつかの方法がトリガーされると、
しかし、現在実装されているコード(
上記のいくつかの配列方法は配列オブジェクトによって提供され、
まず、配列に
同様に
OK私たちは今依存の追加を完了し、残りは依存のトリガを実現します.
処理方法:配列オブジェクトが特定のメソッドを呼び出すときに、まず見つけたのは私たちが自分で書いたメソッドであり、このメソッドでは元のメソッドが呼び出され、依存がトリガーされます.
まず、方法を包装して、同名の方法を得ます.
OK私たちは今いくつかの列の同名の方法を得ました.私は呼び出し時に、まず私たちの方法を呼び出すことを確保すればいいです.
次の2つの方法があります.配列オブジェクトに直接この方法があるので、オブジェクト上のプロトタイプチェーン を探すことができない.はオブジェクトの を見つけます.
具体的には、コードの実装:
テスト:
これまで,配列呼び出しメソッドの際に依存を追加しトリガすることに成功した.
解決行為2
まず、配列の下のインデックスは、オブジェクトの下のキーと同様の表現であり、つまり
しかし、
テスト:
現在では、完全なデータ傍受モデルも完了し、
値を設定すると依存が正常にトリガーされます.
クリックして関連コードを表示
シリーズ記事アドレス VUE - MVVM - part1 - defineProperty VUE - MVVM - part2 - Dep VUE - MVVM - part3 - Watcher VUE-MVVM-part 4-最適化Watcher VUE - MVVM - part5 - Observe VUE - MVVM - part6 - Array VUE - MVVM - part7 - Event VUE-MVVM-part 8-最適化Event VUE - MVVM - part9 - Vue VUE - MVVM - part10 - Computed VUE - MVVM - part11 - Extend VUE - MVVM - part12 - props VUE-MVVM-part 13-inject&総括
レビュー
前のいくつかの
step
では,オブジェクトの属性の傍受を実現したが,配列に関する挙動はずっと処理されていない.まず、配列にどのような動作をもたらすかを分析します.arr.splice(1, 2, 'something1', 'someting2')
arr[1] = 'something'
まず、配列の下のいくつかの方法が元の配列に影響を与えることを知っています.以下のいくつかがあります.
これらの方法は総じていくつかの影響を及ぼします.
key
値の順序が変化した場合、ビューの変化には影響しませんが、配列の順序が変化した場合、ビューは変化します.すなわち、いくつかの方法がトリガーされると、
Dep
のnotify
関数をトリガーするビューの更新が必要になります.しかし、現在実装されているコード(
step5
のコード)を見ると、配列にDep
を提供するわけではありません.上記のいくつかの配列方法は配列オブジェクトによって提供され、
Dep
の下のnotify
関数をトリガする方法を考えなければならない.まず、配列に
Dep
、完全なObserver
を提供します.export class Observer {
constructor(value) {
this.value = value
if (Array.isArray(value)) {
// Dep
this.dep = new Dep()
this.observeArray(value)
} else {
this.walk(value)
}
Object.defineProperty(value, '__ob__', {
value: this,
enumerable: false,
writable: true,
configurable: true
})
}
/**
* ,
*/
walk(obj) {
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i], obj[keys[i]])
}
}
/**
* ,
*/
observeArray (items) {
for (let i = 0, l = items.length; i < l; i++) {
observe(items[i])
}
}
}
同様に
defineReactive
で配列追加依存論理を処理する必要がありますexport function defineReactive(object, key, value) {
let dep = new Dep()
let childOb = observe(value)
Object.defineProperty(object, key, {
configurable: true,
enumerable: true,
get: function () {
if (Dep.target) {
dep.addSub(Dep.target)
Dep.target.addDep(dep)
//
if(Array.isArray(value)){
childOb.dep.addSub(Dep.target)
Dep.target.addDep(childOb.dep)
}
}
return value
},
set: function (newValue) {
if (newValue !== value) {
value = newValue
dep.notify()
}
}
})
}
OK私たちは今依存の追加を完了し、残りは依存のトリガを実現します.
処理方法:配列オブジェクトが特定のメソッドを呼び出すときに、まず見つけたのは私たちが自分で書いたメソッドであり、このメソッドでは元のメソッドが呼び出され、依存がトリガーされます.
まず、方法を包装して、同名の方法を得ます.
const arrayProto = Array.prototype
//
export const arrayMethods = Object.create(arrayProto)
const methodsToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
/**
* ,
*/
methodsToPatch.forEach(function (method) {
//
const original = arrayProto[method]
let mutator = function (...args) {
const result = original.apply(this, args)
const ob = this.__ob__
let inserted
switch (method) {
case 'push':
case 'unshift':
inserted = args
break
case 'splice':
inserted = args.slice(2)
break
}
//
if (inserted) ob.observeArray(inserted)
// notify
ob.dep.notify()
return result
}
Object.defineProperty(arrayMethods, method, {
value: mutator,
enumerable: false,
writable: true,
configurable: true
})
})
OK私たちは今いくつかの列の同名の方法を得ました.私は呼び出し時に、まず私たちの方法を呼び出すことを確保すればいいです.
次の2つの方法があります.
__proto__
をカバーし、プロトタイプチェーンを探すときに、まず私たちの方法具体的には、コードの実装:
export class Observer {
constructor(value) {
this.value = value
if (Array.isArray(value)) {
this.dep = new Dep()
const augment = ('__proto__' in {})
? protoAugment
: copyAugment
// ,
augment(value, arrayMethods, arrayKeys)
this.observeArray(value)
} else {
this.walk(value)
}
...
}
...
}
/**
* __proto__
*/
function protoAugment (target, src, keys) {
target.__proto__ = src
}
/**
* __proto__
*/
function copyAugment (target, src, keys) {
for (let i = 0, l = keys.length; i < l; i++) {
const key = keys[i]
Object.defineProperty(target, key, {
value: src[key],
enumerable: false,
writable: true,
configurable: true
})
}
}
テスト:
let object = {
arrayTest: [1, 2, 3, 4, 5]
}
observe(object)
let watcher = new Watcher(object, function () {
return this.arrayTest.reduce((sum, num) => sum + num)
}, function (newValue, oldValue) {
console.log(` , = ${newValue}`)
})
object.arrayTest.push(10)
// , = 25
これまで,配列呼び出しメソッドの際に依存を追加しトリガすることに成功した.
解決行為2
まず、配列の下のインデックスは、オブジェクトの下のキーと同様の表現であり、つまり
defineReactive
でインデックス値を処理することができるが、配列は一連の値を格納するために用いられ、最初から配列の長さを決定することはできず、最初から配列の長さが0
である可能性が高く、その後も配列中のインデックスに対応する内容が変化し続ける可能性が高いことを説明する.したがって、インデックスに対してdefineReactive
を呼び出すのは現実的ではない.しかし、
arr[1] = 'something'
のような付与値は配列においても一般的な動作であり、Vue
において$set
の具体的な詳細が実現されている.ここでは、配列オブジェクトの下に1つの方法を追加するだけでよい別の方法が実現されている.arrayMethods.$apply = function () {
this.__ob__.observeArray(this)
this.__ob__.dep.notify()
}
テスト:
object.arrayTest[1] = 10
object.arrayTest.$apply()
// , = 33
現在では、完全なデータ傍受モデルも完了し、
observe
法を用いて傍受可能な構造を得ることができ、その後、Watcher
で依存性を追加することができる.値を設定すると依存が正常にトリガーされます.
クリックして関連コードを表示
シリーズ記事アドレス