Code前端首页关于Code前端联系我们

1.Vue Router setup 到底要怎么初始化配置?

terry 11小时前 阅读数 19 #Vue

用Vue 3开发项目时,很多同学一碰到Vue Router的setup用法就犯难——毕竟组合式API和之前的选项式写法思路差别挺大,这篇用问答形式,把Vue Router setup里的配置、导航、参数处理这些核心问题拆开来唠,帮你把路由逻辑顺明白,以后写项目少踩坑~

想在Vue 3项目里用Vue Router,第一步得把路由实例“搭”起来,首先得装依赖(如果是Vite+Vue 3的项目,执行`npm i vue-router@4`),然后分两步走:
  • 第一步:创建路由实例
    新建个router/index.js(或ts)文件,用createRoutercreateWebHistory(或createWebHashHistory,看路由模式)来配置。

    import { createRouter, createWebHistory } from 'vue-router'
    import HomeView from '../views/HomeView.vue'
    const router = createRouter({
      history: createWebHistory(import.meta.env.BASE_URL), // 配置路由模式
      routes: [
        {
          path: '/',
          name: 'home',
          component: HomeView
        },
        {
          path: '/about',
          name: 'about',
          component: () => import('../views/AboutView.vue') // 路由懒加载写法
        }
      ]
    })
    export default router

    这里routes数组里每个对象对应一条路由规则,component既可以直接导入组件,也能用() => import(...)做懒加载(后续会讲好处)。

  • 第二步:挂载到Vue应用
    打开main.js,把路由实例挂到App上:

    import { createApp } from 'vue'
    import App from './App.vue'
    import router from './router'
    const app = createApp(App)
    app.use(router) // 让Vue应用“认识”路由系统
    app.mount('#app')

    完成这步,项目就有了路由的基础能力,接下来要解决的是组件里怎么用setup和路由互动

组件里怎么用setup获取路由信息和导航?

Vue 3的组合式API里,操作路由主要靠两个“工具”:useRouteruseRoute,需先从vue-router导入:

import { useRouter, useRoute } from 'vue-router'
  • useRouter:负责“导航跳转”
    它返回路由实例,能调用pushreplacego等方法,比如做个按钮,点击跳转到/about页面:

    <script setup>
    import { useRouter } from 'vue-router'
    const router = useRouter()
    const goAbout = () => {
      router.push('/about') // 直接写路径跳转
      // 也能传对象:router.push({ name: 'about' }) 
      // (路由配置了name时,用name更稳,避免路径拼写错误)
    }
    </script>
    <template>
      <button @click="goAbout">去关于页</button>
    </template>
  • useRoute:负责“读路由信息”
    它返回当前路由的详细信息,比如path(当前路径)、params(动态参数)、query(查询参数)、meta(路由元信息)等,举个例子,页面里要显示当前路径:

    <script setup>
    import { useRoute } from 'vue-router'
    const route = useRoute()
    console.log(route.path) // 打印如“/”或“/about”
    </script>

    简单说,useRouter负责“跳”,useRoute负责“读”,记住这俩工具,组件里和路由互动就有抓手了。

动态路由参数在setup里怎么处理?

比如做用户详情页,路由配置为/user/:id,不同用户(id不同)需加载不同数据,要注意:同一路由,参数变化时,组件不会重新创建(比如从/user/1跳到/user/2,组件实例复用),所以得主动监听参数变化,否则数据不会更新。

  • 步骤1:路由配置定义动态参数
    router/index.js里添加:

    {
      path: '/user/:id',
      name: 'user',
      component: () => import('../views/UserView.vue')
    }
  • 步骤2:组件里监听参数变化
    UserView.vue的setup中,用watchwatchEffect紧盯route.params.id,示例:

    <script setup>
    import { useRoute, watch, watchEffect } from 'vue-router'
    import { ref } from 'vue'
    const route = useRoute()
    const userInfo = ref({})
    // 方法1:watch监听params变化
    watch(
      () => route.params.id, 
      (newId) => {
        // 每次id变化,重新请求数据
        fetchUser(newId).then(data => {
          userInfo.value = data
        })
      },
      { immediate: true } // 页面首次加载时也执行
    )
    // 方法2:watchEffect(自动追踪依赖)
    watchEffect(() => {
      const id = route.params.id
      fetchUser(id).then(data => {
        userInfo.value = data
      })
    })
    // 模拟请求函数
    function fetchUser(id) {
      return new Promise(resolve => {
        setTimeout(() => {
          resolve({ id, name: `用户${id}` })
        }, 500)
      })
    }
    </script>
    <template>
      <div>用户ID:{{ route.params.id }}</div>
      <div>用户信息:{{ userInfo }}</div>
    </template>

    这里immediate: true很关键,页面首次加载时也需执行请求逻辑;若没加,只有参数变化时才触发,刚进页面数据会是空的。

嵌套路由在setup模式下怎么配置和渲染?

做后台管理系统时,常需“嵌套路由”——比如外层是Layout(含侧边栏、顶栏),内层切换Dashboard、Settings等页面,配置和使用分两步:

  • 步骤1:路由配置写children
    router/index.js里,给父路由加children数组:

    {
      path: '/admin',
      name: 'admin',
      component: () => import('../views/AdminLayout.vue'), // 父组件(Layout)
      children: [
        {
          path: '', // 空路径表示默认子路由
          name: 'dashboard',
          component: () => import('../views/Dashboard.vue')
        },
        {
          path: 'settings',
          name: 'settings',
          component: () => import('../views/Settings.vue')
        }
      ]
    }
  • 步骤2:父组件用渲染子路由
    AdminLayout.vue的模板里,用放置子组件:

    <script setup>
    // 父组件逻辑,比如处理侧边栏导航
    import { useRouter } from 'vue-router'
    const router = useRouter()
    </script>
    <template>
      <div class="admin-layout">
        <aside>侧边栏</aside>
        <main>
          <!-- 子路由组件渲染到这里 -->
          <RouterView />
        </main>
      </div>
    </template>

    这样,访问/admin时默认显示Dashboard;访问/admin/settings时显示Settings,父组件负责布局,子组件负责具体内容,分工清晰。

编程式导航在setup里有哪些需要注意的点?

router.push等方法时,看似简单,实则有不少细节易踩坑:

  • 路径与命名路由的区别
    name跳转更“稳”,因路径可能变化,但name一般固定,示例:

    // 方式1:用path(传query需自己拼接)
    router.push('/about?tab=1') 
    // 方式2:用name + query(更灵活)
    router.push({ name: 'about', query: { tab: '1' } })

    若路由配置了params(动态参数),只能用name跳转——因path里的参数是写死的,而name可动态传params:

    // 错误:path写params会被当作字符串,无法解析
    router.push('/user/123') // 硬编码id,不灵活
    // 正确:用name + params
    router.push({ name: 'user', params: { id: 123 } })
  • 组件内守卫的替代方案
    Vue Router 3中,组件里可写beforeRouteEnter等守卫,但Vue Router 4的组合式API不支持组件内选项式守卫,若想在导航进入前做判断(如权限验证),需换思路:

    • 全局导航守卫:在router/index.js里写router.beforeEach,判断目标路由的meta是否需权限;
    • 组合式API的watch:在组件setup里,watch路由变化提前拦截(但不如全局守卫优雅)。
      举个全局守卫的例子:
      // router/index.js
      router.beforeEach((to, from) => {
      if (to.meta.requiresAuth && !isLogin()) { 
        return { name: 'login' } // 未登录则跳登录页
      }
      })

路由懒加载在setup项目里怎么配置更高效?

路由懒加载的核心是让页面按需加载,减少初始包体积,提升首屏速度,配置简单,但需结合项目需求优化:

  • 基础配置:用import()语法
    在路由配置里,把component写成函数形式:

    {
      path: '/about',
      name: 'about',
      component: () => import('../views/AboutView.vue')
    }

    这样webpack(或Vite)会把该组件单独打包,只有访问到/about时才加载对应js文件。

  • 进阶优化:配合Suspense处理加载状态
    若组件加载时想显示“加载中”提示,Vue的组件能派上用场,比如在App.vue里:

    <template>
      <Suspense>
        <template #default>
          <RouterView />
        </template>
        <template #fallback>
          <div>加载中...</div>
        </template>
      </Suspense>
    </template>

    需注意,路由懒加载的组件若用了异步组件(如const Comp = defineAsyncComponent(() => import(...))),Suspense才能捕获加载状态。

  • 分组懒加载(可选)
    若多个路由组件属于同一类(如都在admin目录下),可用“魔法注释”合并打包:

    component: () => import(/* webpackChunkName: "admin" */ '../views/AdminView.vue')

    这样所有加了webpackChunkName: "admin"的组件,会被打包到同一chunk里,减少请求次数。

路由元信息(meta)在setup里怎么用?

路由元信息(meta)是“附加信息容器”——可给路由加自定义信息(如是否需登录、页面标题、权限等级)。

  • 步骤1:路由配置加meta
    router/index.js的路由规则里写:

    {
      path: '/profile',
      name: 'profile',
      component: () => import('../views/Profile.vue'),
      meta: { 
        requiresAuth: true, // 需登录
        title: '个人中心' // 页面标题
      }
    }
  • 步骤2:在组件或守卫里读取meta

    • 在组件里读:用useRoute().meta
      比如在Profile.vue里设置页面标题:
      <script setup>
      import { useRoute, onMounted } from 'vue-router'
      const route = useRoute()
      onMounted(() => {
        document.title = route.meta.title || '默认标题'
      })
      </script>
    • 在导航守卫里读:判断权限
      前文提过的全局守卫,结合meta做权限控制:
      router.beforeEach((to, from) => {
        if (to.meta.requiresAuth && !isAuthenticated()) {
          return { name: 'login' }
        }
      })

      这样meta就成了路由的“附加属性”,想加什么自定义规则都能往里塞。

多路由出口(Named Views)在setup中怎么实现?

有时一个页面需同时渲染多个组件(如左侧侧边栏+右侧内容区),这时得用命名视图

  • 步骤1:路由配置写components(注意复数)
    router/index.js里,给路由规则的components(复数)配多个命名组件:

    {
      path: '/dashboard',
      name: 'dashboard',
      components: {
        default: () => import('../views/DashboardMain.vue'), // 默认视图
        sidebar: () => import('../views/DashboardSidebar.vue') // 命名为sidebar的视图
      }
    }
  • 步骤2:父组件用渲染
    在Dashboard的父组件(如App.vue或Layout组件)里,用带name的

    <template>
      <div class="dashboard-layout">
        <!-- 渲染name为sidebar的组件 -->
        <RouterView name="sidebar" />
        <!-- 渲染默认组件(name不写即为default) -->
        <RouterView />
      </div>
    </template>

    这样访问/dashboard时,两个组件会同时渲染到对应位置,适合复杂布局场景。

把这些问题吃透,Vue Router setup的核心用法基本就拿捏住了~其实思路很简单:先搭好路由实例,组件里用useRouter和useRoute和路由互动,再结合动态参数、嵌套路由、懒加载这些特性,就能应对大部分项目场景,要是还有细节卡壳,不妨回到官方文档(或自己写个小Demo试一把),实践几次就顺溜啦~

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门