一、vue-router拓展
1.1 addRoutes实现动态路由
router.addRoutes(routes: Array),常用于权限控制,例如会员访问的菜单区分。
关键点:接口传过来的component为字符,并不是对象,需要映射为对象。
api.getRoutes.then(res=>{
const routesConfig = res.routes.map(route=>{
mapComponent(route);
})
this.$router.addRoutes(routesConfig)
})
let mapCom = function(com){
return {
com:()=>import(`@/view/${com}`);
}
}
let mapComponent = function(route){
const route.component = mapCom(route.component);
if(route.children){
route.children = route.children.map(child=>{
mapComponent(child);
})
}
}
1.2 面包屑
面包屑常用于网页的定位,例如首页->列表页,因此可以利用route.matched匹配当前路由的信息。
知识点:$route.matched指当前路由的所有嵌套路径片段的路由记录。当 URL 为 /foo/bar,$route.matched 将会是一个包含从上到下的所有对象 (副本)。
watch:{
$route:{
handler:function(){
this.crumbData = this.$route.matched.map(item=>{
return {name:item.meta.name,path:item.meta.path}
});
},
immediate:true
}
}
1.3 简单版vue-router源码实现
- 开发插件
通过全局方法 Vue.use() 使用插件。它需要在你调用 new Vue() 启动应用之前完成。Vue.js 的插件应该暴露一个 install 方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象:
MyPlugin.install = function (Vue, options) {
// 1. 添加全局方法或 property
Vue.myGlobalMethod = function () {
// 逻辑...
}
// 2. 添加全局资源
Vue.directive('my-directive', {
bind (el, binding, vnode, oldVnode) {
// 逻辑...
}
...
})
// 3. 注入组件选项
Vue.mixin({
created: function () {
// 逻辑...
}
...
})
// 4. 添加实例方法
Vue.prototype.$myMethod = function (methodOptions) {
// 逻辑...
}
}
- 代码实现
实现router-view、router-link组件,获取path与route的映射表,从而获取current的path后,能得到相应的component,current一定要为响应式的。
let Vue;
export default class vueRouter{
constructor(options){
this.options = options;
this.routeMap = {};
this.app = new Vue({
data: {
currentPath: '/'
}
})
}
init(){
this.bindEvents();
this.initComponent();
this.createMatch();
this.onHashChange();
}
onHashChange(){
this.app.currentPath = window.location.hash.slice(1)||'/';
}
bindEvents() {
window.addEventListener('hashchange', this.onHashChange.bind(this))
window.addEventListener('load', this.onHashChange.bind(this))
}
initComponent(){
const self = this;
Vue.component('router-link',{
render(h) {
return h('a',{attrs:{href:`#${this.to}`}},this.$slots.default)
},
props:{
to:String
}
})
Vue.component('router-view',{
render:h => {
const com = self.routeMap[this.app.currentPath].component;
console.log(com)
return h(com);
}
})
}
createMatch(){
this.options.routes.map(route=>{
// 路径和route映射
this.routeMap[route.path] = route;
})
}
}
vueRouter.install = function(_Vue){
Vue = _Vue;
Vue.mixin({
beforeCreate() {
if(this.$options.router!==undefined){
this.router = this.$options.router;
this.router.init()
}
}
})
}