七、Vue Router

文章目录

    • 一、对路由的理解
    • [二、基本切换效果与 `<RouterLink>` / `<RouterView>`](#二、基本切换效果与 <RouterLink> / <RouterView>)
      • [2.1 安装](#2.1 安装)
      • [2.2 核心组件](#2.2 核心组件)
      • [2.3 基础代码示例](#2.3 基础代码示例)
      • [2.4 两个注意点](#2.4 两个注意点)
    • [三、路由器工作模式(History 模式 vs Hash 模式)](#三、路由器工作模式(History 模式 vs Hash 模式))
      • [3.1 History 模式](#3.1 History 模式)
      • [3.2 Hash 模式](#3.2 Hash 模式)
    • [四、路由 `to` 的两种写法](#四、路由 to 的两种写法)
      • [4.1 字符串路径](#4.1 字符串路径)
      • [4.2 对象配置](#4.2 对象配置)
    • 五、命名路由(`name`)
    • 六、嵌套路由(`children`)
      • [6.1 嵌套路由的激活状态](#6.1 嵌套路由的激活状态)
    • [七、路由传参:Query 参数](#七、路由传参:Query 参数)
      • [7.1 传参方式](#7.1 传参方式)
      • [7.2 接收参数](#7.2 接收参数)
    • [八、路由传参:Params 参数(动态路由匹配)](#八、路由传参:Params 参数(动态路由匹配))
      • [8.1 配置路由(占位)](#8.1 配置路由(占位))
      • [8.2 传参方式](#8.2 传参方式)
      • [8.3 接收参数](#8.3 接收参数)
    • [九、路由的 Props 配置(解耦组件与路由)](#九、路由的 Props 配置(解耦组件与路由))
      • [9.1 写法一:布尔值(只映射 params)](#9.1 写法一:布尔值(只映射 params))
      • [9.2 写法二:函数写法(最灵活)](#9.2 写法二:函数写法(最灵活))
      • [9.3 写法三:对象写法(静态 props)](#9.3 写法三:对象写法(静态 props))
    • [十、路由的 Replace 属性(替换历史记录)](#十、路由的 Replace 属性(替换历史记录))
    • [十一、编程式路由导航(`router.push` / `router.replace`)](#十一、编程式路由导航(router.push / router.replace))
      • [11.1 获取路由器实例](#11.1 获取路由器实例)
      • [11.2 自动跳转示例](#11.2 自动跳转示例)
      • [11.3 按钮点击跳转示例](#11.3 按钮点击跳转示例)
      • [11.4 常见使用场景](#11.4 常见使用场景)
    • [十二、路由重定向与 404 兜底](#十二、路由重定向与 404 兜底)
      • [12.1 重定向(Redirect)](#12.1 重定向(Redirect))
      • [12.2 404 兜底页面](#12.2 404 兜底页面)

一、对路由的理解

  1. 路由就是一组 key-value 的对应关系------路径(key)对应着组件(value)。
  2. 多个路由需要经过路由器(router)的管理
  3. SPA(单页面应用) :页面通常有两个区域------导航区展示区。在导航区切换时,页面不会抖动(刷新)。
  4. 核心原理 :点击导航项 → 路径发生变化 → 路由器(router)监测到路径变化 → 根据规则匹配组件 → 展示区卸载旧组件、挂载新组件。核心变化的是路径

二、基本切换效果与 <RouterLink> / <RouterView>

2.1 安装

bash 复制代码
npm install vue-router

2.2 核心组件

  • <RouterLink> :声明式导航,最终渲染为 <a> 标签,点击时拦截默认行为,通过 JS 切换路由。
  • <RouterView>:路由出口(展示区),充当占位符,根据当前 URL 动态渲染匹配到的组件。

2.3 基础代码示例

src/router/index.ts(创建路由器并暴露):

ts 复制代码
import { createRouter, createWebHistory } from "vue-router";
import Home from "@/views/Home.vue";
import News from "@/views/News.vue";
import About from "@/views/About.vue";
// 创建路由器
const router = createRouter({
    history: createWebHistory(), // 路由器的工作模式
    // 配置路由
    routes: [
        { path: '/home', component: Home },
        { path: '/news', component: News },
        { path: '/about', component: About }
    ]
});

export default router;

main.ts(引入并使用路由器):

ts 复制代码
// 引入createApp函数用于创建应用
import { createApp } from 'vue'
// 引入App根组件
import App from './App.vue'
// 引入路由器,index.ts可以不写
import router from './router'
// 创建一个应用
const app = createApp(App)
// 使用路由器
app.use(router) 
// 挂载整个应用到app容器中
app.mount('#app')

App.vue(导航区 + 展示区):

html 复制代码
<script setup lang="ts">
import Header from "@/components/Header.vue";
</script>

<template>
  <div>
    <Header/>
    <h2>Vue路由测试</h2>
    <!-- 导航区 -->
    <div class="navigate">
      <RouterLink to="/home">首页</RouterLink>
      <RouterLink to="/news">新闻</RouterLink>
      <RouterLink to="/about">关于</RouterLink>
    </div>
    <!-- 展示区:此处展示哪个组件,由路由决定 -->
    <div class="main-content">
      <RouterView></RouterView>
    </div>
  </div>
</template>

<style scoped>
.navigate {
  margin: 20px 0;
  padding: 10px 20px;
  background: #f5f5f5;
  border-radius: 6px;
}
.navigate a {
  margin-right: 20px;
  text-decoration: none;
  color: #333;
  cursor: pointer;
}
.navigate a:hover {
  color: #409eff;
}
.main-content {
  margin-top: 20px;
  padding: 20px;
  border: 1px solid #eee;
  border-radius: 6px;
  min-height: 200px;
}
/* 激活状态样式 */
.navigate a.router-link-exact-active {
  color: #409eff;
  font-weight: bold;
  border-bottom: 2px solid #409eff;
}
</style>

子组件示例src/views/Home.vue):

html 复制代码
<script setup lang="ts">
</script>
<template>
  <div><h1>Home</h1></div>
</template>
<style scoped></style>

2.4 两个注意点

  1. 路由组件 通常存放在 pagesviews 文件夹,靠路由规则渲染出来;一般组件 通常存放在 components 文件夹,需要亲手写标签(如 <Header/>)使用。
  2. 通过点击导航"消失"的路由组件,默认是被卸载的,需要时再去挂载。可以借助生命周期钩子证明:
html 复制代码
<script setup lang="ts">
import { onMounted, onUnmounted } from 'vue'

onMounted(() => {
  console.log('组件挂载成功')
})
onUnmounted(() => {
  console.log('组件卸载成功')
})
</script>

三、路由器工作模式(History 模式 vs Hash 模式)

3.1 History 模式

ts 复制代码
const router = createRouter({
    history: createWebHistory(), // history模式
    routes: [...]
})
  • 优点 :URL 更加美观,不带有 #,更接近传统网站 URL。
  • 缺点 :项目上线后,需要服务端配合处理路径问题,否则刷新会有 404 错误。

部署配置示例

Nginx

nginx 复制代码
location / {
  try_files $uri $uri/ /index.html;
}

Apache.htaccess):

apache 复制代码
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.html [L]
</IfModule>

Node.js / Express

js 复制代码
app.use(express.static('dist'))
app.get('*', (req, res) => {
  res.sendFile(__dirname + '/dist/index.html')
})

3.2 Hash 模式

ts 复制代码
const router = createRouter({
    history: createWebHashHistory(), // hash模式
    routes: [...]
})
  • 优点:兼容性更好,不需要服务端处理路径。
  • 缺点 :URL 带有 # 不太美观,SEO 优化方面相对较差。

四、路由 to 的两种写法

4.1 字符串路径

html 复制代码
<RouterLink to="/user/123">用户详情</RouterLink>

4.2 对象配置

html 复制代码
<!-- 等价于 to="/user/123" -->
<RouterLink :to="{ path: '/user/123' }">用户详情</RouterLink>

<!-- 使用命名路由(推荐) -->
<RouterLink :to="{ name: 'UserDetail', params: { id: 123 } }">用户详情</RouterLink>

<!-- 带查询参数 -->
<RouterLink :to="{ path: '/search', query: { keyword: 'vue' } }">搜索</RouterLink>

注意 :使用对象写法时,必须绑定 :tov-bind:to),否则大括号会被当作普通字符串处理。

五、命名路由(name

通过名称标识路由,实现路径与代码的解耦。修改 path 时,只要 name 不变,导航代码无需改动。

src/router/index.ts

ts 复制代码
const router = createRouter({
    history: createWebHistory(),
    routes: [
        { name: 'home',  path: '/home',  component: Home },
        { name: 'news',  path: '/news',  component: News },
        { name: 'about', path: '/about', component: About }
    ]
})

App.vue 中使用

html 复制代码
<RouterLink to="/home">首页</RouterLink>                    <!-- 字符串写法 -->
<RouterLink :to="{ name: 'news' }">新闻</RouterLink>      <!-- 命名路由 -->
<RouterLink :to="{ path: '/about' }">关于</RouterLink>    <!-- 路径对象 -->

六、嵌套路由(children

当页面有布局框架,且内容区需要根据子路径切换时使用。展示区里面还有一个展示区。

src/router/index.ts

ts 复制代码
import Detail from "@/views/Detail.vue";

const router = createRouter({
    history: createWebHistory(),
    routes: [
        { name: 'home', path: '/home', component: Home },
        {
            name: 'news',
            path: '/news',
            component: News,
            children: [
                {
                    name: 'detail',
                    // 配置子路由,子级路由开头不用写 /
                    path: 'detail',
                    component: Detail
                }
            ]
        },
        { name: 'about', path: '/about', component: About }
    ]
})

News.vue(左侧列表 + 右侧详情展示区):

html 复制代码
<script setup lang="ts">
import { ref } from "vue";

const newsList = ref([
  { id: '1', title: '含糖量最高的水果', content: '水蜜桃、香蕉、苹果、橘子、提子、橙子、芒果、荔枝、龙眼、榴莲、甘蔗、红枣、山楂、石榴、葡萄,这些水果的含糖量普遍较高,减肥或控糖人群建议适量食用。' },
  { id: '2', title: '如何一夜暴富', content: '一夜暴富的方法大多写在刑法里,合法途径包括投资理财、创业成功、中彩票、继承遗产等,但都需要长期积累或极强运气,脚踏实地最靠谱。' },
  { id: '3', title: '健康饮食小常识', content: '每天保证足量饮水,多吃蔬菜和优质蛋白,减少高油高盐高糖食物,三餐规律,不暴饮暴食,是保持身体健康的基础。' },
  { id: '4', title: 'Vue3 快速入门', content: 'Vue3 采用组合式API,使用 setup 语法糖,响应式用 ref 和 reactive,组件通信更简洁,搭配 Vue Router 和 Pinia 可快速开发项目。' },
  { id: '5', title: '前端学习路线', content: '先学 HTML + CSS + JavaScript,再学框架 Vue React,然后学工程化、网络请求、状态管理、打包构建,最后做项目实战。' },
  { id: '6', title: '夏季解暑小妙招', content: '多喝温水、避免正午外出、穿透气衣物、常备绿豆汤、使用遮阳伞帽子,保持室内通风,可有效预防中暑。' },
  { id: '7', title: '电脑保养技巧', content: '定期清理垃圾文件、更新系统、查杀病毒、保持散热、不频繁强制关机,能延长电脑使用寿命。' }
])
</script>

<template>
  <div class="news-page">
    <h1>新闻</h1>
    <div class="layout">
      <!-- 左侧导航 -->
      <ul class="news-list">
        <li v-for="news in newsList" :key="news.id">
          <!-- path路径要写完整 -->
          <RouterLink :to="{ path: '/news/detail' }">{{ news.title }}</RouterLink>
        </li>
      </ul>
      <!-- 右侧内容展示区 -->
      <div class="content-box">
        <RouterView />
      </div>
    </div>
  </div>
</template>

<style scoped>
.news-page { padding: 20px; max-width: 1100px; margin: 0 auto; }
.layout { display: flex; gap: 30px; }
.news-list { list-style: none; padding: 0; width: 200px; }
.news-list li { margin: 12px 0; }
.news-list a { text-decoration: none; color: #333; }
.news-list a:hover { color: #409eff; }
.content-box { flex: 1; border: 1px solid #eee; padding: 25px; border-radius: 8px; min-height: 350px; }
</style>

6.1 嵌套路由的激活状态

使用了子路由后,必须用 router-link-active(模糊匹配),不能用 router-link-exact-active(严格完全匹配):

css 复制代码
.navigate a.router-link-active {
  color: #409eff;
  font-weight: bold;
  border-bottom: 2px solid #409eff;
}
  • router-link-exact-active:严格完全匹配(/news 只匹配 /news)。
  • router-link-active:模糊匹配(/news 匹配 /news/news/detail/news/xxx)。

七、路由传参:Query 参数

Query 参数是 URL 中 ? 后面的键值对,用于筛选、搜索等非唯一标识场景。(不需要改路由配置)

7.1 传参方式

第一种:字符串模板写法

html 复制代码
<RouterLink :to="`/news/detail?id=${news.id}&title=${news.title}&content=${news.content}`">
  {{ news.title }}
</RouterLink>

第二种:对象写法(推荐)

html 复制代码
<RouterLink :to="{
  path: '/news/detail',
  query: {
    id: news.id,
    title: news.title,
    content: news.content
  }
}">
  {{ news.title }}
</RouterLink>

也可以用 name

html 复制代码
<RouterLink :to="{
  name: 'detail',
  query: {
    id: news.id,
    title: news.title,
    content: news.content
  }
}">
  {{ news.title }}
</RouterLink>

7.2 接收参数

Detail.vue

html 复制代码
<script setup lang="ts">
import { useRoute } from "vue-router";
const route = useRoute();
</script>

<template>
  <ul class="news-list">
    <li>编号:{{ route.query.id }}</li>
    <li>标题:{{ route.query.title }}</li>
    <li>内容:{{ route.query.content }}</li>
  </ul>
</template>

八、路由传参:Params 参数(动态路由匹配)

Params 参数是 URL 路径的一部分,用于标识唯一资源(如用户 ID、文章 ID)。

8.1 配置路由(占位)

ts 复制代码
const router = createRouter({
    history: createWebHistory(),
    routes: [
        {
            name: 'news',
            path: '/news',
            component: News,
            children: [
                {
                    name: 'detail',
                    // params参数要占位
                    // 后面加 ? 表示参数可传可不传
                    path: 'detail/:id/:title/:content?',
                    component: Detail
                }
            ]
        }
    ]
})

8.2 传参方式

字符串写法:

html 复制代码
<RouterLink :to="`/news/detail/${news.id}/${news.title}/${news.content}`">
  {{ news.title }}
</RouterLink>

对象写法:

html 复制代码
<RouterLink :to="{
  name: 'detail', // 只能写路由名称,不能写 path
  params: {
    id: news.id,
    title: news.title,
    content: news.content
  }
}">
  {{ news.title }}
</RouterLink>

8.3 接收参数

html 复制代码
<script setup lang="ts">
import { useRoute } from "vue-router";
const route = useRoute();
</script>

<template>
  <ul class="news-list">
    <li>编号:{{ route.params.id }}</li>
    <li>标题:{{ route.params.title }}</li>
    <li>内容:{{ route.params.content }}</li>
  </ul>
</template>

注意

  • 传递 params 参数时,若使用 to 的对象写法,必须使用 name 配置项,不能用 path
  • 传递 params 参数时,需要提前在规则中占位

九、路由的 Props 配置(解耦组件与路由)

默认组件通过 useRoute() 获取参数,导致组件与路由强耦合。使用 props 配置可以将参数以 props 形式传入组件。

9.1 写法一:布尔值(只映射 params)

ts 复制代码
{
    name: 'detail',
    path: 'detail/:id/:title/:content?',
    component: Detail,
    props: true // 将所有 params 参数以 props 形式传给 Detail
}

Detail.vue

html 复制代码
<script setup lang="ts">
defineProps({
  id: String,
  title: String,
  content: String
})
</script>

<template>
  <ul class="news-list">
    <li>编号:{{ id }}</li>
    <li>标题:{{ title }}</li>
    <li>内容:{{ content }}</li>
  </ul>
</template>

props: true 只能传递 params 参数,query 参数不行。

9.2 写法二:函数写法(最灵活)

可以自己决定将什么作为 props 传给路由组件:

ts 复制代码
{
    path: 'detail/:id/:title/:content?',
    component: Detail,
    props(route) {
        console.log(route);
        return route.params; // 也可以返回 route.query 或组合数据
    }
}

9.3 写法三:对象写法(静态 props)

ts 复制代码
{
    path: 'detail/:id/:title/:content?',
    component: Detail,
    props: {
        a: 100,
        b: 200,
        c: 300
    }
}

对象写法使用较少,适用于需要传递静态数据的场景。

十、路由的 Replace 属性(替换历史记录)

默认情况下,路由每次跳转都会向浏览器历史栈 push 一条新记录。可以改为 replace 模式,替换当前历史记录(浏览器后退/前进按钮无法回到被替换的页面)。

App.vue

html 复制代码
<div class="navigate">
  <RouterLink replace to="/home">首页</RouterLink>
  <RouterLink replace :to="{ name: 'news' }">新闻</RouterLink>
  <RouterLink replace :to="{ path: '/about' }">关于</RouterLink>
</div>

replace 属性看具体需求使用。

十一、编程式路由导航(router.push / router.replace

脱离 <RouterLink> 标签,通过 JavaScript 代码实现跳转。

11.1 获取路由器实例

html 复制代码
<script setup lang="ts">
import { useRouter } from "vue-router";
const router = useRouter(); // 拿到了路由器
</script>

11.2 自动跳转示例

Home.vue(3 秒后自动跳转到新闻页):

html 复制代码
<script setup lang="ts">
import { onMounted } from "vue";
import { useRouter } from "vue-router";

const router = useRouter();

onMounted(() => {
  setTimeout(() => {
    // push 方法:添加历史记录
    router.push('/news');
    // replace 方法:替换历史记录
    // router.replace('/news');
  }, 3000);
});
</script>

11.3 按钮点击跳转示例

News.vue(点击按钮查看新闻详情):

html 复制代码
<script setup lang="ts">
import { ref } from "vue";
import { useRouter } from "vue-router";

const newsList = ref([...]); // 同上
const router = useRouter();

interface NewsInter {
  id: string;
  title: string;
  content: string;
}

function showNewsDetail(news: NewsInter) {
  // to 怎么写,push 就这么写
  router.push({
    name: 'detail',
    params: {
      id: news.id,
      title: news.title,
      content: news.content
    }
  });
}
</script>

<template>
  <div class="news-page">
    <ul class="news-list">
      <li v-for="news in newsList" :key="news.id">
        <button @click="showNewsDetail(news)">查看新闻</button>
        <RouterLink :to="{
          name: 'detail',
          params: { id: news.id, title: news.title, content: news.content }
        }">
          {{ news.title }}
        </RouterLink>
      </li>
    </ul>
    <div class="content-box">
      <RouterView />
    </div>
  </div>
</template>

11.4 常见使用场景

  • 符合某种条件后跳转(如登录成功)。
  • 鼠标滑过某个元素后延迟跳转。
  • 表单提交后的页面跳转。

十二、路由重定向与 404 兜底

12.1 重定向(Redirect)

解决访问根路径 / 时的警告:

ts 复制代码
const router = createRouter({
    history: createWebHistory(),
    routes: [
        { name: 'home', path: '/home', component: Home },
        { name: 'news', path: '/news', component: News },
        { name: 'about', path: '/about', component: About },
        // 重定向
        { path: '/', redirect: '/home' }
    ]
})

12.2 404 兜底页面

捕获所有未匹配的路径,必须放在路由表最后

ts 复制代码
const routes = [
  // ... 其他路由
  {
    path: '/:pathMatch(.*)*',
    name: 'NotFound',
    component: () => import('@/views/404.vue')
  }
]
相关推荐
羊羊小栈1 小时前
停车场管理系统(基于前后端Web开发)
前端·人工智能·毕业设计·大作业
用户938515635071 小时前
从JS的“坑”到TS的“墙”,再到Bun与AI:打造健壮的全栈应用
前端·javascript
jserTang1 小时前
手撕 Claude Code-7:自动压缩与记忆恢复
前端·后端
橘子星1 小时前
浅谈 TypeScript 与 Bun:现代 JavaScript 开发的利器
前端·javascript
铁皮饭盒1 小时前
Bun 的三种并发"暗器":reusePort、Worker、spawn,能硬刚 Java 吗?
前端·javascript·后端
CodeSheep1 小时前
宇树科技,即将上市!
前端·后端·程序员
yaoxin5211232 小时前
430. Java 日期时间 API - 时间计算 Temporal 包
java·前端·python
Cobyte2 小时前
18.【SolidJS】 采用 template 内容模板元素创建 DOM 元素
前端·javascript·vue.js
山峰哥2 小时前
VB事件驱动编程实战:从零到一搭建完整管理系统
前端·数据库·性能优化·深度优先·vb