专栏首页一Li小麦手撸vuex和vue-router

手撸vuex和vue-router

3. 手撸vuex源码

在手写之前应该想想:

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提交了,就让修改state的方法这么发生了。不返回任何值。
  • dispatch主要是在将来或某个时段(比如请求后)派发修改状态事件,所以必须有返回值。并且需要
    //提交,触发
    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,然后就成功了。


4. 手撸router

现在回顾一下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-linkrouter-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)
            }
        })
    }

那么核心功能就实现了


本文分享自微信公众号 - 一Li小麦(gh_c88159ec1309),作者:一li小麦

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-05-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 基于react的H5音频播放器

    项目是基于React,镶嵌在页面。为此开发了组件audio.js。不过不管什么框架。逻辑都是一样的。

    一粒小麦
  • react核心api

    react从16年12月开始,已经学了有2年多了。react引导了作者找到了第一份比较专职的前端工作。react 2014年横空出世,以其革命性的写法,带动了前...

    一粒小麦
  • 组件设计基础(2)

    早期的react设计了许多的生命周期钩子。它们严格定义了组件的生命周期,一般说,生命周期可能会经历如下三个过程:

    一粒小麦
  • 动手编写你的第一个 Flutter 应用

    我将带领大家尝试编写一个 Flutter 应用,感受一下 Flutter 开发的语法特点和运行效率。

    CSDN技术头条
  • React如何处理事件

    以上示例在点击链接时,会报错:Uncaught TypeError: Cannot read property 'setState' of undefined。...

    用户1272076
  • this四种绑定方式之间的奇淫技巧

    写在前面 上一篇中,我们对于JavaScript中原始值、复杂值以及内存空间进行了一个深入浅出的总结,这次我们来聊一聊JavaScript中this关键字的深入...

    okaychen
  • 如何写出优雅的 JS 代码?使用 SOLID 原则

    把这六个原则的首字母联合起来(两个 L 算做一个)就是 SOLID (solid,稳定的),其代表的含义就是这六个原则结合使用的好处:建立稳定、灵活、健壮的设计...

    前端小智@大迁世界
  • 【被玩坏的博客园】之canvas装饰博客园侧边栏

    用户1749219
  • 【被玩坏的博客园】之canvas装饰博客园侧边栏

    用户1749219
  • [Cocos Creator] 一个全能的挖孔 Shader

    TouchBlocker 是用来限制可点击的节点的独立组件,完整文件在 eazax-ccc/component 目录下。

    陈皮皮

扫码关注云+社区

领取腾讯云代金券