路由导航分析和三后台框架路由导航横向对比(没写完)

博主菜鸡,有错请各位指出

0、路由导航是什么

路由守卫

router.beforeEach:全局前置守卫。
router.beforeResolve:全局解析守卫。
router.afterEach:全局后置钩子。

组件守卫

beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave

路由独享守卫

beforeEnter

总结
导航被触发。
在失活的组件里调用 beforeRouteLeave 守卫。
调用全局的 beforeEach 守卫。
在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
在路由配置里调用 beforeEnter
解析异步路由组件。
在被激活的组件里调用 beforeRouteEnter
调用全局的 beforeResolve 守卫 (2.5+)。
导航被确认。
调用全局的 afterEach 钩子。
触发 DOM 更新。
调用 beforeRouteEnter守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

全局守卫

router.beforeEach((to,from,next)=>{})

router.beforeEach((to,from,next)=>{
  if(to.path == '/login' || to.path == '/register'){
    next();
  }else{
    alert('您还没有登录,请先登录');
    next('/login');
  }
})

router.afterEach((to,from)=>{})
只有两个参数,to:进入到哪个路由去,from:从哪个路由离。

组件内守卫

到达组件时
beforeRouteEnter:(to,from,next)=>{}

<script>
export default {
    data(){
        return{
            name:"Arya"
        }
    },
    beforeRouteEnter:(to,from,next)=>{
        next(vm=>{
            alert("hello" + vm.name);
        })
    }
}
</script>

离开组件时
beforeRouteLeave:(to,from,next)=>{}
点击其他组件时,判断是否确认离开。确认执行next();取消执行next(false),留在当前页面。

beforeRouteLeave:(to,from,next)=>{
        if(confirm("确定离开此页面吗?") == true){
            next();
        }else{
            next(false);
        }
    }

组件更新时
beforeRouteUpdate:(to,from,next)=>{}

  • 当组件内子路由发生变化时,会出发该导航守卫。
  • 当使用 beforeRouteUpdate 导航守卫时,应该等 next() 函数执行后,再获取 params 或 query 中的参数。
  beforeRouteUpdate (to, from, next) {
    console.log('路由更新之前:从to获取参数', to.params, '从this.$route获取参数', this.$route.params)
    next()
    console.log('路由更新之后:从to获取参数', to.params, '从this.$route获取参数', this.$route.params)
  },

路由独享守卫

beforeEnter:(to,from,next)=>{}
写进其中一个路由对象中,只在这个路由下起作用。

{
    path:"/login",
    name:"login",
    component:"/login",beforeEnter:(to,from,next)=>{
        next('/login')
    }
}

1、el-admin

1.1、router.afterEach:全局后置钩子

进度条结束

NProgress.done()

1.2、router.beforeEach:全局前置守卫

index.js

import router from './routers'
import store from '@/store'
import Config from '@/settings'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css'// progress bar style
import { getToken } from '@/utils/auth' // getToken from cookie
import { buildMenus } from '@/api/system/menu'
import { filterAsyncRouter } from '@/store/modules/permission'

NProgress.configure({ showSpinner: false })// NProgress Configuration

const whiteList = ['/login']// no redirect whitelist
router.beforeEach((to, from, next) => {
  if (to.meta.title) {//假如路由组件挂载的时候有写title,则是title-项目名称,Config.title配置了项目名称
    document.title = to.meta.title + ' - ' + Config.title
  }
  NProgress.start()//开启进度条
  if (getToken()) {
    if (to.path === '/login') {// 已登录且要跳转的页面是登录页,此时不能进登录页
      next({ path: '/' })//修改路由为login
      NProgress.done()
    } else {
      //这块Vuex没看懂
      if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
        store.dispatch('GetInfo').then(() => { // 拉取user_info
          // 动态路由,拉取菜单
          loadMenus(next, to)
        }).catch(() => {
          store.dispatch('LogOut').then(() => {
            location.reload() // 为了重新实例化vue-router对象 避免bug
          })
        })
        // 登录时未拉取 菜单,在此处拉取
      } else if (store.getters.loadMenus) {
        // 修改成false,防止死循环
        store.dispatch('updateLoadMenus')
        loadMenus(next, to)
      } else {
        next()//不满足其他条件,放行
      }
    }
  } else {
    /* has no token*/
    if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
      next()
    } else {
      next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
      NProgress.done()
    }
  }
})

export const loadMenus = (next, to) => {
  buildMenus().then(res => {
    const sdata = JSON.parse(JSON.stringify(res))
    const rdata = JSON.parse(JSON.stringify(res))
    const sidebarRoutes = filterAsyncRouter(sdata)
    const rewriteRoutes = filterAsyncRouter(rdata, false, true)
    rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })

    store.dispatch('GenerateRoutes', rewriteRoutes).then(() => { // 存储路由
      router.addRoutes(rewriteRoutes) // 动态添加可访问路由表
      next({ ...to, replace: true })
    })
    store.dispatch('SetSidebarRouters', sidebarRoutes)
  })
}

permission.js

import { constantRouterMap } from '@/router/routers'
import Layout from '@/layout/index'
import ParentView from '@/components/ParentView'

const permission = {
  state: {
    routers: constantRouterMap,
    addRouters: [],
    sidebarRouters: []
  },
  mutations: {
    SET_ROUTERS: (state, routers) => {
      state.addRouters = routers
      state.routers = constantRouterMap.concat(routers)
    },
    SET_SIDEBAR_ROUTERS: (state, routers) => {
      state.sidebarRouters = constantRouterMap.concat(routers)
    }
  },
  actions: {
    GenerateRoutes({ commit }, asyncRouter) {
      commit('SET_ROUTERS', asyncRouter)
    },
    SetSidebarRouters({ commit }, sidebarRouter) {
      commit('SET_SIDEBAR_ROUTERS', sidebarRouter)
    }
  }
}

export const filterAsyncRouter = (routers, lastRouter = false, type = false) => { // 遍历后台传来的路由字符串,转换为组件对象
  return routers.filter(router => {
    if (type && router.children) {
      router.children = filterChildren(router.children)
    }
    if (router.component) {
      if (router.component === 'Layout') { // Layout组件特殊处理
        router.component = Layout
      } else if (router.component === 'ParentView') {
        router.component = ParentView
      } else {
        const component = router.component
        router.component = loadView(component)
      }
    }
    if (router.children != null && router.children && router.children.length) {
      router.children = filterAsyncRouter(router.children, router, type)
    } else {
      delete router['children']
      delete router['redirect']
    }
    return true
  })
}

function filterChildren(childrenMap, lastRouter = false) {
  var children = []
  childrenMap.forEach((el, index) => {
    if (el.children && el.children.length) {
      if (el.component === 'ParentView') {
        el.children.forEach(c => {
          c.path = el.path + '/' + c.path
          if (c.children && c.children.length) {
            children = children.concat(filterChildren(c.children, c))
            return
          }
          children.push(c)
        })
        return
      }
    }
    if (lastRouter) {
      el.path = lastRouter.path + '/' + el.path
    }
    children = children.concat(el)
  })
  return children
}

export const loadView = (view) => {
  return (resolve) => require([`@/views/${view}`], resolve)
}
export default permission

2、Vue-admin-beautiful

。。。进度条居然换了个名就VabProgress了
大同小异,但是横向对比el-admin很多做了配置truefalse,使用起来很自由

/**
 * @copyright chuzhixin 1204505056@qq.com
 * @description 路由守卫,目前两种模式:all模式与intelligence模式
 */
import router from "@/router";
import { deepClone } from "@/utils/clone";
import store from "@/store";
import VabProgress from "nprogress";
import "nprogress/nprogress.css";
import getPageTitle from "@/utils/pageTitle";
import {
  authentication,
  loginInterception,
  progressBar,
  recordRoute,
  routesWhiteList,
} from "./settings";
import { constantRoutes } from "@/router/defaultRouter.js";
import { isNull } from "@/utils/validate";

VabProgress.configure({
  easing: "ease",
  speed: 500,
  trickleSpeed: 200,
  showSpinner: false,
});

router.beforeResolve(async (to, from, next) => {
  if (progressBar) VabProgress.start();
  let hasToken = false;
  let token = store.getters["user/accessToken"];
  let access_token = window.sessionStorage.getItem("access_token");

  if (!isNull(token) && token.length > 0) {
    hasToken = true;
  }
  if (to.path == "/admin") {
    next(`/login`);
  }

  if (!loginInterception) hasToken = true;
  //存在Token
  if (hasToken) {
    if (to.path === "/login") {
      next({ path: "/" });
      if (progressBar) VabProgress.done();
    } else {//这里也是在判断权限
      const hasPermissions =
        store.getters["user/permissions"] &&
        store.getters["user/permissions"].length > 0;

      if (hasPermissions) {
        next();
      } else {
        try {
          let permissions;
          if (!loginInterception) {
            //settings.js loginInterception为false时,创建虚拟权限
            await store.dispatch("user/setPermissions", ["admin"]);
            permissions = ["admin"];
          } else {
            permissions = await store.dispatch("user/getUserInfo");
          }
          let accessRoutes = [];
          if (authentication === "intelligence") {//intelligence和all两种方式,前者后端权限只控制permissions不控制view文件的import(前后端配合,减轻后端工作量),all方式完全交给后端前端只负责加载
            accessRoutes = await store.dispatch(
              "routes/setRoutes",
              permissions
            );
          } else if (authentication === "all") {
            let asyncRoutes = await store.dispatch("routes/setAllRoutes");
            accessRoutes = deepClone([...constantRoutes, ...asyncRoutes]);
          }
          router.addRoutes(accessRoutes);
          next({ ...to, replace: true });
        } catch {//异常捕捉
          await store.dispatch("user/resetAccessToken");
          if (progressBar) VabProgress.done();
        }
      }
    }
  }

  //Php平台 token校验
  else if (access_token) {
    //对令牌进行有效性校验, 无效跳转到登录页面

    //令牌有效

    if (to.path === "/") {
      next({ path: "/platform" });
      if (progressBar) VabProgress.done();
    } else {
      next();
      if (progressBar) VabProgress.done();
    }
  }

  //没有Token
  else {
    if (routesWhiteList.indexOf(to.path) !== -1) {
      //存在setting设置的url, 放行跳转
      next();
    }
    //不存在设置url, 跳转到登录页面
    else {
      if (recordRoute) {//recordRoute布尔值,表示token失效回退到登录页时是否记录本次的路由,false不记录
        next(`/login?redirect=${to.path}`);
      } else {
        if (progressBar) VabProgress.done();
        return next("/userLogin");
      }
      if (progressBar) VabProgress.done();
    }
  }

  document.title = getPageTitle(to.meta.title); //设置标题
});

router.afterEach(() => {
  if (progressBar) VabProgress.done();
});

3、Blade-X

/**
 * 全站权限配置
 *
 */
import router from './router/router'
import store from './store'
import {validatenull} from '@/util/validate'
import {getToken} from '@/util/auth'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
NProgress.configure({showSpinner: false});
const lockPage = store.getters.website.lockPage; //锁屏页
router.beforeEach((to, from, next) => {
  const meta = to.meta || {};
  const isMenu = meta.menu === undefined ? to.query.menu : meta.menu;
  store.commit('SET_IS_MENU', isMenu === undefined);
  if (getToken()) {
    if (store.getters.isLock && to.path !== lockPage) { //如果系统激活锁屏,全部跳转到锁屏页
      next({path: lockPage})
    } else if (to.path === '/login') { //如果登录成功访问登录页跳转到主页
      next({path: '/'})
    } else {
      //如果用户信息为空则获取用户信息,获取用户信息失败,跳转到登录页
      if (store.getters.token.length === 0) {
        store.dispatch('FedLogOut').then(() => {
          next({path: '/login'})
        })
      } else {
        const value = to.query.src || to.fullPath;
        const label = to.query.name || to.name;
        const meta = to.meta || router.$avueRouter.meta || {};
        const i18n = to.query.i18n;
        if (to.query.target) {
          window.open(value)
        } else if (meta.isTab !== false && !validatenull(value) && !validatenull(label)) {
          store.commit('ADD_TAG', {
            label: label,
            value: value,
            params: to.params,
            query: to.query,
            meta: (() => {
              if (!i18n) {
                return meta
              }
              return {
                i18n: i18n
              }
            })(),
            group: router.$avueRouter.group || []
          });
        }
        next()
      }
    }
  } else {
    //判断是否需要认证,没有登录访问去登录页
    if (meta.isAuth === false) {
      next()
    } else {
      next('/login')
    }
  }
})

router.afterEach(() => {
  NProgress.done();
  let title = store.getters.tag.label;
  let i18n = store.getters.tag.meta.i18n;
  title = router.$avueRouter.generateTitle(title, i18n);
  //判断登录页的情况
  if (router.history.current.fullPath === "/login") {
    title = "登录";
  }
  //根据当前的标签也获取label的值动态设置浏览器标题
  router.$avueRouter.setTitle(title);
});

4、路由其他

//本身就是使用了插槽,此组件在安装插件的时候已经全局注册了组件,就不用额外注册了
 <router-view/>

4.1、三种模式

在这里插入图片描述
改变hash都不会导致页面刷新,location.hash=‘#blog’
history的无刷新效果,如下

history.pushState(null,null,'/blog')

4.2、导航a标签改为routerlink更好,取消刷新

在这里插入图片描述
最开始访问首页,有个routerview占位区域,一开始页面刷新,执行JS,创建vue,渲染。
一看history模式,就把路径/得到了,然后去路由规则去匹配,匹配到首页,然后把首页渲染到routerview占位区域。

点击了文章链接,根据你的模式进行切换,是hash切换hash部分,是history切换history部分,vue-router监控到了,读取到路径是blog,重新匹配文章组件,渲染到占位区域。

4.3、激活状态匹配

精确匹配
在这里插入图片描述在这里插入图片描述
.router-link-active样式名支持修改

4.4、命名路由name

用name匹配不用path匹配
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值