✨Vue 静态路由详解:构建应用的导航骨架(4)

目录

[1. 引言](#1. 引言)

[2. 核心概念:什么是静态路由?](#2. 核心概念:什么是静态路由?)

[3. 如何配置静态路由:一步一步来⭐⭐](#3. 如何配置静态路由:一步一步来⭐⭐)

[3.1 安装 Vue Router](#3.1 安装 Vue Router)

[3.2 创建路由实例并定义静态路由表](#3.2 创建路由实例并定义静态路由表)

[3.3 在 main.js 中挂载路由](#3.3 在 main.js 中挂载路由)

[3.4 在组件中使用路由:router-view 和 router-link](#3.4 在组件中使用路由:router-view 和 router-link)

[4. 静态路由的常见配置项](#4. 静态路由的常见配置项)

[5. 静态路由 vs. 动态路由](#5. 静态路由 vs. 动态路由)

[6. 实例与演示⭐⭐⭐](#6. 实例与演示⭐⭐⭐)

[6.1 ClassInfo.vue](#6.1 ClassInfo.vue)

[6.1.1 功能概述](#6.1.1 功能概述)

[6.1.2 代码结构分析](#6.1.2 代码结构分析)

[1. 模板部分 (Template)](#1. 模板部分 (Template))

[2. 逻辑部分 (Script)](#2. 逻辑部分 (Script))

[3. 样式部分 (Style)](#3. 样式部分 (Style))

[6.1.3 小结](#6.1.3 小结)

[6.2 Home.vue](#6.2 Home.vue)

[6.2.1 代码解析](#6.2.1 代码解析)

[1. 模板结构分析](#1. 模板结构分析)

[6.2.2 样式设计特点](#6.2.2 样式设计特点)

[6.3 StudentList.vue](#6.3 StudentList.vue)

[6.3.1 代码功能分析](#6.3.1 代码功能分析)

[6.3.2 代码结构解析](#6.3.2 代码结构解析)

模板部分 (Template)

脚本部分 (Script)

样式部分 (Style)

[6.4 StudetScore.vue](#6.4 StudetScore.vue)

[6.4.1 功能分析](#6.4.1 功能分析)

[6.4.2 代码结构解析](#6.4.2 代码结构解析)

[1. 模板部分 (Template)](#1. 模板部分 (Template))

[2. 脚本部分 (Script)](#2. 脚本部分 (Script))

[3. 样式部分 (Style)](#3. 样式部分 (Style))

[6.4.3 核心功能实现⭐](#6.4.3 核心功能实现⭐)

[1. 行内编辑功能](#1. 行内编辑功能)

[2. 新增学生功能](#2. 新增学生功能)

[3. 数据验证](#3. 数据验证)

[4. 统计功能](#4. 统计功能)

[6.4.4 小结](#6.4.4 小结)

[7. 总结与展望](#7. 总结与展望)


1. 引言

在单页应用(SPA)的开发浪潮中,如何在不刷新页面的情况下优雅地管理视图切换和URL同步,成为前端开发的核心挑战。Vue Router作为Vue.js官方路由管理器,正是解决这一问题的关键利器。

它如同应用的导航大脑,精准映射URL路径与组件视图,让复杂应用保持清晰结构。而静态路由作为Vue Router的基石,通过预先定义所有路由配置,为应用搭建起稳定可靠的导航骨架。无论是企业官网还是后台管理系统,静态路由都能提供直观易懂的路径管理方案。

本文将带您深入掌握Vue静态路由的核心概念与实战技巧,从基础配置到最佳实践,助您构建出导航流畅、结构严谨的现代化Vue应用。让我们一同探索如何用静态路由为您的SPA应用打造坚实的导航基础!

2. 核心概念:什么是静态路由?

静态路由 指的是在项目的路由配置文件(通常是 router/index.js)中,通过一个固定的数组(routes)预先声明所有可能的路径(path)与组件(component)之间的映射关系。

特点:
预先定义
:在应用运行前,所有路由规则都已确定。
配置简单 :像一个清单一样,逐条列出路径和对应的组件。
易于管理:对于中等复杂度的应用,结构清晰,一目了然。

3. 如何配置静态路由:一步一步来⭐⭐

3.1 安装 Vue Router

如果你的项目还没有安装 Vue Router,可以通过以下命令安装:

npm install vue-router 或 yarn add vue-router

3.2 创建路由实例并定义静态路由表

src/router/index.js 文件中,进行配置:

javascript 复制代码
// 1. 引入所需功能和组件
import { createRouter, createWebHistory } from 'vue-router'
// 静态引入组件(打包时会生成单独的chunk)
import HomeView from '../views/HomeView.vue'
import AboutView from '../views/AboutView.vue'
import ContactView from '../views/ContactView.vue'

// 2. 定义静态路由表 - 这是一个数组
const routes = [
  {
    path: '/', // 访问的路径
    name: 'home', // 路由的唯一名称,可用于跳转
    component: HomeView // 对应的组件
  },
  {
    path: '/about',
    name: 'about',
    component: AboutView
  },
  {
    path: '/contact',
    name: 'contact',
    component: ContactView
  },
  // 经典场景:404页面匹配
  {
    path: '/:pathMatch(.*)*', // 匹配任何未定义的路由
    name: 'not-found',
    component: () => import('../views/NotFound.vue') // 动态引入(懒加载),即使是静态路由也可以懒加载
  }
]

// 3. 创建路由实例
const router = createRouter({
  history: createWebHistory(process.env.BASE_URL), // 使用HTML5 History模式
  routes // 缩写,相当于 `routes: routes`
})

// 4. 导出路由实例,以便在main.js中使用
export default router

3.3 在 main.js 中挂载路由

javascript 复制代码
import { createApp } from 'vue'
import App from './App.vue'
import router from './router' // 自动导入router目录下的index.js

const app = createApp(App)
app.use(router) // 使用路由插件
app.mount('#app')

在根组件 App.vue 中,你需要一个地方来放置匹配到的组件(router-view),并通常需要一些导航链接(router-link)。

html 复制代码
<!-- App.vue -->
<template>
  <div id="app">
    <nav>
      <! -- 使用 router-link 组件进行导航 -->
      <! -- to 属性指定目标路由 -->
      <router-link to="/">首页</router-link> |
      <router-link to="/about">关于</router-link> |
      <router-link :to="{ name: 'contact' }">联系我们</router-link> 
      <!-- 使用路由名称(name)进行跳转是一种更好的实践 -->
    </nav>
    <! -- 路由出口 -->
    <! -- 路由匹配到的组件将渲染在这里 -->
    <router-view />
  </div>
</template>

4. 静态路由的常见配置项

除了基本的 path, name, component,静态路由还可以配置更多信息:

javascript 复制代码
const routes = [
  {
    path: '/user/:id',
    name: 'user',
    component: UserProfile,
    props: true, // 将路由参数 `params` 作为 props 传递给组件
    meta: {
      requiresAuth: true, // 自定义元信息,用于路由守卫权限判断
      title: '用户主页'
    },
    // 嵌套路由(子路由)
    children: [
      {
        path: 'posts', // 注意:不要以 `/` 开头
        component: UserPosts
      }
    ]
  }
]

5. 静态路由 vs. 动态路由

特性 静态路由 动态路由
定义时机 项目构建时 运行时(通常是用户登录后)
配置方式 固定的 routes 数组 通过 router.addRoute() API 动态添加
适用场景 页面结构固定(如关于页、帮助页) 权限菜单、根据用户角色生成不同导航
复杂度 简单直观 相对复杂,需要程序逻辑处理

6. 实例与演示⭐⭐⭐

6.1 ClassInfo.vue

这是一个基于Vue 3和TypeScript的班级信息管理系统,具有简洁美观的界面和完整的功能。

6.1.1 功能概述

实现了以下核心功能:

  1. 班级信息展示(名称、人数、班主任)

  2. 新增班级信息

  3. 修改现有班级信息

  4. 删除班级信息

  5. 模态框形式的表单交互

6.1.2 代码结构分析

1. 模板部分 (Template)
html 复制代码
<template>
  <div>
    <h2>班级信息管理</h2>
    <button class="add-button" @click="showAddModal">新增班级</button>

    <div class="class-card" v-for="(classItem, index) in classes" :key="classItem.id">
      <h3>班级名称:{{ classItem.name }}</h3>
      <p>班级人数:{{ classItem.size }}</p>
      <p>班主任:{{ classItem.teacher }}</p>
      <div class="button-group">
        <button class="edit-button" @click="editClass(index)">修改</button>
        <button class="delete-button" @click="deleteClass(index)">删除</button>
      </div>
    </div>

    <div v-if="showModal" class="modal">
      <div class="modal-content">
        <h2>{{ editIndex === null ? '信息' : '信息' }}</h2>
        <form @submit.prevent="saveClass">
          <label>
            班级名称:
            <input v-model="form.name" required />
          </label>
          <label>
            班级人数:
            <input v-model="form.size" type="number" required />
          </label>
          <label>
            班主任:
            <input v-model="form.teacher" required />
          </label>
          <button class="save-button" type="submit">保存</button>
          <button class="cancel-button" type="button" @click="closeModal">取消</button>
        </form>
      </div>
    </div>
  </div>
</template>
  • 使用了清晰的标题和卡片式布局展示班级信息

  • 每个班级卡片包含基本信息和管理按钮

  • 模态框用于新增和编辑操作,提高了用户体验

2. 逻辑部分 (Script)
html 复制代码
<script lang="ts" setup>
import { ref } from 'vue';

// 接口定义
interface ClassItem {
  id: number;
  name: string;
  size: number;
  teacher: string;
}

// 响应式数据
const classes = ref<ClassItem[]>([ id: , name: '', size:  teacher: '']);
const showModal = ref(false);
const editIndex = ref<number | null>(null);
const form = ref<ClassItem>({id: 0,
  name: ''
  size: 0
  teacher: ''});

// 方法定义
const showAddModal = () => {showModal.value = true;
  editIndex.value = null;};
const editClass = (index: number) => {showModal.value = true;
  editIndex.value = index;};
const deleteClass = (index: number) => {if (confirm('确认删除该班级信息吗?')) {
    classes.value.splice(index, 1);
  }};
const saveClass = () => {if (editIndex.value === null) {
    form.value.id = classes.value.length + 1;
    classes.value.push({ ...form.value });
  }};
const closeModal = () => {showModal.value = false;};
const resetForm = () => {id: 0,
    name: ''
    size: 0
    teacher: ''};
</script>
  • 使用Vue 3的Composition API和 script setup 语法糖

  • 使用TypeScript接口明确定义数据类型

  • 合理使用ref创建响应式数据

3. 样式部分 (Style)
html 复制代码
<style>
.class-card {
  background-color: white;
  border: 1px solid #ccc;
  border-radius: 5px;
  padding: 20px;
  margin: 10px;
  width: 280px;
  display: inline-block;
  vertical-align: top;
  text-align: center;
}

.add-button {
  display: block;
  margin: 20px auto;
  padding: 10px 20px;
  background-color: #4caf50;
  color: white;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}
.modal {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
}
</style>

6.1.3 小结

  1. TypeScript集成:使用接口明确数据类型,提高代码可靠性

  2. 响应式设计:合理使用ref管理状态,确保UI与数据同步

  3. 组件化思维:将功能拆分为独立的方法,提高代码可维护性

  4. 用户体验优化:使用模态框进行表单操作,避免页面跳转

  5. 数据验证:表单字段使用required属性进行基本验证

6.2 Home.vue

这是一个基于Vue 3的后台管理系统布局组件,提供了清晰的侧边栏导航和主内容区域。

6.2.1 代码解析

1. 模板结构分析
html 复制代码
<template>
  <div class="app-container">
    <!-- 侧边栏导航 -->
    <aside class="sidebar">
      <ul>
        <li><router-link to="/students">学生信息管理</router-link></li>
        <li><router-link to="/ClassInfo">班级信息管理</router-link></li>
        <li><router-link to="/StudetScore">学生绩点管理</router-link></li>
      </ul>
    </aside>
    
    <!-- 主内容区域 -->
    <div class="main-content">
      <main class="workspace">
        <router-view></router-view>
      </main>
    </div>
  </div>
</template>
  • 使用语义化标签: aside 表示侧边栏, main 表示主内容区域

  • 使用Vue Router的 router-link 实现导航

  • 使用 router-view 作为路由组件的渲染出口

6.2.2 样式设计特点

  • 采用Flex布局实现整体结构

  • 侧边栏固定宽度,主内容区域自适应

  • 活动路由链接有高亮效果

6.3 StudentList.vue

6.3.1 代码功能分析

这是一个基于Vue 3和TypeScript的学生信息管理系统,具有以下核心功能:
1. 学生信息展示 :以卡片形式展示学生信息
2. 新增学生 :通过模态框表单添加新学生
3. 编辑学生 :修改现有学生信息
4. 删除学生 :移除学生记录
5. 性别区分:根据性别显示不同的卡片背景色

6.3.2 代码结构解析

模板部分 (Template)
html 复制代码
<template>
  <div class="app">
    <h2>学生信息图表</h2>
    <button class="add-button" @click="showAddModal">新增</button>
    <div class="student-card" v-for="(item, index) in students" :key="item.id"
      :class="{ 'male': item.gender === '男', 'female': item.gender === '女' }">
      <div class="pic">
        <img src=""
          alt="student-photo">
      </div>
      <p>学号:{{ item.id }}</p>
      <p>姓名: {{ item.name }}</p>

      <div class="button-group">
        <button class="edit-button" @click="editStudent(index)">修改</button>
        <button class="delete-button" @click="deleteStudent(index)">删除</button>
      </div>
    </div>

    <div v-if="showModal" class="modal">
      <div class="modal-content"
        <h2>{{ editIndex === null ? 'xxxx' : 'xxxx' }}</h2>
        <form @submit.prevent="saveStudent">
          <label>
            姓名:
            <input v-model="form.name" required />
          </label>
          <label>
            学号:
            <input v-model="form.id" required />
          </label>
          <button class="save-button" type="submit">保存</button>
          <button class="cancel-button" type="button" @click="closeModal">取消</button>
        </form>
      </div>
    </div>
  </div>
</template>
  • 使用卡片式布局展示学生信息

  • 通过 v-for 指令循环渲染学生卡片

  • 使用条件类绑定(:class)根据性别显示不同背景色

  • 模态框用于新增/编辑操作

脚本部分 (Script)

html 复制代码
interface Student {
  name: string;
  id: string;
  gender: '男' | '女';
  hobbies?: string;
  department?: string;
  birthDate: string;
  hometown?: string;
  age: string;
}
const showModal = ref(false);
const editIndex = ref<number | null>(null);
const form = ref<Student>({
  name: '',
  id: '',
  gender: '男',
  hobbies: '',
  department: '',
  birthDate: '',
  hometown: '',
  age: ''
});
const showAddModal = () => {
  resetForm();
  showModal.value = true;
  editIndex.value = null;
};

const editStudent = (index: number) => {
  form.value = { ...students.value[index] };
  showModal.value = true;
  editIndex.value = index;
};
const saveStudent = () => {
  if (editIndex.value === null) {
    students.value.push({ ...form.value });
  } else {
    students.value[editIndex.value] = { ...form.value };
  }
  closeModal();
};

const closeModal = () => {
  resetForm();
  showModal.value = false;
};
  • 使用Vue 3的Composition API和<script setup>语法

  • 定义 Student 接口确保类型安全

  • 使用ref创建响应式数据

  • 实现了完整的CRUD操作功能

样式部分 (Style)

html 复制代码
<style>
.app {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
}
.add-button {
  display: block;
  margin: 20px auto;
  padding: 10px 20px;
  background-color: #4caf50;
  color: white;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}
.student-card {
  background-color: white;
  border: 1px solid #ccc;
  border-radius: 5px;
  padding: 20px;
  margin: 10px;
  width: 280px;
  display: inline-block;
  vertical-align: top;
  text-align: center;
}
.modal {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
}
.modal-content {
  background-color: #fff;
  padding: 20px;
  border-radius: 5px;
  width: 400px;
  max-width: 100%;
}
.cancel-button {
  background-color: #f44336;
  color: white;
  border: none;
  padding: 10px;
  border-radius: 5px;
  cursor: pointer;
  margin-left: 10px;
}
</style>
  • 简洁现代的UI设计

  • 响应式布局适应不同屏幕

  • 使用柔和的颜色区分男女学生

  • 模态框使用半透明遮罩提升用户体验

6.4 StudetScore.vue

6.4.1 功能分析

实现了核心功能:

  1. 学生信息的表格展示

  2. 新增学生功能

  3. 编辑学生信息(行内编辑)

  4. 删除学生记录

  5. 按性别统计学生人数

  6. 根据性别显示不同的行背景色

6.4.2 代码结构解析

1. 模板部分 (Template)
html 复制代码
<template>
  <div id="app">
    <h1>学生信息表</h1>
    <button @click="startAddStudent" class="addStudent">新增</button>
    <p>共有学生:{{ students.length }}人,其中男生:{{ countGender('男') }}人,女生:{{ countGender('女') }}人</p>
    <table>
      <thead>
        <tr>
          <th>姓名</th>
          <th>学号</th>
          <th>性别</th>
          <th>出生日期</th>
          <th>籍贯</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="(student, index) in students" :key="student.id"
          :class="{ 'male': student.gender === '男', 'female': student.gender === '女' }">
          <td>
            <span v-if="editingIndex !== index">{{ student.gender }}</span>
            <select v-else v-model="editingStudent.gender">
              <option value="男">男</option>
              <option value="女">女</option>
            </select>
          </td>
          <td>
            <button v-if="editingIndex !== index" @click="editStudent(index)">修改</button>
            <button v-else @click="saveStudent(index)">保存</button>
            <button v-else @click="cancelEdit">取消</button>
            <button @click="deleteStudent(index)">删除</button>
          </td>
        </tr>
        <tr v-if="isAdding">
          <td><input v-model="newStudent.name" placeholder="姓名" /></td>
          <td><input v-model="newStudent.id" placeholder="学号" /></td>
          <td>
            <select v-model="newStudent.gender">
              <option value="男">男</option>
              <option value="女">女</option>
            </select>
          </td>
          <td><input v-model="newStudent.birthDate" type="date" placeholder="出生日期" /></td>
          <td><input v-model="newStudent.origin" placeholder="籍贯" /></td>
          <td>
            <button @click="saveNewStudent">保存</button>
            <button @click="cancelAdd">取消</button>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>
  • 使用表格布局展示学生信息

  • 通过 v-ifv-else实现行内编辑与查看模式的切换

  • 新增学生表单集成在表格最后一行

  • 使用动态类绑定根据性别显示不同背景色

2. 脚本部分 (Script)
javascript 复制代码
<script lang="ts" setup>
import { ref } from 'vue';

// 定义学生接口
interface Student {
  name: string;
  id: string;
  gender: string;
  birthDate: string;
  origin: string;
}

// 响应式数据
const students = ref<Student[]>([...]);
const newStudent = ref<Student>({...});
const editingIndex = ref<number | null>(null);
const editingStudent = ref<Student>({...});
const isAdding = ref(false);

// 方法定义
function startAddStudent() {...}
function saveNewStudent() {...}
// ...其他方法
</script>
  • 使用Vue 3的Composition API和 <script setup>语法

  • 使用TypeScript接口确保数据类型安全

  • 合理使用ref创建响应式数据

3. 样式部分 (Style)
javascript 复制代码
<style>
table {
  width: 100%;
  border-collapse: collapse;
}

th,
td {
  border: 1px solid black;
  padding: 8px;
  text-align: center;
}

th {
  background-color: #f2f2f2;
  text-align: center;
}

.male {
  background-color: rgba(179, 243, 207, 0.5);
}

.female {
  background-color: rgba(113, 143, 170, 0.5);
}

button {
  margin-right: 5px;
  background-color: rgb(211, 210, 207);
}
</style>

6.4.3 核心功能实现⭐

1. 行内编辑功能

通过editingIndex变量跟踪当前编辑的行索引,实现行内编辑与查看模式的切换:

html 复制代码
<td>
  <span v-if="editingIndex !== index">{{ student.name }}</span>
  <input v-else v-model="editingStudent.name" />
</td>
2. 新增学生功能

使用isAdding变量控制新增表单的显示与隐藏:

html 复制代码
<tr v-if="isAdding">
  <!-- 新增学生表单 -->
</tr>
3. 数据验证

在保存前进行基本的数据验证:

html 复制代码
if (newStudent.value.name && newStudent.value.id && ...) {
  // 保存数据
} else {
  alert('请填写完整的学生信息');
}
4. 统计功能

使用计算函数统计男女学生人数:

javascript 复制代码
function countGender(gender: string) {
  return students.value.filter(student => student.gender === gender).length;
}

6.4.4 小结

类型安全 :使用TypeScript接口明确定义数据结构
响应式设计 :合理使用ref管理组件状态
用户体验 :行内编辑设计避免页面跳转,操作流畅
代码结构清晰 :功能模块划分明确,易于维护

数据验证:基本的表单验证确保数据完整性

7. 总结与展望

静态路由的基石作用

在本节中,我们系统性地剖析了Vue静态路由如何成为应用导航的"骨架"。静态路由通过在编译时定义固定的路由配置(如routes数组),确保了应用的稳定性和高效性。核心优势包括:

性能优化 :路由在构建时已确定,避免了运行时开销,提升页面加载速度。
易于维护 :集中式配置(如router/index.js)让代码结构清晰,支持嵌套路由、路由参数等特性,便于团队协作。
适用场景广 :特别适合中小型应用或内容固定的项目,例如企业官网、博客系统等,通过路由守卫(如beforeEach)实现权限控制。

迈向动态与进阶之路

静态路由虽强大,但技术永不止步。未来,我们可以进一步探索以下方向:
动态路由的融合 :当应用需要基于用户数据(如权限或实时内容)动态生成路由时,可以结合Vue Router的动态路由API(如addRoute方法)。这在大型后台管理系统或个性化应用中至关重要。

Vue 3与组合式API :随着Vue 3普及,路由管理正拥抱setup语法和Composition API,例如使用useRouter钩子简化代码。推荐大家学习官方示例,提升开发效率。
生态整合 :将路由与状态管理(如Pinia)、服务端渲染(SSR)或微前端架构结合,能构建更复杂的应用。例如,通过静态路由预加载数据,优化SEO和用户体验。
社区趋势:关注Vue Router的更新(如最新版本对TypeScript的强化),并参与开源项目实践。CSDN将持续分享相关教程,助力大家从"骨架"扩展到"血肉丰满"的应用。

静态路由是Vue导航的起点,而非终点。鼓励大家动手实践:尝试在个人项目中实现一个带路由的SPA,并在评论区分享你的心得。

如果觉得本文对你有帮助:

👍 点赞 + ⭐ 收藏 + ➕ 关注!

你的支持是我持续创作技术干货的最大动力!

欢迎在评论区留言交流:

👉「代码已跑通!」-- 欢迎分享你的学习成果

👉「下一期想学什么?」-- 留言告诉我你的需求

👉「遇到了问题」-- 描述具体问题,一起讨论解决

💥💥💥💥💥💥💥💥💥💥💥💥💥💥💥💥💥💥💥💥💥💥💥💥💥💥💥💥💥💥

相关推荐
这是个栗子3 小时前
(二)Vue.js 指令、事件与计算属性
前端·javascript·vue
黑客飓风3 小时前
Chrome性能优化指南
前端·chrome·性能优化
pc大老3 小时前
如何修复 Google Chrome 上的白屏问题
前端·网络·chrome·浏览器·谷歌
xqlily3 小时前
Chrome性能优化指南大纲
前端·chrome·性能优化
FreeBuf_3 小时前
Chrome高危类型混淆0-Day漏洞(CVE-2025-10585)技术分析
前端·chrome
Code_流苏3 小时前
Gemini in Chrome深度解析:反垄断胜诉后,Chrome开启AI智能浏览时代!
前端·人工智能·chrome·gemini·智能时代·ai browser
冲!!3 小时前
项目中的图形验证码是前端还是后端实现?
前端·vue.js
xiyangxiaoguo3 小时前
Qt QEventLoop的使用的一个问题讨论
java·前端·算法
小墨宝4 小时前
umijs 4.0学习 - 路由
前端·javascript·学习