vue3+ts+vite 路由详解
vue3+ts+vite 路由详解
·
安装
1.首先创建项目
npm init vite@latest
输入文件名,选择Vue、TypeScript
2.vscode打开项目,安装router,less,less-loader,@types/node
npm i vue-router -S
npm i less less-loader -S
npm i @types/node -D
npm install pinia
npm install animate.css --save
*注意 Vue3中router要安装4版本,3版本的router语法和4不一样。
3.在components中创建login.vue和register.vue文件
<template>
<div>我是注册组件</div>
</template>
<script setup lang="ts"></script>
<style scoped></style>
4.在src下创建router文件夹,创建index.ts文件
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
// 路由类型:RouteRecordRaw
const routes: Array<RouteRecordRaw> = [
{
path: "/",
component: () => import("../components/login.vue"),
},
{
path: "/register",
component: () => import("../components/register.vue"),
},
];
const router = createRouter({
// 路由模式
history: createWebHistory(),
routes,
});
export default router;
5.在main.ts中引入并注册router
import { createApp } from "vue";
import App from "./App.vue";
// 引入router
import router from "./router";
// .ues(router) 注册router
createApp(App).use(router).mount("#app");
6.在app.vue中写路由出口才能显示路由页面
<template>
<!-- 切换路由 -->
<router-link to="/">注册</router-link>
<router-link to="/register">登录</router-link>
<!-- 路由出口 -->
<router-view></router-view>
</template>
<script setup lang="ts"></script>
<style scoped></style>
路由模式
命名路由
1.将router下index.ts文件里的路由命名
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
// 路由类型:RouteRecordRaw
const routes: Array<RouteRecordRaw> = [
{
path: "/",
// 命名
name: "Login",
component: () => import("../components/login.vue"),
},
{
path: "/register",
// 命名
name: "Register",
component: () => import("../components/register.vue"),
},
];
const router = createRouter({
// 路由模式
history: createWebHistory(),
routes,
});
export default router;
2.app.vue中使用
<template>
<!-- 切换路由 -->
<router-link :to="{ name: 'Login' }">注册</router-link>
<router-link :to="{ name: 'Register' }">登录</router-link>
<!-- 路由出口 -->
<router-view></router-view>
</template>
<script setup lang="ts"></script>
<style scoped></style>
编程式导航
<template>
<!--第一种方式 hash -->
<!-- <button @click="toPage('/')">登录</button>
<button @click="toPage('register')">注册</button> -->
<!--第二种方式 命名 -->
<button @click="toPage('Login')">登录</button>
<button @click="toPage('Register')">注册</button>
<!-- 路由出口 -->
<router-view></router-view>
</template>
<script setup lang="ts">
// 引入useRouter
import { useRouter } from "vue-router";
// 使用router
const router = useRouter();
const toPage = (url: string) => {
router.push({
// hash形式
// path: url,
// 命名形式
name: url,
});
};
</script>
<style scoped></style>
路由传参
*注意下载 JSON to TS 插件,选中json文件(ctrl+shift+alt+s)可以转为ts文件
1.path,query传参
<template>
<div>
<ul v-for="item in data" :key="item.id">
<li>{{ item.name }}</li>
<li>{{ item.age }}</li>
<button @click="toJson(item)">发送</button>
</ul>
</div>
</template>
<script setup lang="ts">
// 数据源
import { data } from "./list.json";
// 传数据的组件
import { useRouter } from "vue-router";
const router = useRouter();
// 定义类型
type Item = {
name: string;
age: number;
id: number;
};
const toJson = (item: Item) => {
router.push({
path: "/",
query: item,
});
};
</script>
<style scoped></style>
<template>
<div>{{ route.query.name }}</div>
<div>{{ route.query.age }}</div>
</template>
<script setup lang="ts">
// 接收数据的组件
import { useRoute } from "vue-router";
const route = useRoute();
</script>
<style scoped></style>
2.name,params传参
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
// 路由类型:RouteRecordRaw
const routes: Array<RouteRecordRaw> = [
{
path: "/",
name: "Father",
component: () => import("../components/father.vue"),
},
{
// 因为params传参是保存在内存中,所以接收参数的页面刷新会丢失数据
// params传参需要配合动态路由参数一起使用就不会有上面的问题
path: "/child/:id",
name: "Child",
component: () => import("../components/child.vue"),
},
];
const router = createRouter({
// 路由模式
history: createWebHistory(),
routes,
});
export default router;
<template>
<div>
<ul v-for="item in data" :key="item.id">
<li>{{ item.name }}</li>
<li>{{ item.age }}</li>
<button @click="toJson(item)">发送</button>
</ul>
</div>
</template>
<script setup lang="ts">
import { data } from "./list.json";
import { useRouter } from "vue-router";
const router = useRouter();
type Item = {
name: string;
age: number;
id: number;
};
const toJson = (item: Item) => {
router.push({
name: "Child",
params: {
id: item.id,
},
});
};
</script>
<style scoped></style>
<template>
<div>{{ item?.name }}</div>
<div>{{ item?.age }}</div>
<div>{{ item?.id }}</div>
</template>
<script setup lang="ts">
import { data } from "./list.json";
import { useRoute } from "vue-router";
const route = useRoute();
// 接收参数
const item = data.find((v) => v.id === Number(route.params.id));
</script>
<style scoped></style>
嵌套路由
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
// 路由类型:RouteRecordRaw
const routes: Array<RouteRecordRaw> = [
{
// 父路由
path: "/user",
component: () => import("../components/father.vue"),
// 子路由
children: [
{
path: "",
component: () => import("../components/child1.vue"),
},
{
path: "child2",
component: () => import("../components/child2.vue"),
},
],
},
];
const router = createRouter({
// 路由模式
history: createWebHistory(),
routes,
});
export default router;
<template>
<div>
父路由
<router-view></router-view>
<router-link to="/user">child1</router-link>
<router-link to="/user/child2">child2</router-link>
</div>
</template>
<script setup lang="ts"></script>
<style scoped></style>
命名视图
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
// 路由类型:RouteRecordRaw
const routes: Array<RouteRecordRaw> = [
{
path: "/",
components: {
default: () => import("../components/layout/menu.vue"),
header: () => import("../components/layout/header.vue"),
content: () => import("../components/layout/content.vue"),
},
},
];
const router = createRouter({
// 路由模式
history: createWebHistory(),
routes,
});
export default router;
<script setup lang="ts"></script>
<template>
<div>
<router-view></router-view>
<router-view name="header"></router-view>
<router-view name="content"></router-view>
</div>
</template>
<style scoped></style>
重定向/别名
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
// 路由类型:RouteRecordRaw
const routes: Array<RouteRecordRaw> = [
{
path: "/",
component: () => import("../components/login.vue"),
// 字符串形式重定向
// redirect: "/menu",
// 对象形式重定向
// redirect: { path: "/menu" },
// 函数形式重定向
redirect(to) {
return {
path: "/content",
query: to.query,
};
},
alias: ["/root", "/lala"], // 设置别名(为重定向服务)
children: [
{
path: "/menu",
components: {
default: () => import("../components/layout/menu.vue"),
},
},
{
path: "/content",
components: {
aaa: () => import("../components/layout/header.vue"),
bbb: () => import("../components/layout/content.vue"),
},
},
],
},
];
const router = createRouter({
// 路由模式
history: createWebHistory(),
routes,
});
export default router;
配置别名
import { defineConfig } from "vite";
import { fileURLToPath, URL } from "url";
import vue from "@vitejs/plugin-vue";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
// 配置别名
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
},
});
注意:如果在vite.config.ts配置别名时,出现 找不到模块“xxx”或其相应的类型声明 这种报错时,需要安装 “@types/node” 模块,处理配置别名不生效的问题
npm i @types/node -D
导航守卫
loadingBar.vue
<template>
<div class="wraps">
<div ref="bar" class="bar"></div>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
let speed = ref<number>(1);
let bar = ref<HTMLElement>();
let timer = ref<number>(0);
const startLoading = () => {
let dom = bar.value as HTMLElement;
speed.value = 1;
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 {
position: fixed;
top: 0;
width: 100%;
height: 2px;
.bar {
height: inherit;
width: 0;
background: blue;
}
}
</style>
main.ts
import { createApp, createVNode, render } from "vue";
import App from "./App.vue";
import router from "./router";
import ElementUI from "element-plus";
import "element-plus/dist/index.css";
import loadingBar from "./components/loadingBar.vue";
const app = createApp(App);
app.use(router);
app.use(ElementUI);
app.mount("#app");
// 设置白名单(允许直接跳转的路由)
const whileList = ["/"];
// 设置前置守卫
router.beforeEach((to, from, next) => {
if (whileList.includes(to.path) || localStorage.getItem("token")) {
next();
Vnode.component?.exposed?.startLoading();
} else {
next("/");
}
});
const Vnode = createVNode(loadingBar);
render(Vnode, document.body);
console.log(Vnode);
// 设置后置守卫(一般用做导航完成的loading页面)
router.afterEach((to, from) => {
Vnode.component?.exposed?.endLoading();
});
to: Route, 即将要进入的目标 路由对象;
from: Route,当前导航正要离开的路由;
next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。
路由元信息
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
// 定义路由元信息meta的title的类型
declare module "vue-router" {
interface RouteMeta {
title: string;
}
}
// 路由类型:RouteRecordRaw
const routes: Array<RouteRecordRaw> = [
{
path: "/",
component: () => import("@/views/login.vue"),
// 设置路由元信息
meta: {
title: "登录页面",
},
},
{
path: "/register",
component: () => import("@/views/register.vue"),
// 设置路由元信息
meta: {
title: "注册页面",
},
},
];
const router = createRouter({
// 路由模式
history: createWebHistory(),
routes,
});
export default router;
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import ElementUI from "element-plus";
import "element-plus/dist/index.css";
const app = createApp(App);
app.use(router);
app.use(ElementUI);
app.mount("#app");
// 设置白名单(允许直接跳转的路由)
const whileList = ["/"];
// 设置前置守卫
router.beforeEach((to, from, next) => {
// 设置路由元信息
document.title = to.meta.title;
if (whileList.includes(to.path) || localStorage.getItem("token")) {
next();
} else {
next("/");
}
});
路由过度动效
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
// 定义title的类型
declare module "vue-router" {
interface RouteMeta {
title: string;
transition: string;
}
}
// 路由类型:RouteRecordRaw
const routes: Array<RouteRecordRaw> = [
{
path: "/",
component: () => import("@/views/login.vue"),
// 设置路由元信息
meta: {
title: "登录页面",
// 设置路由动效类名(基于animate动画库)
transition: "animate__bounceIn",
},
},
{
path: "/register",
component: () => import("@/views/register.vue"),
// 设置路由元信息
meta: {
title: "注册页面",
// 设置路由动效类名(基于animate动画库)
transition: "animate__fadeInUpBig",
},
},
];
const router = createRouter({
// 路由模式
history: createWebHistory(),
routes,
});
export default router;
app.vue
<script setup lang="ts">
import "animate.css";
</script>
<template>
<div>
// 插槽
<router-view #default="{ route, Component }">
// 利用内置transition组件切换animate库类名来控制动画效果
<transition
:enter-active-class="`animate__animated ${route.meta.transition}`"
>
// 绑定相关路由组件
<component :is="Component"></component>
</transition>
</router-view>
</div>
</template>
<style scoped></style>
滚动行为
const router = createRouter({
// 路由模式
history: createWebHistory(),
routes,
// 滚动行为
scrollBehavior: (to, from, savePosition) => {
if (savePosition) {
return savePosition;
} else {
return {
top: 500,
};
}
},
});
动态路由
const initRouter = async () => {
const result = await axios.get('http://localhost:9999/login', { params: formInline });
result.data.route.forEach((v: any) => {
router.addRoute({
path: v.path,
name: v.name,
//这儿不能使用@
component: () => import(`../views/${v.component}`)
})
router.push('/index')
})
console.log(router.getRoutes());
}
更多推荐
已为社区贡献2条内容
所有评论(0)