1

vue-router

vue-router 是vue.js的官方路由管理器.它和vue.js核心深度集成.让构建单页面应用易如反掌

使用步骤

(1) 安装 vue add router
(2) 使用vue-router插件

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

(3) 创建Router实例 router.js

export default new Router({...})

(4) 在根组件上添加该实例 main.js

import Router from './router'
new Vue({
    router,
}).$mount("#app");

(5) 添加路由视图 App.vue

<router-view></router-view>

(6) 路由导航

<router-link to="/">Home</router-link>
this.$router.push('/')

vue-router 源码简单实现

单页面程序中,url发生变化的时候,不刷新页面,显示对应视图

需求分析

(1) 页面不刷新

hash模式  #/about

(2) 页面视图发生变化

router-view
相应式数据: url地址发生变化,找到对应的组件 动态重新执行         render

任务实现一个插件

(1) 实现一个vueRouter类
处理路由选项
监控url变化, hashchange
响应这个变化
(2) 实现install方法
$router注册
两个全局组件  router-link  router-view

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

创建kvue-router.js

let Vue; // 引用构造函数, vueRouter中要使用
class VueRouter {
    constructor(options) {
        this.$options = options;
    }
}
// 插件实现install方法, 注册$router
VueRouter.install = function (_vue) {
    Vue = _Vue;
    // 任务2 挂载$router
    // 为什么要使用混入的方式. 主要原因是vue.use代码在前,Router实例创建在后. 而install逻辑又需要使用到该实例
    Vue.mixin({
        beforeCreated(){
            // 只有根组件拥有router选项
            if (this.$options.router) {
                Vue.prototype.$router = this.$options.router;
            }
        }
    })
    // 任务2 实现两个全局组件router-link router-view
    Vue.component('router-link',Link);
    Vue.component('router-view',View);
}
export default VueRouter

实现router-link组件

<router-link to="/">点击</router-link>

Vue.component('router-link', {
    props: {
        to: {
            type: String,
            required: true
        }
    },
    render (h) {
        return h('a', {attrs: '#' + this.to}, this.$slots.default)
    }
})

实现router-view组件

Vue.component('router-view', {
    render(h) {
        // 暂时不渲染任何内容
        return h(null)
    }
})

监控url变化

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

class VueRouter {
    constructor(options) {
    
    
        // 定义响应式的属性current
        const initial = window.location.hash.slice('#') || '/';
        Vue.util.defineReactive(this, 'current', initial);
        // 监听hash变化
        window.addEventListener('hashchange', this.onHashChange.bind(this));
        
        // 缓存path和route映射关系
        this.routerMap = {};
        this.$options.routes.forEach(route => {
            this.routerMap[route.path] = route;
        })
    }
    onHashChange(){
        this.current = window.location.hash.splice(1);
    }
}

// router-view
Vue.component('router-view', {
    render(h) {
        const {routerMap , current} = this.$router;
        const component = routerMap[current] ? routerMap[current].component : nu~~~~ll;
        return h(component)
    }
})

完整vue-router简单实现代码

let Vue;
class VueRouter {
    constructor(options) {
        this.$options = options;
        // 把current作为相应式数据 
        // 将来发送变化, router-view的render函数能够再次执行
        this.current = '/';
        const initial = window.location.hash.slice("#") || '/'
        Vue.util.defineReactive(this, 'current', initial)
        // 监听hash变化
        window.addEventListener('hashchange', () => {
            this.current = window.location.hash.slice(1);
        })
        // 缓存path和route映射关系
        this.routerMap = {};
        this.$options.routes.forEach(route => {
            this.routerMap[route.path] = route
        });
        console.log(this.routerMap);
    }
}
// _vue 是vue.use调用时传入的
// 全局混入的目的: 延迟下面逻辑到router创建完毕并且 附加到选项上时才执行
VueRouter.install = function(_Vue) {
    Vue = _Vue;
    // 1. 挂载$router属性
    // 全局混入
    Vue.mixin({
        beforeCreate() {
            // 此钩子在每个组件创建实例时都会调用
            // 根实例才有该选项
             if (this.$options.router) {
                 Vue.prototype.$router = this.$options.router; 
             }
        },
    })

    // 2. 注册实现两个自建 router-view, router-link
    Vue.component('router-link', {
        props: {
            to: {
                type: String,
                required: true
            } 
        },
        render (h) { 
            // 使用插槽动态拿到组件包含的文案
             return h(
                 'a', 
                 {
                     attrs:{
                         href: '#'+this.to
                     }
                 }, 
                 this.$slots.default)
        },
    });
    Vue.component('router-view', { 
        render(h) {
            // 获取当前路由对应的组件
            const { routerMap, current} = this.$router;
            const component = routerMap[current] ? routerMap[current].component: null;
            return h(component)
        },
    });
}
export default VueRouter


lolo
12 声望0 粉丝

引用和评论

0 条评论