vue02-全家桶&原理

Vue 全家桶 & 原理

作业

\1. 尝试解决Input里面$parent派发事件不够健壮的问题

element的minxins方法

Input组件中的使用

\2. 组件实例创建的另一种解决方案

const Ctor = Vue.extend(Component) 
const comp = new Ctor({
    propsData: props
}) 
comp.$mount(); 
document.body.appendChild(comp.$el) 
comp.remove = () => { 
    // 移除dom 
    document.body.removeChild(comp.$el) 
    // 销毁组件 
    comp.$destroy(); 
}

\3. 使用插件进一步封装便于使用,create.js

import Notice from '@/components/Notice.vue' 

//... 
export default { 
    install(Vue) { 
        Vue.prototype.$notice = function (options) {
            return create(Notice, options) 
        } 
    } 
}

资源

\1. vue-router

\2. vuex

\3. vue-router源码

\4. vuex源码

知识点

vue-router

Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反

掌。

安装: vue add router

核心步骤:

步骤一:使用vue-router插件,router.js

import Router from 'vue-router' Vue.use(Router)

步骤二:创建Router实例,router.js

export default new Router({...})

步骤三:在根组件上添加该实例,main.js

import router from './router' 

new Vue({ router, }).$mount("#app");

步骤四:添加路由视图,App.vue

<router-view></router-view>

导航

<router-link to="/">Home</router-link> 
<router-link to="/about">About</router-link>

vue-router****源码实现

需求分析

作为一个插件存在:实现VueRouter类和install方法

实现两个全局组件:router-view用于显示匹配组件内容,router-link用于跳转

监控url变化:监听hashchange或popstate事件

响应最新url:创建一个响应式的属性current,当它改变时获取对应组件并显示

实现一个插件:创建****VueRouter类和install方法

创建kvue-router.js

let Vue; 
// 引用构造函数,VueRouter中要使用 
// 保存选项 
class VueRouter { 
    constructor(options) { 
        this.$options = options; 
    } 
}

// 插件:实现install方法,注册$router 
VueRouter.install = function(_Vue) { 
    // 引用构造函数,VueRouter中要使用 
    Vue = _Vue; 
    Vue.mixin({ 
        beforeCreate() { 
            // 只有根组件拥有router选项 
            if (this.$options.router) { 
                // vm.$router 
                Vue.prototype.$router = this.$options.router; 
            } 
        } 
    }); 
};

export default VueRouter;

为什么要用混入方式写?主要原因是use代码在前,Router实例创建在后,而install逻辑又需要用到该实例

创建router-view和****router-link

创建krouter-link.js

export default { 
    props: { 
        to: String, 
        required: true 
    },
    render(h) { 
        // return <a href={'#'+this.to}>{this.$slots.default}</a>; 
        return h('a', { 
            attrs: { 
                href: '#' + this.to 
            } 
        }, [
            this.$slots.default 
        ]) 
    } 
}

创建krouter-view.js

export default { 
    render(h) { 
        // 暂时先不渲染任何内容 
        return h(null); 
    } 
}

监控url变化

定义响应式的current属性,监听hashchange事件


class VueRouter { 
    constructor(options) { 
        // current应该是响应式的 
        Vue.util.defineReactive(this, 'current', '/') 
        // 定义响应式的属性current 
        const initial = window.location.hash.slice(1) || '/' 
        Vue.util.defineReactive(this, 'current', initial) 
        // 监听hashchange事件 
        window.addEventListener('hashchange', this.onHashChange.bind(this)) 
        window.addEventListener('load', this.onHashChange.bind(this)) 
    }
    onHashChange() { 
        this.current = window.location.hash.slice(1) 
    } 
}

动态获取对应组件,krouter-view.js

export default { 
    render(h) { 
        // 动态获取对应组件 
        let component = null; 
        this.$router.$options.routes.forEach(route => { 
            if (route.path === this.$router.current) { 
                component = route.component 
            } 
        }); 
        return h(component); 
    } 
}

提前处理路由表

提前处理路由表避免每次都循环

class VueRouter { 
    constructor(options) { 
        // 缓存path和route映射关系 
        this.routeMap = {} 
        this.$options.routes.forEach(route => { 
            this.routeMap[route.path] = route 
        }); 
    } 
}

使用,krouter-view.js

export default { 
    render(h) { 
        const {routeMap, current} = this.$router 
        const component = routeMap[current].component; 
        return h(component); 
    } 
}

整理一下

Vuex

Vuex 集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以可预测的方式发生变化。

整合 vuex

vue add vuex

核心概念

state 状态、数据

mutations 更改状态的函数

actions 异步操作

store 包含以上概念的容器

状态 - state

state保存应用状态

export default new Vuex.Store({ 
    state: { counter:0 }, 
})

状态变更 - mutations

mutations用于修改状态,store.js

export default new Vuex.Store({ 
    mutations: { 
        add(state) { state.counter++ } 
    } 
})

派生状态 - getters

从state派生出新状态,类似计算属性

export default new Vuex.Store({ 
    getters: { 
        doubleCounter(state) { 
            // 计算剩余数量 
            return state.counter * 2;
        } 
    } 
})

动作 - actions

添加业务逻辑,类似于controller

export default new Vuex.Store({ 
    actions: { 
        add({ commit }) { 
            setTimeout(() => { 
                commit('add') 
            }, 1000); 
        } 
    } 
})

测试代码:

<p @click="$store.commit('add')">counter: {{$store.state.counter}}</p> 
<p @click="$store.dispatch('add')">async counter: {{$store.state.counter}}</p> 
<p>double:{{$store.getters.doubleCounter}}</p>

vuex****原理解析

任务分析

实现一个插件:声明Store类,挂载$store

Store具体实现:

创建响应式的state,保存mutations、actions和getters

实现commit根据用户传入type执行对应mutation

实现dispatch根据用户传入type执行对应action,同时传递上下文

实现getters,按照getters定义对state做派生

初始化:Store声明、install实现,kvuex.js:


let Vue;
class Store { 
    constructor(options = {}) { 
        this._vm = new Vue({ 
            data: { $$state:options.state } 
        }); 
    }
    get state() { 
        return this._vm._data.$$state 
    }
    set state(v) { 
        console.error('please use replaceState to reset state'); 
    } 
}

function install(_Vue) { 
    Vue = _Vue;
    Vue.mixin({ 
        beforeCreate() { 
            if (this.$options.store) { 
                Vue.prototype.$store = this.$options.store; 
            } 
        } 
    }); 
}

export default { 
    Store, install 
};

实现commit:根据用户传入type获取并执行对应mutation

class Store { 
    constructor(options = {}) { 
        // 保存用户配置的mutations选项 
        this._mutations = options.mutations || {} 
    }commit(type, payload) { 
        // 获取type对应的mutation 
        const entry = this._mutations[type] 
        if (!entry) { 
            console.error(`unknown mutation type: ${type}`);
            return 
        }
        // 指定上下文为Store实例 
        // 传递state给mutation 
        entry(this.state, payload); 
    } 
}

上一篇:Linux中配置JDK


下一篇:修复 系统命令不可用的问题