安装

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());
 
}

Logo

前往低代码交流专区

更多推荐