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
   */
相关推荐
软件技术NINI3 分钟前
html知识点框架
前端·html
深情废杨杨7 分钟前
前端vue-插值表达式和v-html的区别
前端·javascript·vue.js
GHUIJS7 分钟前
【vue3】vue3.3新特性真香
前端·javascript·vue.js
众生回避13 分钟前
鸿蒙ms参考
前端·javascript·vue.js
洛千陨14 分钟前
Vue + element-ui实现动态表单项以及动态校验规则
前端·vue.js
GHUIJS1 小时前
【vue3】vue3.5
前端·javascript·vue.js
&白帝&2 小时前
uniapp中使用picker-view选择时间
前端·uni-app
魔术师卡颂2 小时前
如何让“学源码”变得轻松、有意义
前端·面试·源码
谢尔登2 小时前
Babel
前端·react.js·node.js
ling1s2 小时前
C#基础(13)结构体
前端·c#