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