vue3使用vue-router嵌套路由(多级路由)

文章目录

1、Vue3 嵌套路由

Vue3 嵌套路由的使用和 Vue2 相差不大,主要的区别是 Vue3 的路由实例化使用了 createApp() 方法,所以实例化路由时需要传入根组件。另外,Vue3 的路由对象除了包含 Vue2 中的导航守卫、导航钩子和解析守卫等功能外,还新增了 meta prop 和 route prop。

在使用嵌套路由时,建议将路由按照功能模块进行分层,每一层代表一个主要的功能块,每个层级下的路由数量不要过多,一般建议不要超过 10 个,层级也不要超过 5 层。同时,根据实际业务需求,可以适当调整路由层级和数量,以达到更好的管理和使用效果。

2、项目结构

3、编写相关页面代码

3.1、编写route文件下 index.ts文件

route文件下 index.ts文件代码:

javascript 复制代码
import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router'
import HomeView from '../views/HomeView.vue'

const routes: RouteRecordRaw[] = [
  {
    path: '/',
    redirect: '/home',
  },
  {
    path: '/home',
    name: 'Homeindex',
    component: () => import('../views/Home/index.vue'),
    meta: {
      title: 'Home Page',
      roles: ['admin', 'admin1']
    },
    children: [
      {
        path: 'tigerhhzz',
        name: 'Tigerhhzz',
        component: () => import('@/views/Home/Tigerhhzz.vue'),
        // 也可以使用props传参方式接收传来的参数
        props: (propsRouter) => {
          // console.log('props >router', propsRouter)
          // 可以return query 也可以return params支持两种传参方式
          return propsRouter.query
        },
        // 多级嵌套 建议用query传参
        children: [
          {
            path: 'childA',
            name: 'ChildA',
            component: () => import('@/views/Home/ChildA.vue'),
          },
        ]
      },
      {
        path: 'tigerhhzzb/:id/:title', // 提前定义params参数(可以定义多个)
        name: 'Tigerhhzzb',
        component: () => import('@/views/Home/Tigerhhzzb.vue'),
      },
    ]
  },
]


export const router = createRouter({
  // 路由的history模式,共有三种模式,
  // createWebHistory、createWebHashHistory、createMemoryHistory
  // history: createWebHashHistory(),
  history: createWebHistory(),
  // 路由配置
  routes,
  // 是否严格匹配路由
  strict: true,
  // 路由跳转完成后,页面滚动行为
  scrollBehavior: () => ({ left: 0, top: 0 }),
})

3.2、main.ts文件代码:

javascript 复制代码
import './assets/main.css'

import { createApp } from 'vue'
import { createPinia } from 'pinia'

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

const app = createApp(App)

app.use(createPinia())
app.use(router)

app.mount('#app')

3.3、App.vue文件代码:

javascript 复制代码
<script>

import { defineComponent } from 'vue'
 // vue3.0版本语法
export default defineComponent({
  name: 'App',
})

</script>

<template>

  <RouterView />

</template>

<style>

</style>

3.4、views文件夹下的Home文件夹下的index.vue文件代码:

javascript 复制代码
<template>
  <div class="home">
    <h2>首页{{ title }}</h2>
    <!-- 模拟有权限时显示 -->
    <div v-if="roles.includes(role)">
      <h2>嵌套路由</h2>
      <router-link to="/home/tigerhhzz">push跳转到/home/tigerhhzz页面</router-link>
      <br>
      <!-- 加了/就要写全 /home/lxb -->
      <router-link replace to="/home/tigerhhzzb/id:2/title:102">push跳转到/home/tigerhhzzb页面</router-link>

      <router-view></router-view>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent, reactive, onMounted, toRefs, } from 'vue'
import { useRoute, useRouter } from 'vue-router'

export default defineComponent({
  name: 'Homeindex',
  setup() {
    const router = useRouter()
    const route: any = useRoute()

    const state = reactive({
      title: '',
      role: '', // 我的当前角色
      roles: [''],
      routerGo: (path) => {
        if (path === 'lx') {
          // query传参可以用path 也可以用name: Lx
          router.push({
            path: path,
            query: {
              title: '101',
              id: 1
            }
          })
          // router.replace
        } else {
          // params传参只能用name
          router.replace({
            // path: path + '/id:2/title:102',
            name: 'Lxb',
            params: {
              title: '102',
              id: 2
            }
          })
        }
      },
    })
    onMounted(() => {
      console.log('/home', route)
      state.title = route.meta.title
      state.roles = route.meta.roles
      // 模拟一个接口
      setTimeout(() => {
        const res = {
          code: 200,
          data: {
            token: '123456',
            userName: '吴彦祖',
            role: 'admin'
          }
        }
        state.role = res.data.role
      }, 0)
    })
    return {
      ...toRefs(state)
    }
  }
})
</script>

<style>
.home {
  color: pink;
  font-size: 14px;
}
</style>

3.5、views文件夹下的Home文件夹下的Tigerhhzzb.vue文件代码:

javascript 复制代码
<template>
  <div style="font-size: 14px;">
    <h2>我是练习b{{ route?.params?.title }}页面</h2>
    <div>id:{{ route?.params?.id }}</div>
    <button @click="routerGoBack">返回首页</button>
  </div>
</template>

<script lang="ts">
import { defineComponent, onMounted, reactive, toRefs } from 'vue'
import { useRoute, useRouter } from 'vue-router'

// vue3.0语法
export default defineComponent({
  name: 'Tigerhhzzb',
  setup() {
    const route = useRoute()
    const router = useRouter()
    const state: any = reactive({
      routerGoBack: () => {
        router.replace('/home')
        // 由replace跳转进来的不可以使用router.go(-1) 路由栈是空的》回不到上一个路由
      },
    })

    onMounted(() => {
      console.log(route)
    })

    return {
      route,
      ...toRefs(state)
    }
  },
})
</script>

3.6、views文件夹下的Home文件夹下的T.vue文件代码:

javascript 复制代码
<template>
  <div style="font-size: 14px;">
    <h2>我是练习{{ title }}页面</h2>
    <div>id:{{ id }}</div>
    <div>props: {{ props }}</div>
    <button @click="routerGoBack">返回上一页</button>
    <br>
    <button @click="routerGo('/home/lx/childA')">去子路由childA</button>
    <!-- <router-view></router-view> -->
    <router-view />
  </div>
</template>

<script lang="ts">
import { defineComponent, onMounted, reactive, toRefs } from 'vue'
import { useRoute, useRouter } from 'vue-router'

// vue3.0语法
export default defineComponent({
  name: 'Tigerhhzz',
  props: {
    id: {
      type: String,
      default: ''
    },
    title: {
      type: String,
      default: ''
    },
  },
  setup(props) {
    const route = useRoute()
    const router = useRouter()
    const state: any = reactive({
      id: '',
      title: '',
      routerGoBack: () => {
        router.go(-1) // go(-1)回到上一个路由
        // 也可以用router.replace('/home')跳回指定页
      },
      routerGo: (path) => {
        router.push(path)
      }
    })

    onMounted(() => {
      console.log('lx route', route)
      console.log('lx props', props)
      if (route.query) {
        state.id = route.query.id
        state.title = route.query.title
      }
    })

    return {
      props,
      ...toRefs(state)
    }
  },
})
</script>

3.7、views文件夹下的Home文件夹下的ChildA.vue文件代码:

javascript 复制代码
<template>
    <div style="font-size: 14px;background: skyblue;">
      <h3>我是ChildA组件</h3>
      <h3>route.query:{{ route.query }}</h3>
    </div>
  </template>
  
  <script lang="ts">
  import { defineComponent, onMounted, } from 'vue'
  import { useRoute, useRouter } from 'vue-router'
  // vue3.0语法
  export default defineComponent({
    name: 'ChildA',
    setup() {
      const router = useRouter()
      const route = useRoute()
      function goBack() {
        router.go(-1)
      }
      onMounted(() => {
        console.log(route)
      })
      // 可以在页面销毁前清除事件
      // onUnmounted(() => {
      //   proxy.$mittBus.off('mittUserA')
      // })
      return {
        route, goBack
      }
    },
  })
  </script>

4、测试效果

  • 初始页面效果:
  • 先点击push跳转到/home/tigerhhzzb页面>(嵌套一层的路由)页面效果:
    嵌套一层的路由从原本/home跳入了/home/tigerhhzzb 子路由页面,点击回到首页。
  • 再点击push跳转到/home/tigerhhzz页面>(嵌套多层的路由)页面效果:
  • 子路由效果:

先去到了第一层/home/tigerhhzz子路由页面,

再点击去子路由childA按钮>页面效果:

进到了嵌套的第二层/home/tigerhhzz/childA子路由页面

点击可返回上一页/home/lx 再点击可回到/home首页。

相关推荐
崔庆才丨静觅11 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606112 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了12 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅12 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅12 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅13 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment13 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅13 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊13 小时前
jwt介绍
前端
爱敲代码的小鱼13 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax