Vue中数组变动监听
var obj = { __x: 1 };
Object.defineProperty(obj,"x",{
set: function(x){ console.log("watch"); this.__x = x; },get: function(){ return this.__x; }
});
obj.x = 11; // watch
console.log(obj.x); // 11
var obj = { __x: [1,2,3] };
Object.defineProperty(obj,get: function(){ return this.__x; }
});
obj.x[0] = 11;
console.log(obj.x); // [11,3]
obj.x = [1,3,4,5,6]; // watch
console.log(obj.x); // [1,6]
obj.x.push(7);
console.log(obj.x); // [1,6,7]
// 通过下标对每一个值进行劫持
var obj = { __x: [1,get: function(){ return this.__x; }
});
obj.x.forEach((v,i) => {
Object.defineProperty(obj.x,i,{
set:function(x) { console.log("watch"); v = x; },get: function(){ return v; }
})
})
obj.x[0] = 11; // watch
console.log(obj.x); // [11,3]
<!DOCTYPE html>
<html>
<head>
<title>Vue中数组变动监听</title>
</head>
<body>
<div id="app"></div>
</body>
<script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: '#app',data: {
msg: [1,3]
},template:`
<div>
<div v-for="item in msg" :key="item">{{item}}</div>
<button @click="subscript">subscript</button>
<button @click="push">push</button>
</div>
`,methods:{
subscript: function(){
this.msg[0] = 11;
console.log(this.msg); // [11,__ob__: Observer]
},push: function(){
this.msg.push(4,6);
console.log(this.msg); // [1,__ob__: Observer]
}
}
})
</script>
</html>
// dev/src/core/observer/array.js
/*
* not type checking this file because flow doesn't play well with
* dynamically accessing methods on Array prototype
*/
import { def } from '../util/index'
const arrayProto = Array.prototype
export const arrayMethods = Object.create(arrayProto)
const methodsToPatch = [
'push','pop','shift','unshift','splice','sort','reverse'
]
/**
* Intercept mutating methods and emit events
*/
methodsToPatch.forEach(function (method) {
// cache original method
const original = arrayProto[method]
def(arrayMethods,method,function mutator (...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 change
ob.dep.notify()
return result
})
})
重赋值
var obj = { __x: [1,get: function(){ return this.__x; }
});
obj.x[0] = 11;
obj.x = obj.x; // watch
console.log(obj.x); // [11,3]
obj.x[0] = 111;
obj.x = [].concat(obj.x); // watch
console.log(obj.x); // [111,3]
obj.x[0] = 1111;
obj.x = obj.x.slice(); // watch
console.log(obj.x); // [1111,3]
obj.x[0] = 11111;
obj.x = obj.x.splice(0,obj.x.length); // watch
console.log(obj.x); // [11111,3]
Proxy
var target = [1,3];
var proxy = new Proxy(target,{
set: function(target,key,value,receiver){
console.log("watch");
return Reflect.set(target,receiver);
},get: function(target,receiver){
return target[key];
}
});
proxy[0] = 11; // watch
console.log(target); // [11,3]
https://github.com/WindrunnerMax/EveryDay
https://zhuanlan.zhihu.com/p/50547367
https://juejin.im/post/6844903699425263629
https://juejin.im/post/6844903597591773198
https://segmentfault.com/a/1190000015783546
https://cloud.tencent.com/developer/article/1607061
https://www.cnblogs.com/tugenhua0707/p/11754291.html
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy