console
/*Object的变化侦测*/
//对象的属性拦截
const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto);
function defineReactive(data,key,val){
if(typeof val === 'object'){
new Observer(val)
}
let childOb = observe(val)
let dep = new Dep();
Object.defineProperty(data,key,{
enumerable:true,
configurable:true,
get:function(){
dep.depend()
if(childOb){
// console.log("--get--")
// console.log(childOb)
childOb.dep.depend()
}
return val;
},
set:function(newVal){
console.log("--set--")
console.log(newVal)
console.log(dep)
if(val === newVal){
return
}
val = newVal
dep.notify()
}
})
}
//依赖收集在哪里
class Dep{
constructor(){
this.subs = [];
}
addSub(sub){
this.subs.push(sub)
}
removeSub(sub){
remove(this.subs,sub)
}
depend(){
if(window.target){
this.addSub(window.target)
}
}
notify(){
console.log("3-1")
// console.log(this.subs)
const subs = this.subs.slice()
// console.log(subs)
for(let i =0;i <subs.length;i++){
subs[i].update()
}
}
}
function remove(arr,item){
if(arr.length){
const index = arr.indexOf(item)
if(index >-1){
return arr.splice(index,1)
}
}
}
//依赖类
class Watcher {
constructor(vm,expOrFn,cb){
// console.log("2-1")
//vm是数据对象value
//expOrFn是key
//cb是回调函数
this.vm = vm;
this.getter = parsePath(expOrFn);
//this.getter为返回函数A
this.cb = cb;
this.value = this.get();
}
get(){
window.target = this;
let value = this.getter.call(this.vm,this.vm)
window.target = undefined;
return value
}
update(){
const oldValue = this.value;
this.value = this.get();
this.cb.call(this.vm,this.value,oldValue)
}
}
const bailRE = /[^\w.$]/;
function parsePath(path){
if(bailRE.test(path)){
return
}
const segments = path.split('.')
//返回函数A 闭包函数
return function(obj){
//obj为数据对象value
//segments为key
for(let i =0;i <segments.length;i++){
// console.log("2-3")
if(!obj)return
// console.log("2-4")
obj = obj[segments[i]]
}
return obj
}
}
const hasProto = '__proto__' in {};
const arrayKeys = Object.getOwnPropertyNames(arrayMethods);
//侦测所有的key
class Observer {
constructor(value){
this.value = value;
//数组添加
this.dep = new Dep()
def(value,'__ob__',this)
if(Array.isArray(value)){
const argument = hasProto?protoAugment:copyAugment;
argument(value,arrayMethods,arrayKeys)
observeArray(value)
}
//数组添加
if(!Array.isArray(value)){
this.walk(value)
}
}
walk(obj){
const keys = Object.keys(obj)
for(let i = 0;i<keys.length;i++){
defineReactive(obj,keys[i],obj[keys[i]])
}
}
}
//解析指令
class Compile{
constructor(data,el){
let nodes = [...el.children];
nodes.forEach(node =>{
if(node.children && node.children.length !== 0 ){
new Compile(nodes)
}
if(node.hasAttribute('v-mode')){
let attrVal = node.getAttribute('v-mode');
var arrList = attrVal.split(".")
new Watcher(data,arrList[1],(val,oldval)=>{
console.log("--这是回调函数--")
node.value = val
})
}
})
}
}
//vue类
class Vue{
constructor(options){
new Observer(options)
//给数据添加订阅者
let el = document.getElementById("app");
new Compile(options,el)
// Object.keys(options).forEach(key=>{//按照options的属性循环实例化watcher
// new Watcher(options,key,()=>{
// console.log("这是回调方法")
// });
// })
}
}
// obj.time = "17";
/**
* 数据初始化首先 实例化Obsever 并将对象数据作为参数传入 在observer实例中循环参数
* 对象的值value,并对value调用defineReactive方法中实例化Dep 之后重新定义get和set。
* get方法中收集依赖 set方法中派发依赖
* 其次循环数据value 给value添加订阅者 并通过数据项get方法将value 加入dep实例中
*
* **/
// 数组的变化侦测ss
['push','pop','shift','unshift',
'splice','sort','reverse'].forEach(function(method){
const original = arrayProto[method]
def(arrayMethods,method,function(...args){
const result = original.apply(this,args)
const ob = this.__ob__;
console.log("--push--")
let inserted
switch(method){
case 'push':
case 'unshift':
inserted = args
break
case 'splice':
inserted = args.slice(2)
break
}
if(inserted) observeArray(inserted)
ob.dep.notify()
return result
})
})
function def(obj,key,val,enumerable){
Object.defineProperty(obj,key,{
value:val,
enumerable:!!enumerable,
writable:true,
configurable:true
})
}
//Observer类
function protoAugment(target,src,keys){
target.__proto__ = src;
}
function copyAugment(target,src,keys){
for(let i = 0;i < keys.length;i++){
const key = keys[i];
}
}
function observeArray(items){
for(let i =0; i < items.length;i++){
observe(items[i])
}
}
function observe(value,asRootData){
if(!isObject(value)){
return
}
let ob
// if(hasOwn(value,'__ob__') && value.__ob__ instanceof Observer ){
// ob = value.__ob__;
// }else{
// ob = new Observer(value)
// }
ob = new Observer(value)
return ob
}
function isObject(val) {
return val != null && typeof val === 'object'
// return val != null && typeof val === 'object' && Array.isArray(val) === false;
};
let obj = {
time:1,
}
// let array1 = [1,3,5,7]
new Vue(obj)
setTimeout(()=>{
obj.time = 10;
},5000)
// console.log(obj.array1[0])
// console.log(obj.array1[1])
// obj.array1.push(9)
<div id="app">
1<input type="text" name="" v-mode="obj.time" >
2<input type="text" name="" v-mode="obj.time" >
</div>