(一)vue中的vue-router:
1. 安装vue-router:一般脚手架自带安装好了vue-router。
2. vue项目中引入和使用vue-router:更详细的使用参考:https://blog.csdn.net/qq_42231156/article/details/82949962。
//在router.js文件中配置路由
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router); //vue中挂载vue-router插件
const router=new Router({
mode:'history', //模式包括hash、history、abstract
base:process.env.BASE_URL, //设置访问地址的域名,根据开发环境和正式环境不同自动配置
routes:[
{
path:'/home',
name:'home',
props:true, //表示允许组件props:{}中接受name参数值,然后可以直接渲染在页面{{name}}
alias:'/home_page',//为路由取别名,即访问"/home_page"和访问"/home"和通过name:"home",访问的效果是一样的
meta:[auth:true], //是否开启路由权限校验,在路由守卫中,to.meta.auth && isLogin 即需要登录,且已经登录才会跳转路由
components:()=>import('./view/home.vue') //路由按需引入,按需加载,避免一次性加载过多的页面。
beforeEnter(from,to,next){ //独享路由守卫
},
children:[ //嵌套子路由
{
path:'detail:id', // 相当于/home/detail:id,{{$route.params.id}}或者如果props:true时,可以在组件中通过props:{id:{type:String,default:""}}取得参数值
name:'detail',
components:()=>import('./view/detail.vue')
}
]
}
]
})
//1. 后端返回登录人权限(超级管理员,普通管理员...)前端配置路由权限哪些可以跳转,哪些页面不能跳转。
//2. 后端直接返登录人可以返回跳转页面的权限页面列表,前端映射到响应的权限页面,用户只能登录后端返回的权限页面。
router.beforeEach((to,form,next)=>{ //路由全局守卫,已经登录就跳转要去的路由,没有登录就跳转登录页面
to.meta.auth && localstorage.getItem('isLogin')?next():next('/login');
})
router.beforeResolve((to,form,next)=>{}) //路由全局守卫
router.afterEach((to,form)=>{}) //路由全局守卫
export default router
//在main.js文件中配置router
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
3. vue-router中的路由守卫:包括全局守卫,独享守卫,组件内守卫。
(二)封装简易的ARouter.js:
原理:声明一个ARouter类挂载一个install方法,作为插件被vue使用(即Vue.use(ARouter))时,即执行ARouter类的install方法时将Vue作为参数传递进install方法中,挂载Vue全局混合Vue.mixins()(即所有vue组件执行时都会先执行混合),即在每个组件创建之前,查看该组件是否有this.$option.router,即是否是根组件,只有根组件才会有this.$option.router,在根组件时将路由实例挂载在vue全局上,也就是每个组件都可以调用$router,并执行ARouter类的init()初始化方法(即执行监听url的变化,配置路由的解析,.实现全局组件(router-link和router-view))。具体代码如下:
注意:简易封装的ARouter不能实现路由嵌套(存在无限嵌套循环),只考虑有hash的情况。
1. 创建一个ARouter.js文件:
//新建一个ARouter.js文件,封装简易的router
let Vue;
class ARouter{ //实现简单的vue-router
static install(_vue){ // 这里Vue.use(ARouter)时执行install(),install里面的this指向Vue实例
Vue=_vue;
Vue.mixin({ //Vue的全局混合
beforeCreate(){
if(this.$option.router){ //仅仅在根组件的创建前声明周期上执行一次混合
Vue.prototype.$router=this.$option.router; //在vue上挂载$router,实现在任何组件中都可以使用$router
this.$option.router.init(); //这里的this指的是new Vue() 而不是 ARouter的实例化
}
},
})
}
constructor(options){
this.$option=options; //这里的this指的是ARouter实例
this.routerMap={}; //用于存放配置的路由解析,即将routes数组,转换为对象映射
this.app=new Vue({ //数据响应式路由
data:{
current:'/' //当前路径的根路径,当这个值变化时,可以动态的让(router-link和router-view)组件重新渲染
}
})
}
init(){ //路由初始化时执行:
this.bindEvents(); //1.监听url的变化
this.createRouteMap(); //2.配置路由的解析
this.initComponent(); //3.实现全局组件(router-link和router-view)
}
bindEvents(){
window.addEventListener('load',this,onHashChange.bind(this),false); //页面加载完成时执行,为了保持onHashChange函数里面的this保持是ARouter实例而不是window,所有需要bind(this)
window.addEventListener('hashchange',this.onHashChange.bind(this),false); //当URL的片段标识符更改时,将触发hashchange事件(跟在#符号后面的URL部分,包括#符号)
}
onHashChange(e){ //e是路由变化时的对象
let hash=window.location.hash.slice(1) || "/"
let router=this.routerMap[hash]; //路由变化之后的的路由对象(但是还没有跳转)如:
//{path:"home",component: Home,beforeEnter(from,to,next){})}
let fromPath,toPath;
if(e.newURL){
fromPath=e.oldURL.split("#")[1]
toPath=e.newURL.split("#")[1]
}else{
fromPath='';
toPath=hash;
}
if(router.beforeEnter){
router.beforeEnter(fromPath,toPath,()=>{
this.app.current=hash; //此时才执行跳转路由,因为new Vue的current值改变。重新渲染
})
}else{
this.app.current=hash;
}
//window.location.hash='#/down?id=1',indow.location.hash.slice(1)='/down?id=1',思考:当页面url不是hash模式的处理?
}
createRouteMap(){ //new ARouter({routes:[]})里面的routes
this.$option.routes.forEach((item)=>{
this.routerMap[item.path]=item; //形成键值对 {'/':Home,'/about':About}之类的页面路由path和页面一一对应起来
})
}
initComponent(){
let _this=this;
Vue.component('router-link',{ //在Vue中注册全局组件<router-link to='/about'>关于</router-link>
props:{
to:{
type:String,
default:""
}
},
render(h){ //虚拟dom, h(tag,data,children),这里的this指的是router-link组件
return h('a',{
attrs:{
href:"#"+this.to //存在hash的情况是
}
},[this.$slots.default]) //this.$slots.default是匿名插槽相当于文本内容‘关于’
}
})
Vue.component('router-view',{ //在Vue中注册全局组件<router-view />
render(h){ //虚拟dom, h(tag,data,children)
const comp=_this.routerMap[_this.app.current].component;
return h(comp)
}
})
}
}
export default new ARouter({
routes :[
{
path: '/',
name: 'home',
component: Home,
beforeEnter(from,to,next){ //独享路由守卫
},
}
]
})
2.在main.js中调用ARouter.js:
import Vue from 'vue'
import App from './App.vue'
import ARouter from './ARouter.js'
Vue.use(ARouter); //即相当于调用ARouter的install方法,并把Vue作为参数传递进去。
new Vue({
ARouter,
render: h => h(App)
}).$mount('#app')