当前的路由数据是完全符合vue路由声明规则的,但是直接使用添加路由的方法addRoutes动态添加路由是不行的。因为vue路由的component属性必须是一个组件,比如
{ name: "login", path: "/login", component: () => import("@/pages/Login.vue") }而目前我们得到的路由数据中component属性是一个字符串。需要根据这个字符串将component属性处理成真正的组件。在路由数据中除了component这个属性不符合vue路由要求,还多了componentPath这个属性。下面介绍两种分别根据这两个属性处理路由的方法。
处理路由 使用routerMapComponents这个名称是我取的,其实就是维护一个js文件,将组件按照key-value的规则导出,比如:
import layoutHeaderAside from '@/layout/header-aside' export default { "layoutHeaderAside": layoutHeaderAside, "menu": () => import(/* webpackChunkName: "menu" */'@/pages/sys/menu'), "route": () => import(/* webpackChunkName: "route" */'@/pages/sys/route'), "function": () => import(/* webpackChunkName: "function" */'@/pages/permission/function'), "role": () => import(/* webpackChunkName: "role" */'@/pages/permission/role'), "rolePermission": () => import(/* webpackChunkName: "rolepermission" */'@/pages/permission/rolePermission'), "roleUser": () => import(/* webpackChunkName: "roleuser" */'@/pages/permission/roleUser'), "userRole": () => import(/* webpackChunkName: "userrole" */'@/pages/permission/userRole'), "user": () => import(/* webpackChunkName: "user" */'@/pages/permission/user') }这里的key就是与后端返回的路由数据的component属性对应。所以拿到后端返回的路由数据后,使用这份规则将路由数据处理一下即可:
const formatRoutes = function (routes) { routes.forEach(route => { route.component = routerMapComponents[route.component] if (route.children) { formatRoutes(route.children) } }) } formatRoutes(permissionRouter) router.addRoutes(permissionRouter);而且,规则列表里维护的组件都会被webpack打包成单独的js文件,即使处理路由数据的时候没有被使用到(没有被routerMapComponents[route.component]匹配出来)。当我们需要给一个页面做多种布局的时候,只需要在菜单维护界面上将component修改为routerMapComponents中相应的key即可。
标准的异步组件按照vue官方文档的的写法,得到两种处理路由的方法,并且用到了路由数据中的componentPath:
第一种写法:
const formatRoutesByComponentPath = function (routes) { routes.forEach(route => { route.component = function (resolve) { require([`../${route.componentPath}.vue`], resolve) } if (route.children) { formatRoutesByComponentPath(route.children) } }) } formatRoutesByComponentPath(permissionRouter); router.addRoutes(permissionRouter);第二种写法:
const formatRoutesByComponentPath = function (routes) { routes.forEach(route => { route.component = () => import(`../${route.componentPath}.vue`) if (route.children) { formatRoutesByComponentPath(route.children) } }) } formatRoutesByComponentPath(permissionRouter); router.addRoutes(permissionRouter);其实在大多数人的认知里(包括我),这样的代码webpack应该是处理不了的,毕竟componentPath是运行时才确定,而webpack是“编译”时进行静态处理的。
为了验证这样的代码能不能正常运行,写了个简单的demo,感兴趣的可以下载到本地运行。
测试的结果是:上面的两种写法程序都可以正常运行。
观察打包后的代码,发现所有的组件都被打包,不管是否被使用(之前routerMapComponents方式中,只有维护进列表中的组件才会打包)。
所有的组件都被打包了,但是两种方法打包后的代码却是天差地别。
使用
route.component = function (resolve) { require([`../${route.componentPath}.vue`], resolve) }处理路由,打包后
0开头的文件是page404.vue打包后的代码,1开头的是home.vue的。这两个组件能分别打包,是因为main.js中显式的使用的这两个组件:
... let routers = [ { name: "home", path: "http://www.likecs.com/", component: () => import(/* webpackChunkName: "home" */"@/pages/home.vue") }, { name: "404", path: "*", component: () => import(/* webpackChunkName: "page404" */"@/pages/page404.vue") } ]; let router = new Router({ // mode: 'history', // require service support scrollBehavior: () => ({ y: 0 }), routes: routers }); ...而4开头的文件就是其它全部组件打包后的,而且额外带了点东西:
webpackJsonp([4, 0], { "/EbY": function(e, t, n) { var r = { "./App.vue": "M93x", "./pages/dynamic.vue": "fJxZ", "./pages/home.vue": "vkyI", "./pages/nouse.vue": "HYpT", "./pages/page404.vue": "GVrJ" }; function i(e) { return n(a(e)) } function a(e) { var t = r[e]; if (! (t + 1)) throw new Error("Cannot find module '" + e + "'."); return t } i.keys = function() { return Object.keys(r) }, i.resolve = a, e.exports = i, i.id = "/EbY" }, GVrJ: function(e, t, n) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }); var r = { render: function() { var e = this.$createElement, t = this._self._c || e; return t("div", [this._v("\n 404\n "), t("div", [t("router-link", { attrs: { to: "http://www.likecs.com/" } }, [this._v("返回首页")])], 1)]) }, staticRenderFns: [] }; var i = n("VU/8")({ name: "page404" }, r, !1, function(e) { n("tqPO") }, "data-v-5b14313a", null); t. default = i.exports }, HYpT: function(e, t, n) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }); var r = { render: function() { var e = this.$createElement; return (this._self._c || e)("div", [this._v("\n 从未使用的组件\n")]) }, staticRenderFns: [] }; var i = n("VU/8")({ name: "nouse" }, r, !1, function(e) { n("v4yi") }, "data-v-d4fde316", null); t. default = i.exports }, WMa5: function(e, t) {}, fJxZ: function(e, t, n) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }); var r = { render: function() { var e = this.$createElement, t = this._self._c || e; return t("div", [t("div", [this._v("动态路由页")]), this._v(" "), t("router-link", { attrs: { to: "http://www.likecs.com/" } }, [this._v("首页")])], 1) }, staticRenderFns: [] }; var i = n("VU/8")({ name: "dynamic" }, r, !1, function(e) { n("WMa5") }, "data-v-71726d06", null); t. default = i.exports }, tqPO: function(e, t) {}, v4yi: function(e, t) {} });dynamic.vue,nouse.vue都被打包进去了,而且page404.vue又被打包了一次(???)。
而且有点东西:
var r = { "./App.vue": "M93x", "./pages/dynamic.vue": "fJxZ", "./pages/home.vue": "vkyI", "./pages/nouse.vue": "HYpT", "./pages/page404.vue": "GVrJ" };这应该就是运行时使用componentPath处理路由,程序也能正常运行的关键点。