vue3(十三)-基础入门之路由配置与重定向

一、一级路由与重定向

1、创建 App.vue

在父组件中导入子组件 Navbar

<template>
  <div>
    <navbar></navbar>
  </div>
</template>

<style lang="scss"></style>

<script>
import navbar from '@/components/Navbar'

export default {
  components: {
    navbar
  }
}
</script>

2、创建 Navbar.vue 组件

App.vue 导入了 Navbar 组件,所以需要创建该组件;使用 router-link 作为跳转标签;而 router-view 看作一个插槽,点击相应的跳转标签,就根据路径到 myrouter.js 找与跳转标签中的路径一致的 path,根据 myrouter.js 文件中路径与组件的映射关系,显示相应的组件

<template>
  <div>
    <router-link to="/film" active-class="mycolor">电影</router-link>
    <router-link to="/video" active-class="mycolor">视频</router-link>
    <router-link to="/center" active-class="mycolor">我的</router-link>
    <router-view></router-view>
  </div>
</template>

<!-- 设置点击后的文字颜色 -->
<style lang="scss" scoped>
.mycolor {
  color: red;
}
</style>

3、配置 main.js 文件

在这导入路由的的配置文件 myrouter.js,并显式使用 use(router) 来绑定路由

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

createApp(App).use(router).mount('#app')

4、配置路由

创建 myrouter.js 文件,配置路径与组件的映射关系

import { createRouter, createWebHistory } from 'vue-router'
import Film from './views/Film.vue'
import Center from '@/views/Center.vue'
import Video from '@/views/Video.vue'

const routes = [
  {
    path: '/film',
    component: Film
  },
  {
    path: '/center/',
    component: Center
  },
  {
    path: '/video',
    component: Video
  },
  {
  	// path: '/:catchAll(.*)*',将匹配所有内容并将其放在 `$route.params.pathMatch` 下
    path: '/:pathMatch(.*)*',
    // 将匹配以 `/user-` 开头的所有内容,并将其放在 `$route.params.afterUser` 下
    // { path: '/user-:afterUser(.*)', component: UserGeneric },
    //重定向,当没有匹配路径时重定向到 /film
    redirect: '/film'
  }
]

const myrouter = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default myrouter

5、创建子组件

5.1、Film.vue

<template>
  <div class="film">
    <h1>This is an film page</h1>
  </div>
</template>

5.2、Video.vue

<template>
  <div class="video">
    <h1>This is an video page</h1>
  </div>
</template>

5.2、Center.vue

<template>
  <div class="center">
    <h1>This is an center page</h1>
  </div>
</template>

6、页面展示

当分别点击 电影 视频 我的 三个标签后,分别展示 Film.vue Video.vue Center.vue 3个组件内容

在这里插入图片描述

A:以下为通过监听浏览器 hashchange 事件(监听浏览器地址栏路径的切换)实现的简单路由


<script setup>
import { ref, computed } from 'vue'
import Film from './views/Film'
import Cneter from './views/Center'
import Video from './views/Video'

const routes = {
  '/': Film,
  '/center': Cneter
}

const currentPath = ref(window.location.hash)

window.addEventListener('hashchange', () => {
  currentPath.value = window.location.hash
})

const currentView = computed(() => {
  return routes[currentPath.value.slice(1) || '/'] || Video
})
</script>

<template>
  <div>
    <a href="#/">Film</a>
    <a href="#/center">Center</a>
    <a href="#/non-exist">Video</a>
    <component :is="currentView" />
  </div>
</template>

B:main.js 文件

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

createApp(App).mount('#app')

二、二级路由与重定向

上述第一种一级路由写法中, App.vue 、Navbar.vue 、main.js 、Video.vue、Center.vue 不作修改

1、Film.vue

增加 轮播、正在热映、即将上映 三个组件

<template>
  <div class="film">
    <filmCarousel></filmCarousel>
    <router-link to="/film/nowPlaying" active-class="mycolor">正在热映</router-link>
    <router-link to="/film/comingSoon" active-class="mycolor">即将上映</router-link>
    <router-view></router-view>
  </div>
</template>

<script>
import filmCarousel from '@/components/film/FilmCarousel.vue'
export default {
  components: {
    filmCarousel
  }
}
</script>
<style lang="scss" scoped>
.mycolor {
  color: blue;
}
</style>

新增

轮播组件:FilmCarousel.vue
正在热映:FilmNowPlaying.vue
即将上映:FilmCommingsoon.vue

2、myrouter.js

增加 /film 路径下的二级路由与重定向

import { createRouter, createWebHistory } from 'vue-router'
import Film from './views/Film.vue'
import Center from '@/views/Center.vue'
import Video from '@/views/Video.vue'
import FilmNowPlaying from '@/components/film/FilmNowPlaying.vue'
import FilmCommingsoon from '@/components/film/FilmCommingsoon.vue'

const routes = [
  {
    path: '/film',
    component: Film,
    children: [
      { path: 'nowPlaying', component: FilmNowPlaying },
      { path: 'comingSoon', component: FilmCommingsoon },
      // 重定向:当 /film 路径下没有匹配的路径时重定向到 /film/nowPlaying
      { path: '', redirect: '/film/nowPlaying' }
    ]
  },
  {
    path: '/center/',
    component: Center
  },
  {
    path: '/video',
    component: Video
  },
  {
    // path: '/:catchAll(.*)',重定向,当没有匹配路径时重定向到 /film
    path: '/:pathMatch(.*)',
    redirect: '/film'
  }
]

const myrouter = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default myrouter

3、新增的三个子组件

A、FilmCarousel.vue

<!-- 电影-轮播 -->
<template>
  <div class="swiper-container">
    <div class="swiper-wrapper">
      <div class="swiper-slide" v-for="(item,index) in dataList" :key="index">
        {{ item }}
      </div>
    </div>
  </div>
</template>

<script>
import Swiper from 'swiper'
import 'swiper/swiper-bundle.css'
export default {
  data() {
    return { dataList: [] }
  },
  mounted() {
    this.dataList = ['轮播1', '轮播2', '轮播4', '轮播4']
  },
  updated() {
    const mySwiper = new Swiper('.swiper-container', {
      loop: true,
      autoplay: { delay: 1000, disableOnInteraction: false },
      scrollbar: false,
      slidesPerView: 1,
      slidesPerGroup: 1
    })
  }
}
</script>

<style scoped>
.swiper-container {
  width: 100%; /* 根据需要进行调整 */
  overflow: hidden;
}
</style>

B、FilmNowPlaying.vue

<!-- 电影-正在热映 -->
<template>
  <div>
    <div v-for="(item,index) in dataList" :key="index">
      {{ item }} 
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return { dataList: ['热映1', '热映2', '热映3', '热映4'] }
  }
}
</script>

C、FilmCommingsoon.vue

<!-- 电影-即将上映 -->
<template>
  <div>
    <div v-for="(item,index) in dataList" :key="index">
      {{ item }}
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return { dataList: ['即将上映1', '即将上映2', '即将上映3', '即将上映4'] }
  }
}
</script>

4、页面展示

在这里插入图片描述

三、动态路由

这里一共整理了 5 种传参方式,分别为

1、路径字符串/ 拼接参数
2、路径字符串?拼接参数
3、path + query
4、name + query
5、name + params

1、在 FilmNowPlaying.vue 中增加 查看详情 按钮

<!-- 电影-正在热映 -->
<template>
  <div>
    <div v-for="(item,index) in dataList" :key="index">
      {{ item }} <button @click="checkDetail(index)"> 查看详情</button>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return { dataList: ['热映1', '热映2', '热映3', '热映4'] }
  },
  methods: {
    checkDetail(index) {
      // 1、路径字符串/ 拼接参数
      // this.$router.push('/film/detail/' + index)
      
      // 2、路径字符串?拼接参数
      this.$router.push('/film/detail?index=' + index)
      
      // 3、path + query
      // this.$router.push({
      //   path: 'detail',
      //   query: {
      //     index: index
      //   }
      // })
      
      // 4、name + query
      // this.$router.push({
      //   name: 'detail',
      //   query: {
      //     index: index
      //   }
      // })
      
      // 5、name + params
      // this.$router.push({
      //   name: 'detail',
      //   params: {
      //     index: index
      //   }
      // })
    }
  }
}
</script>

2、新增 FilmDetail.vue 组件

<!-- 详情页面 -->
<template>
  <div>详情页面</div>
</template>

<script>
import { useRouter } from 'vue-router'
export default {
  mounted() {
    // 1、路径字符串/ 拼接参数
    // console.log(this.$route.params.index)
    // 2、路径字符串?拼接参数
    console.log(this.$route.query.index)
    // 3、path + query
    // console.log(this.$route.query.index)
    // 4、name + query
    // console.log(this.$route.query.index)
    // 5、name + params
    // console.log(this.$route.params.index)
  }
}
</script>

3、myrouter.js

import { createRouter, createWebHistory } from 'vue-router'
import Film from './views/Film.vue'
import Center from '@/views/Center.vue'
import Video from '@/views/Video.vue'
import FilmNowPlaying from '@/components/film/FilmNowPlaying.vue'
import FilmCommingsoon from '@/components/film/FilmCommingsoon.vue'
import FilmDetail from '@/components/film/FilmDetail.vue'
const routes = [
  {
    path: '/film',
    component: Film,
    children: [
      { path: 'nowPlaying', component: FilmNowPlaying },
      { path: 'comingSoon', component: FilmCommingsoon },
      // 重定向:当 /film 路径下没有匹配的路径时重定向到 /film/nowPlaying
      { path: '', redirect: '/film/nowPlaying' },
      
      // 1、路径字符串/ 拼接参数
      // { path: 'detail/:index', component: FilmDetail },

      // 2、路径字符串?拼接参数
      { path: 'detail', component: FilmDetail }

      // 3、path + query
      // { path: 'detail', component: FilmDetail },

      // 4、name + query
      // { path: 'detail', name: 'detail', component: FilmDetail },

      // 5、name + params
      // { path: 'detail/:index', name: 'detail', component: FilmDetail },
    ]
  },
  {
    path: '/center/',
    component: Center
  },
  {
    path: '/video',
    component: Video
  },
  {
    // path: '/:catchAll(.*)', 重定向,当没有匹配路径时重定向到 /film
    path: '/:pathMatch(.*)',
    redirect: '/film'
  }
]

const myrouter = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default myrouter

4、页面展示

在这里插入图片描述

四、路由语法介绍

1、动态路由匹配

1.1 、路径参数 用冒号 : 表示,当一个路由被匹配时,它的 params 的值将在每个组件中以 this.$route.params
的形式暴露出来。因此跨域通过 this. $route.params.index 获取参数

1.2、在同一个路由中设置有多个 路径参数,它们会映射到 $route.params 上的相应字段。例如:

匹配模式匹配路径$route.params
/users/:username/users/eduardo{ username: 'eduardo' }
/users/:username/posts/:postId/users/eduardo/posts/123{ username: 'eduardo', postId: '123' }

2、路由匹配语法

1、在参数中自定义正则

const routes = [
  // /:orderId -> 仅匹配数字
  { path: '/:orderId(\\d+)' },
  // /:productName -> 匹配其他任何内容
  { path: '/:productName' },
]

2、可重复的参数

2.1、匹配规则

const routes = [
  // /:chapters ->  匹配 /one, /one/two, /one/two/three, 等
  { path: '/:chapters+' },
  // /:chapters -> 匹配 /, /one, /one/two, /one/two/three, 等
  { path: '/:chapters*' },
  
  // 仅匹配数字
  // 匹配 /1, /1/2, 等
  { path: '/:chapters(\\d+)+' },
  // 匹配 /, /1, /1/2, 等
  { path: '/:chapters(\\d+)*' },
]

2.2、传参

// 给定 { path: '/:chapters*', name: 'chapters' },
router.resolve({ name: 'chapters', params: { chapters: [] } }).href
// 产生 /
router.resolve({ name: 'chapters', params: { chapters: ['a', 'b'] } }).href
// 产生 /a/b

// 给定 { path: '/:chapters+', name: 'chapters' },
router.resolve({ name: 'chapters', params: { chapters: [] } }).href
// 抛出错误,因为 `chapters` 为空

3.可选参数

也可以通过使用 ? 修饰符(0 个或 1 个)将一个参数标记为可选:

const routes = [
  // 匹配 /users 和 /users/posva
  { path: '/users/:userId?' },
  // 匹配 /users 和 /users/42
  { path: '/users/:userId(\\d+)?' },
]

3、编程式导航

3.1、push()

当点击 时,内部会调用这个方法,所以点击 相当于调用 router.push(…) :

声明式编程式
<router-link :to="...">router.push(...)

该方法的参数可以是一个字符串路径,或者一个描述地址的对象。例如:

// 字符串路径
router.push('/users/eduardo')

// 带有路径的对象
router.push({ path: '/users/eduardo' })

// 命名的路由,并加上参数,让路由建立 url
router.push({ name: 'user', params: { username: 'eduardo' } })

// 带查询参数,结果是 /register?plan=private
router.push({ path: '/register', query: { plan: 'private' } })

// 带 hash,结果是 /about#team
router.push({ path: '/about', hash: '#team' })

注意:如果提供了 path,params 会被忽略,上述例子中的 query 并不属于这种情况;params 不能与 path 一起使用
当指定 params 时,可提供 string 或 number 参数(或者对于可重复的参数可提供一个数组)。任何其他类型(如对象、布尔等)都将被自动字符串化。对于可选参数,你可以提供一个空字符串(“”)或 null 来移除它。

3.2、替换当前位置

它的作用类似于 router.push,唯一不同的是,它在导航时不会向 history 添加新记录,正如它的名字所暗示的那样——它取代了当前的条目。

声明式编程式
<router-link :to="..." replace>router.replace(...)

也可以直接在传递给 router.push 的 to 参数中增加一个属性 replace: true :

router.push({ path: '/home', replace: true })
// 相当于
router.replace({ path: '/home' })

3.3、横跨历史

该方法采用一个整数作为参数,表示在历史堆栈中前进或后退多少步,类似于 window.history.go(n)。

// 向前移动一条记录,与 router.forward() 相同
router.go(1)

// 返回一条记录,与 router.back() 相同
router.go(-1)

// 前进 3 条记录
router.go(3)

// 如果没有那么多记录,静默失败
router.go(-100)
router.go(100)

4、命名视图

有时候想同时 (同级) 展示多个视图,而不是嵌套展示;需要在 < router-view > 标签中 命名 name 属性; 如果 router-view 没有设置名字,那么默认为 default。

App.vue

<template>
  <h1>Named Views</h1>
  <ul>
    <li>
      <router-link to="/">First page</router-link>
    </li>
    <li>
      <router-link to="/other">Second page</router-link>
    </li>
  </ul>
  <!-- 没有name属性,默认default -->
  <router-view class="view one"></router-view>
  <!-- name="a",对应 router.js 中的components,匹配components中的key,从而具体组件 -->
  <router-view class="view two" name="a"></router-view>
  <router-view class="view three" name="b"></router-view>
</template>

<script>
export default {
  name: "App",
};
</script>

router.js

import { createRouter, createWebHistory } from 'vue-router'
import First from './views/First.vue'
import Second from './views/Second.vue'
import Third from './views/Third.vue'

export const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/',
      components: {
        default: First,
        a: Second,
        b: Third,
      },
    },
    {
      path: '/other',
      components: {
        default: Third,
        a: Second,
        b: First,
      },
    },
  ],
})

5、重定向和别名

5.1、重定向

  • 重定向也是通过 routes 配置来完成,下面例子是从 /home 重定向到 /:
const routes = [{ path: '/home', redirect: '/' }]
  • 重定向的目标也可以是一个命名的路由:
const routes = [{ path: '/home', redirect: { name: 'homepage' } }]
  • 甚至是一个方法,动态返回重定向目标:
const routes = [
  {
    // /search/screens -> /search?q=screens
    path: '/search/:searchText',
    redirect: to => {
      // 方法接收目标路由作为参数
      // return 重定向的字符串路径/路径对象
      return { path: '/search', query: { q: to.params.searchText } }
    },
  },
  {
    path: '/search',
    // ...
  },
]
  • 也可以重定向到相对位置:
const routes = [
  {
    // 将总是把/users/123/posts重定向到/users/123/profile。
    path: '/users/:id/posts',
    redirect: to => {
      // 该函数接收目标路由作为参数
      // 相对位置不以`/`开头
      // 或 { path: 'profile'}
      return 'profile'
    },
  },
]

5.2、别名

/ 别名为 /home,意味着当用户访问 /home 时,URL 仍然是 /home,但会被匹配为用户正在访问 /

const routes = [{ path: '/', component: Homepage, alias: '/home' }]

通过别名,可以自由地将 UI 结构映射到一个任意的 URL,而不受配置的嵌套结构的限制。使别名以 / 开头,以使嵌套路径中的路径成为绝对路径。甚至可以将两者结合起来,用一个数组提供多个别名:

const routes = [
  {
    path: '/users',
    component: UsersLayout,
    children: [
      // 为这 3 个 URL 呈现 UserList
      // - /users
      // - /users/list
      // - /people
      //   别名:/people 将可以代表 /users 
      //   别名:list 作为子节点的别名,最后结构为:/users/list
      { path: '', component: UserList, alias: ['/people', 'list'] },
    ],
  },
]

如果路由有参数,请确保在任何绝对别名中包含它们:

const routes = [
  {
    path: '/users/:id',
    component: UsersByIdLayout,
    children: [
      // 为这 3 个 URL 呈现 UserDetails
      // - /users/24
      // - /users/24/profile
      // - /24
      { path: 'profile', component: UserDetails, alias: ['/:id', ''] },
    ],
  },
]
  • 13
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值