import Vue from '../modules/vue/index'
const App = {
el:'#app',
data(){
return{
message: 'Hello Vue!',
a:1,
b:2
}
},
template: `
<div>
<h1>{{ message }}</h1>
</div>
`,
computed:{
total(){
console.log('computed');
return this.a + this.b;
}
},
watch:{
total(newValue,oldValue){
console.log('total watch',newValue,oldValue);
},
a(newValue,oldValue){
console.log('a watch',newValue,oldValue);
},
b(newValue,oldValue){
console.log('b watch',newValue,oldValue);
},
}
}
const vm = new Vue(App)
console.log(vm);
console.log(vm.total);
console.log(vm.total);
console.log(vm.total);
vm.a = 100;
console.log(vm.total);
console.log(vm.total);
console.log(vm.total);
vm.b = 200;
console.log(vm.total);
console.log(vm.total);
console.log(vm.total);
import Computed from "./computed";
import { reactive } from "./reactive";
import Watcher from "./watcher";
class Vue {
constructor(optinos){
const {data,computed,watch,el} = optinos;
this.$data = data();
this.$el = el;
this._init(this,computed,watch);
}
_init(vm,computed,watch){
this.initData(vm);
const computedIns = this.initComputed(vm,computed);
const watcherIns = this.initWatcher(vm,watch);
this.$computed = computedIns.update.bind(computedIns);
this.$watch = watcherIns.invoke.bind(watcherIns);
}
initData(vm){
reactive(vm,(key,value)=>{
},(key,newValue,oldValue)=>{
if(newValue === oldValue) return;
this.$computed(key,(key,newValue,oldValue)=>{
this.$watch(key,newValue,oldValue);
});
this.$watch(key,newValue,oldValue);
});
}
initComputed(vm,computed){
const computedIns = new Computed();
for (const key in computed) {
computedIns.addComputed(vm,computed,key)
}
return computedIns;
}
initWatcher(vm,watch){
const watcherIns = new Watcher();
for (const key in watch) {
watcherIns.addWatcher(vm,watch,key)
}
return watcherIns;
}
}
export default Vue;
export function reactive(vm,__get__,__set__){
const _data = vm.$data;
for (const key in _data) {
Object.defineProperty(vm,key,{
get:function(){
__get__(key,_data[key])
return _data[key];
},
set:function(newValue){
const oldValue = _data[key];
_data[key] = newValue;
__set__(key,newValue,oldValue)
}
})
}
}
class Computed{
constructor(){
this.computedData = []
}
addComputed(vm,computed,key){
const descriptor = Object.getOwnPropertyDescriptor(computed,key),
descriptorFn = descriptor.value.get?descriptor.value.get:descriptor.value,
value = descriptorFn.call(vm),
get = descriptorFn.bind(vm),
dep = this.collectDep(descriptorFn);
this._addComputedProp({key,value,get,dep});
const dataItem = this.computedData.find(item=>item.key == key);
Object.defineProperty(vm,key,{
get:function(){
return dataItem.value
},
set:function(newValue){
dataItem.value = dataItem.get();
}
})
}
_addComputedProp(computedProp){
this.computedData.push(computedProp)
}
collectDep(fn){
const matched = fn.toString().match(/this\.(.+?)/g);
return matched.map(item=>item.split('.')[1])
}
update(key,cb){
this.computedData.map(item=>{
const dep = item.dep;
const _key = dep.find(el=>el == key);
if(_key){
let oldValue=item.value;
item.value = item.get();
cb && cb(item.key,item.value,oldValue)
}
})
}
}
export default Computed;
class Watcher{
constructor(){
this.watchers = [];
}
addWatcher(vm,watch,key){
this._addWatcherProp({
key,
fn:watch[key].bind(vm)
})
}
_addWatcherProp(watchProp){
this.watchers.push(watchProp)
}
invoke(key,newValue,oldValue){
this.watchers.map(item=>{
if(item.key === key){
item.fn(newValue,oldValue);
}
})
}
}
export default Watcher;