欢迎大家来到IT世界,在知识的湖畔探索吧!
悟耘开源,致力于基础平台开发,点击上方“关注”,每天为你分享开发技巧和开源干货
其实vue也用了好几年了,都是从脚手架开始入手的,可能随着年纪,学习的欲望越来越少了,一直想看看vue-router是怎么运作的,但是一直都没有下手.
最近打算自己搞一个基础开发平台,需要自己下手了,这个地方总归是要懂的,花了几天时间,从迷糊到清晰,慢慢的了解了这块的运作方式,把这块原理试着阐释一下:
在我看来本质就是一个前端的拦截器,然后内部跳转,这也是单页应用的核心,不刷新可以完美地搞定所有事情,但是又和以前的ajax有所区别,可以更好的工程化的解决问题,用来满足现在越来越重的前端需求
2.vue的组件,这个算是一个成功的,不过以前我写过flex,可能现在大家不熟悉,那个时候是用actionScript和xml混合协作的是不是很熟悉,没错我感觉现在的这几个vue和angular都参考了那个,而且flash gameover之后那几个大神好像都去了google,没多久angular就面世了,一样的动态绑定,一样的动态刷新,但是组件算是前进了一大步.他脱胎于class但是优于class,让我们可以单个组件封装了一个完整的html和js以及css的功能
3.路由虽然官方的demo是
<router-link to="/foo">Go to Foo</router-link>
欢迎大家来到IT世界,在知识的湖畔探索吧!
但是我感觉开发应该很少这样用,毕竟我们都是代码小能手,这种固定的东西如何我们天天改的需求,所以常用的还是
欢迎大家来到IT世界,在知识的湖畔探索吧!router.push({ path: 'register', query: { plan: 'private' }})// 我们可以自由的传参和修改地址
但是我们路由总要一个地方管理,这里我们的主角就要出现了VueRouter,我们可以定义好我们的全局路由管理用了吧我们整个项目的路由统一管理
const router = new VueRouter({
routes: [
{
path: '/user/:userId',
name: 'user',
component: User
}
]
})
但是我们的我们没办法把路由都写死在前端,当然我们也可以这样做,但是开始简单,后期维护就负责,而且各自权限管理,也把我们搞得昏头暗地的,我们自然而然地想到了,后台系统把路由组装好,然后再给前端,前端根据后台显示的路由加载界面,这样既可以节省性能,又可以完整的控制权限.
动态加载路由,需要使用官方的api,直接调用函数就可以了,一开始没找到,一直在自己添加原始的路由,结果路由一直匹配不到
欢迎大家来到IT世界,在知识的湖畔探索吧!router.addRoute
addRoute(route: RouteConfig): () => void
后台组装路由,包括基础的对象,主要是path和name,meta用来添加备用信息
@Data
public class IViewMenu {
/**
* 数据ID
*/
private String id;
/**
* 前端路径
*/
private String path;
/**
* 名称
*/
private String name;
private String redirect;
private String component;
private IViewMenuMeta meta;
private List<IViewMenu> children;
@Data
static private class IViewMenuMeta {
/**
* 访问权限
*/
private String access;
/**
* 图标
*/
private String icon;
/**
* 分组标题
*/
private String title;
/**
* 是否缓存
*/
private boolean notCache = false;
/**
* 关闭tab回调函数
*/
private String beforeCloseName;
}
}
4.import,组件的动态加载
我们每一个界面都是一个单独的组件,但是我们现在希望路由规则是后台传过来的,那我们的组件也是根据后台的规则动态加载的,import是我们的常用规则的
// 常用的组件就是这样加载的,其他都是正常属性,component需要我们到前端来加载
{
path: '/login',
name: 'login',
meta: {
title: 'Login - 登录',
hideInMenu: true
},
component: () => import('@/view/base/login/login.vue')
}
// 因为eslint 是不允许import在函数使用的,我们就要单独把这个建一个别名
export const _import = file => () => import('@/view/' + file + '.vue')
然后在.eslintignore这个文件里面把这个文件给忽略,不然编译会一直gg
整体流程是就
登录—>加载菜单–>加载组件–>显示主页 核心代码如下:
- 核心功能是beforeEach,全局的拦截器,可以帮助我们获取到用户跳转之前的所有请求
- 用户to过来大部分都是自动匹配过来的,匹配可以规矩path也可以根据name匹配
- 匹配可以包括多个,上下级都有,整体框架的加载
import Vue from 'vue'
import Router from 'vue-router'
import {routers as routes, _import} from './routers'
import store from '@/store'
import iView from 'view-design'
import { getToken, canTurnTo } from '@/libs/util'
import { isURL } from '@/libs/validate'
import { getRouters } from '@/api/user'
import config from '@/config'
import Main from '@/components/main'
const { homeName } = config
Vue.use(Router)
const router = new Router({
routes,
isAddRouters: false,
mode: 'history'
})
const LOGIN_PAGE_NAME = 'login'
const turnTo = (to, access, next) => {
if (canTurnTo(to.name, access, routes)) next() // 有权限,可访问
else next({ replace: true, name: 'error_401' }) // 无权限,重定向到401页面
}
const addRouters = (data) => {
if (!router.isAddRouters) {
data.forEach(d => {
loadComponent([d])
routes.push(d)
router.addRoutes([d]) // 动态添加路由
router.isAddRouters = true
})
}
}
const loadComponent = (data) => {
data.forEach(route => {
if (route.menu === '3') {
route['component'] = Main
} else if (isURL(route.path)) {
route.meta.iframeUrl = route.href
route['meta']['type'] = 'iframe'
} else if (route.target === 'iframe') {
route['meta']['iframeUrl'] = `${process.env.VUE_APP_SERVER_URL}${route.href}`
} else {
try {
route['component'] = _import(route.path) || null
} catch (e) {
console.log(e)
}
}
if (route.children && route.children.length > 0) {
loadComponent(route.children)
}
})
}
const gotoAssess = (to, store, next) => {
if (store.state.user.hasGetInfo) {
turnTo(to, store.state.user.access, next)
} else {
store.dispatch('getUserInfo', store.state.user.userId).then(user => {
// 拉取用户信息,通过用户权限和跳转的页面的name来判断是否有权
//限访问;access必须是一个数组,如:['super_admin'] ['super_admin', 'admin']
turnTo(to, user.access, next)
}).catch(() => {
next({
name: LOGIN_PAGE_NAME
})
})
}
}
/**
* 核心功能是beforeEach,全局的拦截器,可以帮助我们获取到用户跳转之前的所有请求
* 用户to过来大部分都是自动匹配过来的,匹配可以规矩path也可以根据name匹配
*匹配可以包括多个,上下级都有
*/
router.beforeEach((to, from, next) => {
iView.LoadingBar.start()
const token = getToken()
if (!token && to.name !== LOGIN_PAGE_NAME) {
// 未登录且要跳转的页面不是登录页
next({
name: LOGIN_PAGE_NAME // 跳转到登录页
})
} else if (!token && to.name === LOGIN_PAGE_NAME) {
// 未登陆且要跳转的页面是登录页
next() // 跳转
} else if (token && to.name === LOGIN_PAGE_NAME) {
// 已登录且要跳转的页面是登录页
next({
name: homeName // 跳转到homeName页
})
} else {
if (router.isAddRouters) {
gotoAssess(to, store, next)
} else {
// 没获取用户信息,说明没有获取路由菜单
getRouters(store.state.user.userId).then(routerArr => {
addRouters(routerArr)
gotoAssess(to, store, next)
})
}
}
})
router.afterEach(to => {
iView.LoadingBar.finish()
window.scrollTo(0, 0)
})
export default router
描述的可能不是很全,自己遇到的几个问题都再重点突出以下
- router定义的时候routes是固定的
- beforeEach 匹配path和name都可以匹配
- mate元信息可以自己随便搞
- import 不能随便用
期待你的关注,这里是悟耘开源,开源项目包括EasyPoi(快速完成Office操作工具包,开源中国GVP项目),风铃(基于springboot的快速开发平台),代码生成器等开源项目,悟耘开源致力于基础平台开发,希望帮助大家提高开发速度,提升开发质量,让大家远离996。关注我,获取分享开源路上的感悟和开发相关技术分享。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/34866.html