Vue-Router入门(三) :嵌套路由和编程式导航

前言

前面的文章Vue-Router入门(一) :初识路由,我们了解到了一个children属性,代表着路由下面的子路由,也称为嵌套路由 。也提到组件 router-link 来进行跳转。本文就来详细介绍下嵌套路由以及编程式导航。

嵌套路由

因为组件是有嵌套关系的存在,路由与组件是对应的,如果我们做过一些比较复杂的项目,它的页面大多由多层嵌套的组件组成,所有我们就一定会接触到嵌套路由。

嵌套路由的语法很简单,就是在创建路由时将子路由放到childrenchildren的ts接口依旧为RouteRecordRaw数组,这也就意味着嵌套可以无限下去。

写法

嵌套路由写法虽然很简单,但还是有好几个注意的点,下面我们就在Root路由添加一个子路由渲染下视图。

js 复制代码
// 定义路由
const routes: Array<RouteRecordRaw> = [
  {
    path: "/",
    name: "Root",
    component: () => import("../views/TheRoot.vue"),
    //定义子路由
    children: [
      {
        path: "/home",
        name: "home",
        component: HomeView,
      },
      {
        path: "/about",
        name: "about",
        //也可以通过懒加载的方式
        component: () => import("../views/AboutView.vue"),
      },
    ],
  },
];

我们添加了一个about子路由,加载路由的写法就是父路由后面拼接path名称,我们打开页面请求/about

还是Root界面,这是为什么呢?原因很简单,TheRoot文件没有添加router-view路由想要渲染出对应的视图,必须要用router-view,嵌套路由就需要在父路由添加。我们在Root界面添加一个router-view,然后刷新页面。

子路由对应的组件就渲染出来了。嵌套路由的表现出来的就是嵌套组件,这也是我们一直强调的路由对于组件,

编程式导航

前面章节我们都是通过router-link进行路由之间的跳转,这种是声明式导航。但日常开发中我们需要从代码层面进行路由跳转,也就是编程式导航,本节我们就来学习一下。

本部分所涉及的所有源码都在这里源码位置

编程式导航写法

编程式导航在代码层面操作路由,这些操作都是router实例方法,要想使用这些方法就得先访问router实例。vue版本不同访问router实例的方法也不同:

  • vue2.x(2.7可以引入组合式API)使用编程式API可以通过this.$router进行访问。
  • vue3.x组合式API,在setup中需要使用useRouter函数。 router中有很多实例方法,下面我们了解一下导航相关的。

push方法

router.push方法用于跳转路由,可以导航到任意页面,具体的语法为:

js 复制代码
   router.push(to)

to参数为具体的路由,ts类型为RouteLocationRaw ,返回一个promise

js 复制代码
    push(to: RouteLocationRaw): Promise<NavigationFailure | void | undefined>;
    /**
     * Programmatically navigate to a new URL by replacing the current entry in
     * the history stack.
     *
     * @param to - Route location to navigate to
     */

RouteLactionRaw是一个联合类型,核心是两种形式:

  • RouteQueryAndHash&LocationAsPath&RouteLocationOptions:path(路径)、query(传参)、hash形式组合。
  • RouteQueryAndHash & LocationAsRelativeRaw & RouteLocationOptions:name(命令视图)、params(传参)形式组合。
js 复制代码
   interface RouteQueryAndHash {
        query?: LocationQueryRaw;
        hash?: string;
   }
   interface LocationAsPath {
        path: string;
   }
   interface LocationAsRelativeRaw {
        name?: RouteRecordName;
        params?: RouteParamsRaw;
   }

push的参数对象不能混用,比如name与query不能一块使用,这是由具体的ts类型决定的。

js 复制代码
router.push({ name: 'home', params: { id: '123' } })

router.push({ path: '/home', query: { id: '123' } })

原理

push的原理就是向history添加新记录,如果我们在A页面用push导航到B页面,点击浏览器退回页面就会回到A页面。虽说原理很简单,但源码还是复杂的,毕竟要考虑各种情况。首先会判断是否有重定向地址,如果有跳转重定向地址。

js 复制代码
function pushWithRedirect(
    to: RouteLocationRaw | RouteLocation,
    redirectedFrom?: RouteLocation
  ): Promise<NavigationFailure | void | undefined> {
    const targetLocation: RouteLocation = (pendingLocation = resolve(to))
    const from = currentRoute.value
    const data: HistoryState | undefined = (to as RouteLocationOptions).state
    const force: boolean | undefined = (to as RouteLocationOptions).force
    // to could be a string where `replace` is a function
    const replace = (to as RouteLocationOptions).replace === true

    const shouldRedirect = handleRedirectRecord(targetLocation)

    if (shouldRedirect)
      return pushWithRedirect(
        assign(locationAsObject(shouldRedirect), {
          state:
            typeof shouldRedirect === 'object'
              ? assign({}, data, shouldRedirect.state)
              : data,
          force,
          replace,
        }),
        // keep original redirectedFrom if it exists
        redirectedFrom || targetLocation
      )

pushWithRedirect还考虑了replace导航,通过一系列判断最终调用routerHistory的push方法。

js 复制代码
 if (isPush) {
      // on the initial navigation, we want to reuse the scroll position from
      // history state if it exists
      if (replace || isFirstNavigation)
        routerHistory.replace(
          toLocation.fullPath,
          assign(
            {
              scroll: isFirstNavigation && state && state.scroll,
            },
            data
          )
        )
      else routerHistory.push(toLocation.fullPath, data)
    }

replace方法

router.replace替换当前路由,replace的用法跟push方法基本一样,不过该方法不会往浏览器的历史记录添加记录

查看push源码时我们就提到replace方法也包含其中,而replace的底层API就是History.replaceState()。如果我们在用push导航时将replace属性设置为true,结果跟直接调用replace方法一样。

js 复制代码
   router.push({ name: 'login', replace:true })
   router.replace({ path: '/login' })

go方法

router.go(n):将路由前进或后退到第n条记录,n为整数,正数表示前进;负数表示后退。浏览器中前进按钮就相当于router.go(1),后退就相当于router.go(-1)。通过push与replace方法我们可以猜到router.go用到的API就是history.go()

例子:

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

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

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

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

源码:

js 复制代码
  back(): ReturnType<Router['go']>
  /**
   * Go forward in history if possible by calling `history.forward()`.
   * Equivalent to `router.go(1)`.
   */
  forward(): ReturnType<Router['go']>
  /**
   * Allows you to move forward or backward through the history. Calls
   * `history.go()`.
   *
   * @param delta - The position in the history to which you want to move,
   * relative to the current page
   */
  go(delta: number): void

  /**
   * Add a navigation guard that executes before any navigation. Returns a
   * function that removes the registered guard.
   *
   * @param guard - navigation guard to add
   */
相关推荐
恋猫de小郭8 小时前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
崔庆才丨静觅15 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606116 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了16 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅16 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅16 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅16 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment17 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅17 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊17 小时前
jwt介绍
前端