在手写之前应该想想:
vuex如何知道状态变化,并通知组件? 组件如何响应?...
接下来,就实现一个duex
的状态管理器吧!
对应的store称为DStore
// written by Djtao
class DStore{
constructor(options){
//参数内定义了三大方法:
this.state=options.state;
this.mutations=options.mutations;
this.actions=options.actions;
//借用Vue的数据劫持功能
this.vm=new Vue({
data:{
state:this.state
}
});
}
借用了vue的劫持功能。与redux不同之处,在于vuex与vue强耦合。
commit和actions可根据type拿到函数方法: 不同点在于:
//提交,触发
commit(type,payload){
//通过`type`拿到函数
const mutations=this.mutations[type];
// 执行这个函数!第一个参数为state,第二个是自定义参数payload
mutations(this.state.payload);
}
//派发事件
dispatch(type,payload){
const actions=this.actions[type];
const ctx={
commit:this.commit,
state:this.state,
dispatch:this.dispatch
}
// 把这个函数的运行结果返回出去!
return actions(ctx,payload);
}
把这个store返回出去,那就写完了,核心原理可以说是异常简单。 就用官方文档的案例验证下这个duex有多靠谱:
// DStore。js导入duex:
export default new DStore({
state:{count:1},
mutations:{
add(state){
state.count++
}
}
})
在组件中吧状态作为计算属性导入:
// app.vue需要导入DStore
export defaut{
computed:{
count(){
return store.state.count;
}
}
}
写一个按钮,点击触发add,然后就成功了。
现在回顾一下router通常是怎么用的。
const routes=[
{path:'/aaa',component:Aaa},
{path:'/bbb',component:Bbb},
{path:'/ccc',component:Ccc},
]
const router=new VueRouter(Vue,{routes});
new Vue({
el:`#App`,
router
})
如果看到这个十分亲切而不会一脸懵逼,那么就可以进行手撸router的操作了。 这个简化版的名字就叫做Due-router吧。
// 引入Vue
class DueRouter{
constructor(Vue,options){
this.$options=options;
// 全局路由映射,不可重复,routerMap里的键就是path,值就是里面的组件。
this.routeMap={};
//强依赖,把动态路由路径存进去:
this.vm=new Vue({
data:{
current:'#/'
}
});
this.init();
this.createRouteMap(this.$options);
}
options
就是那一大串路由数组。通过createRouteMap
存到this.routeMap
中。
//映射:把options里的内容装进去!
createRouteMap(options){
options.routes.forEach(item => {
this.routeMap[item.path]=item.component
});
}
当前页面的的路由值是存到vue实例的一个状态中(current
),初始值为#/
接下来就是监听网页的哈希路由改变事件,网页加载事件:
// 初始化hashChange,只要哈希变化,就执行onHashChange方法。
init(){
window.addEventListener('load',this.onHashChange.bind(this),false);
window.addEventListener('hashchange',this.onHashChange.bind(this),false)
}
//onHashChange:设置当前路径
onHashChange(){
this.vm.current=this.getHash();
}
// 获取hash路由
getHash(){
return window.location.hash.slice(1)||'/'
}
实现在使用中的两个功能,router-link
和router-view
:
//注册组件
initComponent(Vue){
Vue.component('router-link',{
props:{
to:String
},
// 返回虚拟a标签
render:function(h){
// 这里的h,表示createElement,实际上就是返回虚拟dom的工厂函数。
// 实际上你看到的是 <a :href="to"><slot></slot></a>
return h(
'a',//a标签
{href:this.to},//设置href属性
this.slot.default
);
}
})
const _this=this;
// 根据组件,返回router-view的虚拟dom
Vue.component('router-View',{
render(h){
let component=_this.routeMap[_this.vm.current];
//页面刷新,渲染对应的component
return h(component)
}
})
}
那么核心功能就实现了