[Vue-Router] Efecto dinámico de transición de enrutamiento

En Vue Router, puede usar los efectos de transición para agregar efectos de transición suaves al cambio de ruta para mejorar la experiencia del usuario. Las animaciones de transición se pueden implementar utilizando <transition>componentes Vue y transiciones CSS.

Uso básico:

  1. Para usar la animación para la navegación, v-slotse requiere API:
    <router-view #default="{route,Component}">
        <transition  :enter-active-class="`animate__animated ${route.meta.transition}`">
            <component :is="Component"></component>
        </transition>
    </router-view>
  1. Lo anterior utilizará la misma transición para todas las rutas. Si desea que los componentes de cada ruta tengan transiciones diferentes, puede combinar la metainformación con la dinámica y nameponerla <transition>:
declare module 'vue-router'{
    
    
     interface RouteMeta {
    
    
        title:string,
        transition:string,
     }
}
 
const router = createRouter({
    
    
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
    
    
      path: '/',
      component: () => import('@/views/Login.vue'),
      meta:{
    
    
         title:"登录页面",
         transition:"animate__fadeInUp",
      }
    },
    {
    
    
      path: '/index',
      component: () => import('@/views/Index.vue'),
      meta:{
    
    
         title:"首页!!!",
         transition:"animate__bounceIn",
      }
    }
  ]
})

Resumen de uso, agregue efectos de transición al cambiar de ruta:

  1. Primero, debe importar el componente en su proyecto Vue <transition>.

  2. Cuando sea necesario agregar transiciones (generalmente enrutamiento <router-view>), <transition>envuelva su contenido con .

  3. Agregue una clase CSS al <transition>componente para activar la transición cuando se cambia la ruta.

Ejemplo de demostración (los siguientes ejemplos usarán Animation.cssla biblioteca):

inserte la descripción de la imagen aquí
índice.ts

import {
    
     createRouter, createWebHistory } from 'vue-router'

declare module 'vue-router' {
    
    
  interface RouteMeta {
    
    
    title: string,
    transition: string
  }
}

export const router = createRouter({
    
    
  // import.meta.env.BASE_URL 应用的基本 URL。基本 URL 是指在你的应用部署到某个域名或子路径时,URL 的起始部分。例如,如果你的应用部署在 https://example.com/myapp/ 这个路径下,那么 import.meta.env.BASE_URL 就会是 /myapp/。
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
    
    
      path: '/',
      component: () => import('@/views/Login.vue'),
      meta: {
    
    
        title: "登录页",
        transition: "animate__fadeIn"
      }
    },
    {
    
    
      path: '/index',
      component: () => import('@/views/Index.vue'),
      meta: {
    
    
        title: "首页",
        transition: "animate__bounceOut"
      }
    },
  ],
})

loadingBar.vue

<template>
  <div class="wraps">
    <div ref="bar" class="bar"></div>
  </div>
</template>

<script setup lang="ts">
import {
      
       ref, onMounted } from 'vue'
let speed = ref<number>(1)
let bar = ref<HTMLElement>()
let timer = ref<number>(0)
const startLoading = () => {
      
      
  speed.value = 1
  let dom = bar.value as HTMLElement
  timer.value = window.requestAnimationFrame(function fn() {
      
      
    if (speed.value < 90) {
      
      
      speed.value += 1;
      dom.style.width = speed.value + '%'
      timer.value = window.requestAnimationFrame(fn)
    } else {
      
      
      speed.value = 1
      window.cancelAnimationFrame(timer.value)
    }
  })
}
const endLoading = () => {
      
      
  let dom = bar.value as HTMLElement
  setTimeout(() => {
      
      
    window.requestAnimationFrame(() => {
      
      
      speed.value = 100
      dom.style.width = speed.value + '%'
    })
  }, 500)

}

defineExpose({
      
       startLoading, endLoading })
</script>

<style scoped lang="less">
.wraps {
      
      
  width: 100%;
  position: fixed;
  height: 10px;
  top: 0;

  .bar {
      
      
    height: inherit;
    width: 0;
    background-color: #409eff;
  }
}
</style>

índice.vista

<template>
  <h1>
    我进来啦
  </h1>
</template>

<script setup lang="ts">

</script>

<style scoped></style>

Login.vue

<template>
  <div class="login">
    <el-card class="box-card">
      <el-form ref="form" :rules="rules" :model="formInline" class="demo-form-inline">
        <el-form-item prop="user" label="账号:">
          <el-input v-model="formInline.user" placeholder="请输入账号" />
        </el-form-item>
        <el-form-item prop="password" label="密码:">
          <el-input v-model="formInline.password" placeholder="请输入密码" type="password"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="onSubmit">登录</el-button>
        </el-form-item>
      </el-form>
    </el-card>
  </div>
</template>

<script setup lang="ts">
import {
      
       reactive, ref } from 'vue'
import {
      
       useRouter } from 'vue-router'
import type {
      
       FormItemRule, FormInstance } from 'element-plus';
import {
      
       ElMessage } from 'element-plus'

const router = useRouter()
type Form = {
      
      
  user: string,
  password: string
}
type  Rules = {
      
      
  [k in keyof Form]?: Array<FormItemRule>
}
const formInline = reactive<Form>({
      
      
  user: '',
  password: '',
})
const form = ref<FormInstance>()
const rules = reactive({
      
      
  user: [
    {
      
      
      required: true,
      message: '请输入账号',
      type: 'string',
    }
  ],
  password: [
    {
      
      
      required: true,
      message: '请输入密码',
      type: 'string',
    }
  ]
})

const onSubmit = () => {
      
      
  console.log('submit!', form.value)
  form.value?.validate((validate)=>{
      
      
    if (validate) {
      
      
      router.push('/index')
      localStorage.setItem('token', '1')
    } else {
      
      
      ElMessage.error('账号或密码错误')
    }
  })

}
</script>

<style scoped lang="less">
.login {
      
      
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}
</style>

aplicación.vue

<template>
  <router-view #default="{ Component, route }">
    <transition :enter-active-class="`animate__animated ${route.meta.transition}`">
    <component :is="Component"></component>
    </transition>
  </router-view>
</template>

<script setup lang="ts">
import 'animate.css'

</script>

<style>
/* 注意 style 标签 别加 scoped 不然设置宽高不生效 */
* {
      
      
  margin: 0;
  padding: 0;
}
html, body, #app {
      
      
  height: 100%;
  overflow: hidden;
}
</style>

principal.ts

import {
    
     createApp,createVNode,render } from 'vue'
import App from './App.vue'
import {
    
    router} from './router'
// import 引入
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import loadingBar from './components/loadingBar.vue'

const Vnode = createVNode(loadingBar)
render(Vnode,document.body)
const app = createApp(App)
app.use(router)
// use 注入 ElementPlus 插件
app.use(ElementPlus)

const whiteList = ['/']

// beforeEach 可以定义不止一个,vue会收集所有定义的路由钩子,所以next的作用不应该是跳转,而是使步骤进行到下一个你定义的钩子
router.beforeEach((to, from, next) => {
    
    
  document.title = to.meta.title
  Vnode.component?.exposed?.startLoading()
  // token每次都要跟后端校验一下是否过期
  if(whiteList.includes(to.path) || localStorage.getItem('token')){
    
    
    next()
  }else{
    
    
    next('/')
  }
})

router.afterEach((to, from) => {
    
    
  Vnode.component?.exposed?.endLoading()
})
app.mount('#app')

Se puede encontrar que hay un efecto de transición al cambiar a la página de inicio o la página de inicio de sesión.

Supongo que te gusta

Origin blog.csdn.net/XiugongHao/article/details/132302015
Recomendado
Clasificación