切换至深色主题
vue-router
安装配置
> pnpm install vue-router@4路由配置结构
- index.ts
// index.ts
import { createRouter, createWebHistory } from 'vue-router';
import routesList from './routes';
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
scrollBehavior: () => ({ top: 0 }),
routes: routesList
});
export default router;- routes.ts
import type { RouteRecordRaw } from 'vue-router';
import { routerAccount } from './modules/account';
const routesList: RouteRecordRaw[] = [
{
path: '/',
name: 'index',
component: () => import('@/views/index.vue'),
meta: {
index: 0
}
},
...routerAccount(),
{
path: '/:catchAll(.*)',
name: 'catchError',
component: () => import('@/views/catch-error/error.vue'),
meta: {
index: 9999
}
}
];- modules/account.ts
export function routerAccount() {
const route = [
{
path: '/account',
name: 'account',
meta: {
index: 200
},
children: [
{
path: 'enroll',
name: 'accountEnroll',
component: () => import('@/views/account/enroll.vue'),
meta: {
index: 210
}
}
]
}
];
return route;
}API接口
// 第三方资源类库或插件
import {
RouterLink,
RouterView,
START_LOCATION,
createMemoryHistory,
createRouter,
createRouterMatcher,
createWebHashHistory,
createWebHistory,
isNavigationFailure,
matchedRouteKey,
onBeforeRouteLeave,
onBeforeRouteUpdate,
parseQuery,
routeLocationKey,
routerKey,
routerViewLocationKey,
stringifyQuery,
useLink,
useRoute,
useRouter,
viewDepthKey,
} from 'vue-router';
/**
* @当前业务
* 具体逻辑实现代码
*/
const { proxy: { $nextTick, $forceUpdate, $slots } } = getCurrentInstance();
const router = useRouter(); // 返回路由器实例。相当于在模板中使用 $router。
const route = useRoute(); // 返回当前的路由地址。相当于在模板中使用 $route。
// 当前路由
console.log(route.path);
onMounted(() => {
$forceUpdate()
}
$nextTick(() => {
//
})
onBeforeRouteUpdate(async (to, from) => {
});
onBeforeRouteLeave(async (to, from) => {
//
});
// 路由
const switchPath = (path: string) => {
router.push({ path });
};路由按需加载(懒加载)
当打包构建应用时,JavaScript 包会变得非常大,影响页面加载,把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就会更加高效。
const routes: Array<RouteRecordRaw> = [
{
path: '/article',
component: import(/* webpackChunkName: "index" */ '@/components/index.vue')
}
];动态路由
const routes: Array<RouteRecordRaw> = [
{
path: '/article/:id',
component: Article
}
];完整的导航解析流程
- 导航被触发。
- 在失活的组件里调用 beforeRouteLeave 守卫。
- 调用全局的 beforeEach 守卫。
- 在重用的组件里调用 beforeRouteUpdate 守卫(2.2+)。
- 在路由配置里调用 beforeEnter。
- 解析异步路由组件。
- 在被激活的组件里调用 beforeRouteEnter。
- 调用全局的 beforeResolve 守卫(2.5+)。
- 导航被确认。
- 调用全局的 afterEach 钩子。
- 触发 DOM 更新。
- 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。
beforeunload 事件
当浏览器窗口关闭或者刷新时,会触发 beforeunload 事件。当前页面不会直接关闭,可以点击确定按钮关闭或刷新,也可以取消关闭或刷新。
window.addEventListener('beforeunload', (event) => {
// Cancel the event as stated by the standard.
event.preventDefault();
// Chrome requires returnValue to be set.
event.returnValue = '';
});路由转场动画
<template>
<div class="com-frame component-container">
<router-view v-slot="{ Component }" class="com-frame router-view">
<keep-alive>
<transition name="el-zoom-in-center" mode="out-in">
<component :is="Component" />
</transition>
</keep-alive>
</router-view>
</div>
</template>
<script setup lang="ts">
// 第三方资源类库或插件
import { ref, watchEffect, watch } from "vue";
import { RouterView, useRouter, useRoute } from 'vue-router';
/**
* @当前业务
* 具体逻辑实现代码
*/
const router = useRouter();
const route = useRoute();
watch(router.currentRoute, (newValue, oldValue) => {
console.info('路由: ', newValue, oldValue);
}, { deep: true });
</script>
<style lang="scss" scoped>
</style>路由转场动画
路由进入与离开,前进与后退转场切换动画。
<template>
<div id="fujinhuo" class="com-frame com-flexh">
<!--旧语法-->
<transition :name="swipeAnimate">
<router-view class="router-view"></router-view>
</transition>
<!--Vue3语法-->
<router-view v-slot="{ Component }">
<transition :name="swipeAnimate">
<keep-alive>
<component :is="Component" />
</keep-alive>
</transition>
</router-view>
</div>
</template>
<script>
export default {
name: 'fujinhuo',
data() {
return {
routeList: [
{ route: '/message/index', icon: '', text: '消息', active: false, css: 'font-size:.17rem;'},
{ route: '/goods/index', icon: '', text: '购物', active: false, css: 'font-size:.18rem;'},
{ route: '/nearby/index', icon: '', text: '附近', active: false, css: 'font-size:.25rem;'},
{ route: '/activity/index', icon: '', text: '活动', active: false, css: 'font-size:.18rem;'},
{ route: '/account/index', icon: '', text: '我的', active: false, css: 'font-size:.18rem;'}
],
swipeAnimate: ""
}
},
components: {},
watch: {
$route(to, from) {
this.routeList.forEach((idx)=> {
idx.active = false;
if (to.path == idx.route) {
idx.active = true;
}
});
//路由转场动画
if (typeof to.meta.index !== 'number' || typeof from.meta.index !== 'number') {
return ;
}
if (to.meta.index > from.meta.index) {
this.swipeAnimate = "slide-left";
return;
}
this.swipeAnimate = "slide-right";
}
},
methods: {
changeItem(dx) {
this.$router.push({
path: dx.route
});
}
}
}
</script>
<style type="text/css">
@use "~@/assets/css/default.css";
@use "~@/assets/css/public.css";
.slide-right-enter-active, .slide-right-leave-active, .slide-left-enter-active, .slide-left-leave-active {
will-change: transform;
transition: all 200ms;
position: absolute;
}
.slide-right-enter {
opacity: 0;
transform: translate3d(-100%, 0, 0);
}
.slide-right-leave-active {
opacity: 0;
transform: translate3d(100%, 0, 0);
}
.slide-left-enter {
opacity: 0;
transform: translate3d(100%, 0, 0);
}
.slide-left-leave-active {
opacity: 0;
transform: translate3d(-100%, 0, 0);
}
</style>