Coder Social home page Coder Social logo

mymvvm's Introduction

Vue依赖追踪原理

class Dep {
    constructor(){
        this.subs = []
    }
    addSub(sub){
        this.subs.push(sub)
    }
    notify(){
        this.subs.forEach(sub => sub.update())
    }
}

class Watcher {
    constructor(){
        Dep.target = this
    }
    update(){
        console.log('视图更新!')
    }   
}

class Observer{
    constructor(data){
        let self = this
        Object.keys(data).forEach(key => 
            self.defineReactive(data,key,data[key])
        )
    }
    defineReactive(data,key,val){
        const dep = new Dep()

        Object.defineProperty(data,key,{
            configurable:true,
            enumerable:true,
            get(){
                dep.addSub(Dep.target)
                return val
            },
            set(newVal){
                if(val === newVal)return;
                val = newVal;
                dep.notify()
            }
        })
    }
}

function observe(value){
    if(!value || typeof value != 'object')return;
    new Observer(value)
}

class Vue {
    constructor(options){
        //1.挂载data到vm
        this._data = options.data
        //2.添加getter setter
        observe(this._data)
        //3.注册订阅者watcher
        new Watcher()
        //4.强制添加订阅者
        console.log('添加订阅者' + this._data.test)
    }
}


const test = new Vue({
    data:{
        test:'plus'
    }
})

test._data.test = 'test plus'
console.log(test._data.test)

Dep.target = null

Vue的执行过程

proxyData(data){
    Object.keys(data).forEach(key => {
        //1.将vm.data下的对象,代理到vm下
        Object.defineProperty(this,key,{
            configurable:true,
            enumerable:false,
            get(){
                return data[key]
            },
            set(newVal){
                data[key] = newVal
            }
        })
    })
}

defineReactive(data,key,val){
    //3.收集watcher
    const dep = new Dep()
    //2.递归定义getter setter 为了后续添加wacher订阅者作准备
    observe(val)
    Object.defineProperty(data,key,{
        enumerable:true,
        configurable:true,
        get(){
            if(Dep.target){
                dep.addSub(Dep.target)
            }
            return val
        },
        set(newVal){
            if(val === newVal)return;
            val = newVal
            dep.notify()
        }
    })
}
}

compileModel(node,vm,exp,dir){
    let val = vm[exp]
    this.modelUpdater(node,val)
    //5.在编译v-model时添加订阅者
    new Watcher(vm,exp,(value,oldValue) => {
        //将新的值添加到真实dom上
        this.modelUpdater(node,value)
    })
    //绑定输入事件
    node.addEventListener('input',e => {
        let newValue = e.target.value
        if(val === newValue)return;
        //当接收到视图变化的时候通知订阅者更新
        vm[exp] = newValue
    })
}

compileText(node,exp){
    let initText = this.vm[exp]
    //将变量替换为变量所对应的文字
    this.updateText(node,initText)
    //6.编译文本节点的时候添加订阅者
    new Watcher(this.vm,exp,(value,oldValue) => {
        this.updateText(node,value)
    })
}

class Vue {
    constructor(options){
        this.data = options.data;
        this.methods = options.methods;
        this.proxyData(this.data)
        observe(this.data)
        //4.编译#app模版代码
        new Compile(options.el,this)
        //7.执行生命周期函数
        options.mounted.call(this);
    }
} 

Vuex原理

const state = {
    foo:'foo',
    bar:'bar'
}
const actions = {
    asyncFoo(commit,payload){
        setTimeout(() => commit('foo',payload),3000)
    },
    asyncBar(commit,payload){
        setTimeout(() => commit('bar',payload),3000)
    }
}
const mutations = {
    foo(state,type,payload){
         state[type] = payload
    },
    bar(state,type,payload){
         state[type] = payload
    }
}
const store = new Store({state,actions,mutations});
window.Vue.use(Vuex)
new Vue({
    name:'testRoot',
    el:'#app',
    store,
    data:{
        title:'plus'
    },
    beforeCreate(){
        this.$store.dispatch('asyncFoo','我是foo')
        this.$store.dispatch('asyncBar','我是bar')
    },
    computed:{  
        foo(){
            return this.$store._state.foo
        },
        bar(){
            return this.$store._state.bar
        }
    }
})

class Store {
    constructor({state,actions,mutations}){   
        this._vm = new Vue({
            data:{
                $$state:state
            }
        })
        
        this._state = this._vm._data.$$state
       
        this._actions = {
            ...actions,
        }

        this._mutations = {
            ...mutations
        }
    }

    commit(type,payload,_options){
        const entry = [this._mutations[type]]
        entry.forEach((handler) => {
            handler(this._vm._data.$$state,type,payload);
        })
    }
   
    dispatch(type,payload){
        const entry = [this._actions[type]]
        return entry[0](this.commit.bind(this),payload)
    }
}

function vuexInit(){
    //拿到根组件传入到配置参数
    const options = this.$options
    if(options.store){
        //有store挂到$store上
        this.$store = options.store
    } else {
        //没有store查找父组件到store
        this.$store = options.parent.$store
    }
}

function Vuex(_Vue){
    //将vuex插件混入到各个组件到beforeCreate中去
    _Vue.mixin({beforeCreate:vuexInit})
}

vue-router原理

路由对象生成之前先生成各种钩子

const queue = [
    this.router.beforeEach,
    this.current.route.beforeLeave,
    route.beforeEnter,
    route.afterEnter
]

function next(queue){
    let i = -1;
    (function _next(){
        i++
        if(i >= queue.length){
            cb()
        }else if(queue[i]){
            queue[i](_next)
        } else {
            _next()
        }
    })()
}
next(queue)

生成路由对象

this.current.path = route.path
this.current.name = route.name
this.current.params = route.params
this.current.query = route.query
this.current.route = route
this.current.fullPath = route.fullPath

监听变化

observer(this.history.current)
new Watcher(this.history.current,'route',this.render.bind(this))

更新视图

document.getElementById(this.container).innerHTML = this.history.current.route.component

mymvvm's People

Contributors

pluslius avatar

Stargazers

 avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.