手写vue-router
main.js
import Vue from "vue"; import App from "./App.vue"; // 手动封装的krouter import router from './krouter' new Vue({ router, render: h => h(App) }).$mount("#app");
krouter.js
import Vue from 'vue' //组件引入 import Home from "./views/Home"; import About from "./views/About"; import VueRouter from './kvue-router' // 插件注册 Vue.use(VueRouter); export default new VueRouter({ routes: [ { path: "/", component: Home }, { path: "/about", component: About } ] });
kvue-router
let Vue; class VueRouter { constructor(options) { //接收到krouter.js传过来的配置项 this.$options = options; // 创建一个路由path和route映射 this.routeMap = {}; // 利用Vue响应式原理将当前路径current做成响应式 this.app = new Vue({ data: { current: '/' } }) } init() { // 绑定浏览器事件 this.bindEvents(); // 解析路由配置 this.createRouteMap(this.$options); // 创建router-link和router-view this.initComponent(); } bindEvents() { //监听浏览器hash值的变化和加载事件 window.addEventListener('hashchange', this.onHashChange.bind(this)) window.addEventListener('load', this.onHashChange.bind(this)) } onHashChange() { //例如: http://localhost/#/home this.app.current = window.location.hash.slice(1) || '/'; } createRouteMap(options) { options.routes.forEach(item => { // ['/home']: {path:'/home',component:Home} this.routeMap[item.path] = item; }) } initComponent() { // 声明两个全局组件 Vue.component('router-link', { props: { to: String }, render(h) { // 目标是:<a :href="to">xxx</a> return h('a', { attrs: { href: '#' + this.to } }, this.$slots.default) // return <a href={this.to}>{this.$slots.default}</a> } }); // hash -> current -> render Vue.component('router-view', { // 箭头函数能保留this指向,这里指向VueRouter实例 render: (h) => { const Comp = this.routeMap[this.app.current].component; return h(Comp); } }) } } // 把VueRouter变为插件 VueRouter.install = function (_Vue) { Vue = _Vue; // 这里保存,上面使用 // 混入任务 Vue.mixin({ // 混入:就是扩展Vue beforeCreate() { // 这里的代码将来会在外面初始化的时候被调用 // 这样我们就实现了Vue扩展 // 但是这里只希望根组件执行一次 if (this.$options.router) { // Vue.prototype.$router = this.$options.router; this.$options.router.init(); } } }) } export default VueRouter
请用今天的努力,让明天没有遗憾。