Vue3 --- 路由

1. 模块下载

npm i vue-router

2. 基本使用

1. 指定路由规则

src/router/index.ts

import { createRouter, createWebHashHistory } from "vue-router";
import Home from "@/components/Home.vue"
import News from "@/components/News.vue"
import About from "@/components/About.vue"

// 创建路由器并暴露
export default createRouter({
    // 路由器的工作模式: history 模式
    history: createWebHashHistory(),

    // 路由规则
    routes:[
        {
            path: "/home",
            component: Home
        },
        {
            path: "/news",
            component: News
        },
        {
            path: "/about",
            component: About
        }
    ]
})

2. 使用路由器

src/main.ts

import {createApp} from 'vue'
import App from './App.vue'
import router from './router'

// 创建 App 应用
const app = createApp(App)

// 使用 router 路由器
app.use(router)

// 股灾整个应用到 app 容器中
app.mount('#app')

3. 页面中指定路由

App.vue

<template>
  <div class="app">
    <!-- 标题 -->
    <h2>Vue 路由测试</h2>

    <!-- 导航区 -->
    <div class="nav">
        <!-- 3. 使用 RouterLink 标签 包裹需要点击跳转的路由 -->
        <!-- active-class="active" 表示当前路由被激活时候的 css 样式 -->
        <RouterLink to="/home" active-class="active">首页</RouterLink>
        
        <!-- to 的 字符串 写法 -->
        <RouterLink to="/news" active-class="active">新闻</RouterLink>
        
        <!-- to 的 对象 写法, path 是固定 key -->
        <RouterLink :to="{path: '/about'}" active-class="active">关于</RouterLink>
    </div>

    <!-- 内容展示区 -->
    <div class="content">
        <!-- 2. 使用 RouterView 标签来表示组件内容展示在这里 -->
         <RouterView></RouterView>
    </div>
  </div>
</template>


<script lang="ts" setup name="App">
// 1. 引入 RouterView
import {RouterView,RouterLink} from 'vue-router'

</script>

<style scoped>
    h2{
        width: 100%;
        height: 100px;
        background-color: aliceblue;
        text-align: center;
        line-height: 100px;
    }
    .nav{
        display: flex;
        justify-content: space-around;
    }
    .nav a{
        width: 80px;
        height: 38px;
        border-radius: 15px;
        align-content: center;
        text-align: center
    }

    .nav a.active{
        background-color: rgb(44, 223, 139);
    }

    .content{
        width: 1200px;
        height: 500px;
        border: 1px solid black;
        border-radius: 20px;
        margin-top: 50px;
    }
</style>

src/views/Home.vue

<template>
<h2>Home</h2>
</template>

<script lang="ts" setup name="Home">
</script>

src/views/News.vue

<template>
<h2>News</h2>
</template>

<script lang="ts" setup name="News">
</script>

src/views/About.vue

<template>
<h2>About</h2>
</template>

<script lang="ts" setup name="About">
</script>

3. 注意

  1. 路由组件通常放在 pagesviews 文件夹中, 一般组件通常放在 components 文件夹
  2. 通过点击导航, 视觉效果上 消失 了的路由组件, 默认是被 销毁 掉的, 需要的时候再去 挂载

4. 三种跳转方式

1. 字符串

<RouterLink to="/home" active-class="active">首页</RouterLink>

2. 对象

<RouterLink :to="{path: '/about'}" active-class="active">关于</RouterLink>

3. 命名空间

router/index.ts

import { createRouter, createWebHistory } from "vue-router";
import Home from "@/components/Home.vue"
import News from "@/components/News.vue"
import About from "@/components/About.vue"

export default createRouter({
    history: createWebHistory(),

    routes:[
        {
            name: "home",    // 添加名字
            path: "/home",
            component: Home
        },
        {
            name: "news",
            path: "/news",
            component: News
        },
        {
            name: "about",
            path: "/about",
            component: About
        }
    ]
})

页面中跳转

<RouterLink :to="{name: 'about'}" active-class="active">关于</RouterLink>

5. 两种工作模式

1. history 模式

优点: URL 更美观, 不带有 #, 更接近于传统网站的 URL

缺点: 后期项目上线, 需要服务端配置处理路径问题, 否则刷新就会有 404 错误

应用场景: TOC 的网站一般使用 history 模式, 如 B站

import { createWebHistory } from "vue-router";

export default createRouter({
    history: createWebHistory(),
    
    // ......
}

后端处理路径问题: Vue3 ---- 部署

2. hash 模式

优点: 兼容性更好, 因为不需要服务器端处理路径

缺点: URL 带有 # 不太美观, 且在 SEO 优化方面相对较差

应用场景: 后台管理系统等, 一般使用 hash 模式

import { createWebHashHistory } from "vue-router";

export default createRouter({
    history: createWebHashHistory(),
    
    // ......
}

5. 嵌套路由

src/router/index.ts

import { createRouter, createWebHistory } from "vue-router";
import Home from "@/components/Home.vue"
import News from "@/components/News.vue"
import About from "@/components/About.vue"
import Detail from "@/components/Detail.vue"

export default createRouter({
    history: createWebHistory(),

    routes:[
        {
            name: "home",
            path: "/home",
            component: Home
        },
        {
            name: "news",
            path: "/news",
            component: News,
            // 配置子路由
            children:[
                {
                    path: "detail",   // 子路由不用写 /
                    component: Detail,
                }
            ]
        },
        {
            name: "about",
            path: "/about",
            component: About
        }
    ]
})

src/views/news.vue

<template>
    <div class="news">
        <!-- 导航区 -->
        <ul>
            <!-- RouterLink 定义跳转标签, to 定义跳转链接, 链接需要从根路由开始写全 -->
            <li v-for="n in news" :key="n.id"><RouterLink to="/news/detail">{{ n.title }}</RouterLink></li>
        </ul>

        <!-- 展示区 -->
        <div class="new-content">
            <RouterView></RouterView>
        </div>
    </div>

</template>

<script lang="ts" setup name="News">
import { reactive } from 'vue';
import {RouterView,RouterLink} from 'vue-router'

const news = reactive([
    {
        id: 'adfasdfc01',
        title: '十种抗癌食物',
        content: '西蓝花'
    },
    {
        id: 'adfasdfc02',
        title: '母猪的产后护理',
        content: '吃喝'
    },
    {
        id: 'adfasdfc03',
        title: '小明竟然...',
        content: '打了个喷嚏'
    }
])
</script>

<style>
    .news{
        display: flex;
    }
    .new-content{
        width: 1000px;
        height: 420px;
        border: 1px solid black;
        border-radius: 20px;
        margin-top: 50px;
    }
</style>

6. 路由传参

1. query 参数

1. 父组件传参

<ul>
	<li v-for="n in news" :key="n.id">
        <!-- 方式一: 字符串拼接写法 -->
        <RouterLink :to="`/news/detail?id=${n.id}&title=${n.title}&content=${n.content}`">{{ n.title }}</RouterLink>
        
        <!-- 方式二: 对象写法 -->
        <RouterLink 
            :to="{
            path: '/news/detail',
            query:{
                id:n.id,
                title: n.title,
                content: n.content
            }
            }"
            >
            {{ n.title }}
        </RouterLink>
        
        <!-- 方式三: 命名空间写法, 前提需要在路由规则中添加 name: "detail" -->
        <RouterLink 
            :to="{
            name: 'detail',
            query:{
                id:n.id,
                title: n.title,
                content: n.content
            }
            }"
            >
            {{ n.title }}
        </RouterLink>
    </li>
</ul>

2. 子组件接受参数

方式一: useRoute 中提取传过来的 query 参数

<template>
    <div>
        编号: <span> {{ query.id }}</span>
    </div>
    <div>
        标题: <span>{{ query.title }}</span>
    </div>
    <div>
        内容: <span>{{ query.content }}</span>
    </div>
    
</template>

<script lang="ts" setup name="Detail">
// 1. 导入 toRefs, useRoute hook 函数
import { toRefs } from 'vue';
import { useRoute } from 'vue-router'

// 2. 调用 hook 函数, 并赋值
let route = useRoute()

// 3. 从 route.query 中解构 query 参数, 必须使用 toRefs 将 route 变成一个响应式
const {query} =toRefs(route)

</script>

方式二: props 提取传过来的 query 参数

在 路由规则中 配置使用 props 方式来传递 query 参数

import { createRouter, createWebHistory } from "vue-router";
import Home from "@/components/Home.vue"
import News from "@/components/News.vue"
import About from "@/components/About.vue"
import Detail from "@/components/Detail.vue"

export default createRouter({
    history: createWebHistory(),

    routes:[
        {
            name: "home",
            path: "/home",
            component: Home
        },
        {
            name: "news",
            path: "/news",
            component: News,
            children:[
                {
                    name:"detail",
                    path: "detail",
                    component: Detail,
                    // 函数写法: 可以自己决定将什么作为 props 参数
                    props(route) {
                        return route.query
                    }
                    
                }
            ]
        },
        {
            name: "about",
            path: "/about",
            component: About
        }
    ]
})

在 子组件 中接受 props 传递的数据

<template>
    <div>
        编号: <span> {{ id }}</span>
    </div>
    <div>
        标题: <span>{{ title }}</span>
    </div>
    <div>
        内容: <span>{{ content }}</span>
    </div>
    
</template>

<script lang="ts" setup name="Detail">

defineProps(['id',"title","content"])

</script>

2. params 参数

1. 修改路由规则

import { createRouter, createWebHistory } from "vue-router";
import Home from "@/components/Home.vue"
import News from "@/components/News.vue"
import About from "@/components/About.vue"
import Detail from "@/components/Detail.vue"

export default createRouter({
    history: createWebHistory(),

    routes:[
        {
            name: "home",
            path: "/home",
            component: Home
        },
        {
            name: "news",
            path: "/news",
            component: News,
            children:[
                {
                    name:"detail",
                    path: "detail/:id/:title/:content?",   // 传递 params 参数必须先使用此规则占位, ?表示此参数非必要
                    component: Detail,
                }
            ]
        },
        {
            name: "about",
            path: "/about",
            component: About
        }
    ]
})

2. 父组件传递参数

<ul>
	<li v-for="n in news" :key="n.id">
        <!-- 方式一: 字符串写法 -->
        <RouterLink :to="`/news/detail/${n.id}/${n.title}/${n.content}/`">{{ n.title }}</RouterLink>
		
        <!-- 方式二: 对象写法 -->
        <RouterLink 
            :to="{
            name: 'detail',    // 传递 params 参数 只能使用 name 方式, 前提需要在路由规则中添加 name: "detail" 
            params:{    // params 中的值不能为 对象 或 数组
                id:n.id,
                title: n.title,
                content: n.content
            }
            }"
        >
            {{ n.title }}
        </RouterLink>
    </li>
</ul>

3. 子组件接受参数

方式一: useRoute 中提取传过来的 params 参数

<template>
    <div>
        编号: <span> {{ params.id }}</span>
    </div>
    <div>
        标题: <span>{{ params.title }}</span>
    </div>
    <div>
        内容: <span>{{ params.content }}</span>
    </div>
    
</template>

<script lang="ts" setup name="Detail">
// 1. 导入 toRefs, useRoute hook 函数
import { toRefs } from 'vue';
import { useRoute } from 'vue-router';

// 2. 调用 hook 函数, 并赋值
let route = useRoute()

// 3. 从 route.query 中解构 params 参数, 必须使用 toRefs 将 route 变成一个响应式
const {params} = toRefs(route)
</script>

方式二: props 提取传过来的 params 参数

在 路由规则中 配置使用 props 方式来传递 params 参数

import { createRouter, createWebHistory } from "vue-router";
import Home from "@/components/Home.vue"
import News from "@/components/News.vue"
import About from "@/components/About.vue"
import Detail from "@/components/Detail.vue"

export default createRouter({
    history: createWebHistory(),

    routes:[
        {
            name: "home",
            path: "/home",
            component: Home
        },
        {
            name: "news",
            path: "/news",
            component: News,
            children:[
                {
                    name:"detail",
                    path: "detail/:id/:title/:content?",
                    component: Detail,
                    props: true    // 配置项写法: 将路由收到的 params 参数, 转化为 props 传递给子组件, 子组件可以使用 props 来读取 params 参数 (推荐)
                    // 函数写法: 可以自己决定将什么作为 props 参数
                    props(route) {
                        return route.params.params
                    }
                }
            ]
        },
        {
            name: "about",
            path: "/about",
            component: About
        }
    ]
})

在 子组件 中接受 props 传递的数据

<template>
    <div>
        编号: <span> {{ id }}</span>
    </div>
    <div>
        标题: <span>{{ title }}</span>
    </div>
    <div>
        内容: <span>{{ content }}</span>
    </div>
    
</template>

<script lang="ts" setup name="Detail">

defineProps(['id',"title","content"])

</script>

7. repalce 属性

**push模式( 默认 ): ** 将访问路径 push 到栈底, 浏览器中可以前进后退

replace模式 将访问路径替换之前的路径, 浏览器中无法前进后退

<!-- 添加 replace 属性 -->
<RouterLink replace to="/home" active-class="active">首页</RouterLink>

8. 编程式导航 ( 路由跳转 )

1. 简单使用

**需求: ** 3 秒后跳转到首页

<template>
  <div class="nav">
    <RouterLink to="/home">首页</RouterLink>
  </div>

  <div class="content">
    <RouterView></RouterView>
  </div>
</template>

<script setup lang="ts" name="App">

import {onMounted} from "vue";
// 1. 导入 useRouter
import {useRouter} from "vue-router";

// 2. 接收 router
const router = useRouter();

onMounted(()=>{
  setTimeout(()=>{
    // 3. 跳转到首页
    router.push("/home")
  },3000)
})

</script>

<style scoped>

.content{
  width: 1200px;
  height: 800px;
  border: 1px solid black;
  border-radius: 25px;
  margin-top: 30px;
}
</style>

2. 携带参数

跟 RouterLink 的 to 所传的参数保持一致

<template>
  <div class="nav">
    <RouterLink to="/home">首页</RouterLink>
    <button @click="toHome">跳转到首页</button>
  </div>

  <div class="content">
    <RouterView></RouterView>
  </div>
</template>

<script setup lang="ts" name="App">

import {onMounted} from "vue";
// 1. 导入 useRouter
import {useRouter} from "vue-router";

// 2. 接收 router
const router = useRouter();

const a = 1
const b = 2

// 跳转到首页
function toHome() {
  // 3. 跳转到首页, 并携带 query 参数
  router.push({
    path: '/home',
    query:{
      a,
      b
    }
  })
}

</script>

<style scoped>

.content{
  width: 1200px;
  height: 800px;
  border: 1px solid black;
  border-radius: 25px;
  margin-top: 30px;
}
</style>

9. 重定向

src/router/index.ts

import {createRouter, createWebHistory} from "vue-router";
import Home from "@/components/Home.vue"

export default createRouter({
    history: createWebHistory(),

    routes: [
        {
            name: "home",
            path: "/home",
            component: Home
        },
        {
            path: "/",    
            redirect: "/home",  // 对于根路径 / 的请求, 重定向到 /home 路径
        }
    ]
})
posted @ 2024-08-14 10:57  河图s  阅读(216)  评论(0)    收藏  举报