console
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){
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")
const subs = this.subs.slice()
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){
this.vm = vm;
this.getter = parsePath(expOrFn);
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('.')
return function(obj){
for(let i =0;i <segments.length;i++){
if(!obj)return
obj = obj[segments[i]]
}
return obj
}
}
const hasProto = '__proto__' in {};
const arrayKeys = Object.getOwnPropertyNames(arrayMethods);
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
})
}
})
}
}
class Vue{
constructor(options){
new Observer(options)
let el = document.getElementById("app");
new Compile(options,el)
}
}
['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
})
}
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
ob = new Observer(value)
return ob
}
function isObject(val) {
return val != null && typeof val === 'object'
};
let obj = {
time:1,
}
new Vue(obj)
setTimeout(()=>{
obj.time = 10;
},5000)
<div id="app">
1<input type="text" name="" v-mode="obj.time" >
2<input type="text" name="" v-mode="obj.time" >
</div>