Vue Router进阶详解

导航守卫

若依框架登录鉴权详解(动态路由)_若依鉴权-CSDN博客

完整的导航解析流程

  1. 导航被触发

    • 当用户点击页面中的链接、使用编程式导航(如router.pushrouter.replace)或手动输入URL时,导航流程被触发。
  2. 在失活的组件里调用beforeRouteLeave守卫

    • 如果当前有激活的组件(即用户正在查看的组件),则在该组件内调用beforeRouteLeave守卫。这允许组件在离开之前执行一些清理工作或条件检查(如用户是否保存了更改)。
  3. 调用全局beforeEach守卫

    • 在路由实例上注册的全局beforeEach守卫会在导航确认之前被调用。这是一个全局的钩子,可以用于执行一些通用的检查或处理逻辑,如身份验证
  4. 在复用组件里调用beforeRouteUpdate守卫(Vue Router 2.2+):

    • 如果目标路由和当前路由使用相同的组件,并且只是参数发生了变化(如从一个用户页面导航到另一个用户页面,但两者都使用相同的User组件),则会在该组件内调用beforeRouteUpdate守卫。这允许组件在参数变化时更新其内容。
  5. 调用路由配置里的beforeEnter守卫

    • 在路由配置对象中定义的beforeEnter守卫会在导航到该路由之前被调用。这是一个路由独享的钩子,可以用于在该路由上执行一些特定的逻辑。
  6. 解析异步路由组件

    • 如果目标路由是一个异步组件,则此时会解析该异步组件。
  7. 在被激活的组件里调用beforeRouteEnter守卫

    • 在目标路由对应的组件内调用beforeRouteEnter守卫。这允许组件在渲染之前执行一些初始化工作。需要注意的是,此时组件实例尚未被创建,因此无法访问this。但可以通过向next函数传递一个回调函数来访问组件实例
  8. 调用全局beforeResolve守卫(Vue Router 2.5+):

    • 在导航被确认之前,并且在所有组件内守卫和异步路由组件被解析之后,调用全局beforeResolve守卫。这是一个全局的钩子,可以用于在导航确认之前执行一些额外的逻辑。
  9. 导航被确认

    • 此时,所有的守卫和钩子都已经被调用,并且没有守卫中断导航。路由实例现在会确认导航,并准备更新DOM。
  10. 调用全局afterEach钩子

    • 在导航完成后调用全局afterEach钩子。这是一个全局的钩子,不会接受next函数,也不会改变导航本身。它主要用于记录导航的详细信息或执行一些清理工作。
  11. 触发DOM更新

    • Vue Router会根据目标路由渲染相应的组件,并更新DOM以反映新的视图。
  12. 用创建好的实例调用beforeRouteEnter守卫中传给next的回调函数

    • 如果在beforeRouteEnter守卫中向next函数传递了一个回调函数,则此时会调用该回调函数,并将组件实例作为参数传递给它。这允许组件在渲染之后执行一些后续工作。

全局守卫(router.beforeEach与router.afterEach)

全局守卫是作用于整个Vue应用的守卫,它们会在任意路由发生改变时被调用。全局守卫主要包括全局前置守卫(router.beforeEach)和全局后置守卫(router.afterEach)。

  • 全局前置守卫 :在路由跳转之前执行,可以通过调用router.beforeEach方法注册。这些守卫会按照注册顺序依次执行,并且每个守卫都有机会中断导航过程。如果守卫函数返回false或调用next(false),则导航会被中断 。如果守卫函数不调用next()或调用next('/')next({ ... })进行重定向,则导航也会中断

  • 全局后置守卫 :在导航完成后被调用,不接受next函数也不可以中断导航。它们主要用于做一些清理工作或者修改状态。

    router.beforeEach((to, from, next) => {
    NProgress.start()
    if (getToken()) {
    //获取路由的mata.title属性,并存储在Vuex中
    to.meta.title && store.dispatch('settings/setTitle', to.meta.title)
    /* has token*/
    if (to.path === '/login') {
    next({ path: '/' })
    NProgress.done()
    } else {
    if (store.getters.roles.length === 0) {
    isRelogin.show = true
    // 判断当前用户是否已拉取完user_info信息
    store.dispatch('GetInfo').then(() => {
    isRelogin.show = false
    store.dispatch('GenerateRoutes').then(accessRoutes => {
    // 根据roles权限生成可访问的路由表
    console.log(accessRoutes);
    router.addRoutes(accessRoutes) // 动态添加可访问路由表
    //通过返回新的位置来触发重定向
    next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
    })
    }).catch(err => {
    store.dispatch('LogOut').then(() => {
    Message.error(err)
    next({ path: '/' })
    })
    })
    } else {
    next()
    }
    }
    } else {
    // 没有token
    if (whiteList.indexOf(to.path) !== -1) {
    // 在免登录白名单,直接进入
    next()
    } else {
    next(/login?redirect=${to.fullPath}) // 否则全部重定向到登录页
    NProgress.done()
    }
    }
    })

    router.afterEach(() => {
    NProgress.done()
    })

路由独享守卫(beforeEnter)

是作用于单个路由或一组路由的守卫 ,可以在路由配置中直接定义。这种守卫允许开发者针对特定的路由实施一些逻辑,例如验证用户是否有权限访问某个页面。路由独享守卫只有一个钩子函数beforeEnter它会在进入路由时触发,不会在参数、查询字符串或哈希值改变时触发

组件内守卫( beforeRouteEnterbeforeRouteUpdatebeforeRouteLeave。)

组件内守卫是作用于路由组件内的守卫,只能在路由组件中使用。这些守卫允许开发者在组件的生命周期钩子中控制路由导航。组件内守卫包括beforeRouteEnterbeforeRouteUpdatebeforeRouteLeave

  • beforeRouteEnter :在组件被创建之前调用,此时组件实例尚未被创建,因此无法访问this。可以通过向next函数传递一个回调函数来访问组件实例
  • beforeRouteUpdate在当前路由改变,但是该组件被复用时调用 。例如,对于一个带有动态参数的路径/foo/:id,在/foo/1/foo/2之间导航时,同一个Foo组件实例会被复用,此时会调用beforeRouteUpdate守卫。
  • beforeRouteLeave:在导航离开该组件的对应路由时被调用。它可用于在离开路由前进行一些操作,比如保存用户编辑的内容或询问用户是否确定离开。

动态路由

  1. 权限管理:在应用中,不同用户可能有不同的访问权限。通过动态路由,我们可以在用户登录后根据其权限动态添加或删除路由,从而控制用户对不同页面的访问。
  2. 模块懒加载:对于大型应用,为了优化性能,我们可以按需加载不同模块的路由。在用户访问某个模块时,再动态添加该模块的路由配置。
  3. 动态生成菜单:在一些后台管理系统中,菜单项和对应的路由可能是动态生成的。我们可以根据后台返回的菜单配置,动态生成对应的路由。
const router = createRouter({
  history: createWebHistory(),
  routes: [{ path: '/:articleName', component: Article }],
})
router.addRoute({ path: '/about', component: About })
//页面仍然会显示 Article 组件,我们需要手动调用 router.replace() 来改变当前的位置,并覆盖我们原来的位置
router.addRoute({ path: '/about', component: About })
// 我们也可以使用 this.$route 或 useRoute()
router.replace(router.currentRoute.value.fullPath)

在导航守卫中添加路由

如果你决定在导航守卫内部添加或删除路由,你不应该调用 router.replace(),而是通过返回新的位置来触发重定向:

store.dispatch('GenerateRoutes').then(accessRoutes => {
            // 根据roles权限生成可访问的路由表
            console.log(accessRoutes);
            router.addRoutes(accessRoutes) // 动态添加可访问路由表
            //通过返回新的位置来触发重定向
            next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
          })
--------------------------------------------------------------------------
router.beforeEach(to => {
  if (!hasNecessaryRoute(to)) {
    router.addRoute(generateRoute(to))
    // 触发重定向
    return to.fullPath
  }
})

过渡效果

原生CSS中transation与animation

CSS中的Transition(过渡效果)和Animation(动画)是实现网页动态效果的重要技术,能够提升用户体验,使网页看起来更加生动和吸引人。以下是两者的详细介绍:

一、CSS Transition(过渡效果)
  1. 基本概念

    CSS Transition允许元素从一种样式状态平滑地改变为另一种样式状态,通常用于简单的动态效果,如按钮的悬停状态、元素的显示和隐藏等。

  2. 主要属性

    • transition-property:指定应用过渡效果的CSS属性名称,如width、height、background-color等。也可以使用"all"来指定所有可动画属性。
    • transition-duration:定义过渡效果完成所需的时间,单位可以是秒(s)或毫秒(ms)。
    • transition-timing-function:描述过渡效果的速度曲线,如linear(线性)、ease(慢到快再到慢)、ease-in(慢到快)、ease-out(快到慢)和ease-in-out(慢到快再到慢,但比ease更平缓)。还可以使用cubic-bezier函数来自定义速度曲线。
    • transition-delay:定义过渡效果开始前的延迟时间,单位同样可以是秒(s)或毫秒(ms)。
    • transition:上述四个属性的简写形式,按顺序分别指定transition-property、transition-duration、transition-timing-function和transition-delay。
  3. 使用示例

    .box { 
    width: 100px; 
    height: 100px; 
    background-color: red; 
    transition: width 1s ease-in-out; 
    } 
    
    
    .box:hover { 
    width: 200px; 
    }
    

    当鼠标悬停在具有".box"类的元素上时,元素的宽度会从100px平滑地过渡到200px,过渡效果持续1秒,采用缓入缓出的时间函数。

  4. 注意事项

    • 过渡效果不会应用于display、visibility等少数CSS属性
    • 过渡效果在元素从不可见变为可见时不会触发,除非是通过改变opacity或其他可以产生类似效果的属性来实现可见性的变化。
    • 如果过渡效果的目标值与起始值相同,过渡效果将不会触发。
    • 过渡效果在元素或其父元素被隐藏(如display: none)时不会运行。
二、CSS Animation(动画)
  1. 基本概念

    CSS Animation比Transition更为强大,它允许创建更复杂的动画效果,可以包含多个步骤和关键帧。

  2. 主要属性

    • animation-name:指定要绑定到选择器的关键帧的名称。
    • animation-duration:定义动画完成一个周期需要多少秒或毫秒。
    • animation-timing-function:指定动画将如何完成一个周期,与Transition中的transition-timing-function类似,也可以使用cubic-bezier函数来自定义速度曲线。
    • animation-delay:定义动画什么时候开始,单位可以是秒(s)或毫秒(ms),也可以是负值以表示跳过部分动画。
    • animation-iteration-count:定义动画应该播放多少次,可以是具体次数或infinite(无限循环)。
    • animation-direction:定义是否循环交替反向播放动画,如normal(正向播放)、reverse(反向播放)、alternate(交替正向和反向播放)等。
    • animation-fill-mode:规定当动画不播放时(如动画完成时、有延迟未开始播放时)要应用到元素的样式,如none、forwards(动画结束时保持最后一帧的样式)等。
    • animation-play-state:指定动画是否正在运行或已暂停。
    • animation:上述属性的简写形式,按顺序分别指定各属性的值。
  3. 使用示例

    .box-max { 
    width: 100px; 
    height: 100px; 
    background-color: aqua; 
    animation-name: box1; 
    animation-duration: 3s; 
    } 
    
    
    @keyframes box1 { 
    0% { 
    opacity: 1; 
    } 
    100% { 
    opacity: 0.3; 
    } 
    }
    

    这个示例创建了一个名为".box-max"的元素,并应用了一个名为"box1"的动画。动画使元素的透明度从1逐渐变为0.3,持续时间为3秒。

  4. 注意事项

    • 使用Animation时,规需要配合@keyframes则来定义动画的关键帧。
    • 动画的性能可能会受到多个因素的影响,如动画的复杂度、元素的数量等。因此,在使用动画时需要注意性能优化,如避免对大量元素同时应用复杂的动画效果。

Vue中transition

<transition>组件会在其包裹的内容(一个元素或组件)进入和离开DOM时,自动应用过渡效果。这些过渡效果可以通过CSS过渡(transition)或CSS动画(animation)来实现。

常见属性

  1. name :用于指定过渡效果的名称。如果不指定,Vue会使用默认的类名前缀v-。指定后,Vue会使用指定的名称作为类名前缀,如fade-enter-active
  2. mode :用于设置过渡的模式。可以是in-out(先完成当前元素的过渡,然后新元素开始过渡)或out-in(先让当前元素过渡出去,然后新元素开始过渡)。默认是in-out
  3. type :指定过渡效果的类型,可以是transition(CSS过渡)或animation(CSS动画)。Vue 2.9.0+版本支持。如果不指定,Vue会根据元素的样式自动判断。
  4. duration:设置过渡效果的持续时间,单位是毫秒。可以是一个固定的值,也可以是一个对象,分别指定进入和离开的持续时间。Vue 2.9.0+版本支持。

常见钩子

  1. before-enter:进入过渡之前调用。
  2. enter:进入过渡被触发时调用。
  3. after-enter:进入过渡结束后调用。
  4. enter-cancelled:在进入过渡被取消时调用(比如通过切换v-if条件来取消过渡)。
  5. before-leave:离开过渡之前调用。
  6. leave:离开过渡被触发时调用。
  7. after-leave:离开过渡结束后调用。
  8. leave-cancelled:在离开过渡被取消时调用。
为过渡命名
<Transition name="fade">
  ...
</Transition>

.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.5s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}
与原生CSS的transition一同使用
<Transition name="slide-fade">
  <p v-if="show">hello</p>
</Transition>

/*
  进入和离开动画可以使用不同
  持续时间和速度曲线。
*/
.slide-fade-enter-active {
  transition: all 0.3s ease-out;
}

.slide-fade-leave-active {
  transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1);
}

.slide-fade-enter-from,
.slide-fade-leave-to {
  transform: translateX(20px);
  opacity: 0;
}
与原生animation一同使用
<Transition name="bounce">
  <p v-if="show" style="text-align: center;">
    Hello here is some bouncy text!
  </p>
</Transition>

.bounce-enter-active {
  animation: bounce-in 0.5s;
}
.bounce-leave-active {
  animation: bounce-in 0.5s reverse;
}
@keyframes bounce-in {
  0% {
    transform: scale(0);
  }
  50% {
    transform: scale(1.25);
  }
  100% {
    transform: scale(1);
  }
}
深层级过渡与显式过渡时长
<Transition name="nested">
  <div v-if="show" class="outer">
    <div class="inner">
      Hello
    </div>
  </div>
</Transition>

/* 应用于嵌套元素的规则 */
.nested-enter-active .inner,
.nested-leave-active .inner {
  transition: all 0.3s ease-in-out;
}

.nested-enter-from .inner,
.nested-leave-to .inner {
  transform: translateX(30px);
  opacity: 0;
}

/* ... 省略了其他必要的 CSS */

/*我们甚至可以在深层元素上添加一个过渡延迟,从而创建一个带渐进延迟的动画序列:*/

/* 延迟嵌套元素的进入以获得交错效果 */
.nested-enter-active .inner {
  transition-delay: 0.25s;
}

然而,这会带来一个小问题。默认情况下,<Transition> 组件会通过监听过渡根元素上的第一个 transitionend 或者 animationend 事件来尝试自动判断过渡何时结束。而在嵌套的过渡中,期望的行为应该是等待所有内部元素的过渡完成。

在这种情况下,你可以通过向 <Transition> 组件传入 duration prop 来显式指定过渡的持续时间 (以毫秒为单位)。总持续时间应该匹配延迟加上内部元素的过渡持续时间

<Transition :duration="550">...</Transition>

<Transition :duration="{ enter: 500, leave: 800 }">...</Transition>

keep-alive& transition &router-view

<router-view v-slot="{ Component }">
  <transition>
    <keep-alive>
      <component :is="Component" />
    </keep-alive>
  </transition>
</router-view>
相关推荐
运维-大白同学4 分钟前
将django+vue项目发布部署到服务器
服务器·vue.js·django
Myli_ing34 分钟前
HTML的自动定义倒计时,这个配色存一下
前端·javascript·html
dr李四维1 小时前
iOS构建版本以及Hbuilder打iOS的ipa包全流程
前端·笔记·ios·产品运营·产品经理·xcode
I_Am_Me_1 小时前
【JavaEE进阶】 JavaScript
开发语言·javascript·ecmascript
雯0609~1 小时前
网页F12:缓存的使用(设值、取值、删除)
前端·缓存
℘团子এ1 小时前
vue3中如何上传文件到腾讯云的桶(cosbrowser)
前端·javascript·腾讯云
学习前端的小z1 小时前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript
星星会笑滴1 小时前
vue+node+Express+xlsx+emements-plus实现导入excel,并且将数据保存到数据库
vue.js·excel·express
前端百草阁2 小时前
【TS简单上手,快速入门教程】————适合零基础
javascript·typescript
彭世瑜2 小时前
ts: TypeScript跳过检查/忽略类型检查
前端·javascript·typescript