vue-router 如何从父路由继承 props

How to inherit props from parent route with vue-router

我有以下路由器配置,希望将 main.parent 路由的 id 转换为整数,然后传递给子组件(给定 props: true)所有子组件。

{
  path: '/',
  component: GrandparentComponent,
  name: 'main',
  children: [{
    path: ':id',
    component: ParentComponent,
    name: 'main.parent',
    props: route => {
      return {
        // parse URL id to int
        id: parseInt(route.params.id, 10)
      };
    },

    children: [{
      path: 'details',
      name: 'main.parent.child',
      component: ChildComponent,
      props: true,
      children: [{
        ...
      }]
    }]
  }]
}

然而,似乎 route function 只真正被调用一次(在评估 /:id 时)而不是在评估 /:id/details 时。 vue-router中的相关代码似乎证实了这一点。

            const route = routeToDisplay.value;
            const matchedRoute = matchedRouteRef.value;
            const ViewComponent = matchedRoute && matchedRoute.components[props.name];
            // we need the value at the time we render because when we unmount, we
            // navigated to a different location so the value is different
            const currentName = props.name;
            if (!ViewComponent) {
                return normalizeSlot(slots.default, { Component: ViewComponent, route });
            }
            // props from route configuration
            const routePropsOption = matchedRoute.props[props.name];
            const routeProps = routePropsOption
                ? routePropsOption === true
                    ? route.params
                    : typeof routePropsOption === 'function'
                        ? routePropsOption(route)
                        : routePropsOption
                : null;
            ...
            const component = h(ViewComponent, assign({}, routeProps, attrs, {
                onVnodeUnmounted,
                ref: viewRef,
            }));
            ...

我想知道是否有人试图解决同样的问题以及他们想出了什么解决方案。理想情况下,我想避免为每个子路由重复 props 函数。

Vue Router 中没有这样的功能,可以通过这种方式将 props 传递给 child 路由。

相反,您可以使用 provide/inject 来有效地做到这一点。 parent 将 provide id 属性,任何后代都可以 inject 它:

  1. ParentComponent.vue 中,在 props 上使用 toRefs() 以获得对 id 道具的反应 ref
  2. 使用provide()为任何children(包括child路线)提供id
  3. <router-view> 上应用 key 以确保视图是 re-rendered 基于唯一 id.
  4. ChildComponent.vue 中,使用 inject 属性注入步骤 2 中的 id
// ParentComponent.vue
<script>
/* Composition API */
import { provide, toRefs } from 'vue'

export default {
  props: ['id'],
  setup(props) {
    const { id } = toRefs(props)
    provide('id', id)
  },
}

/* Options API */
import { toRefs } from 'vue'

export default {
  props: ['id'],
  provide() {
    const { id } = toRefs(this.$props)
    return { id }
  },
}
</script>

<template>
  <router-view :key="id" />
</template>
// ChildComponent.vue
<script>
export default {
  inject: ['id'],
}
</script>

<template>
  <h2>Detail {{ id }}</h2>
</template>

Composition API demo

Options API demo

TL;DR See working demo


我不太明白你在问什么,但我对你的问题的理解是这样的:

  1. route 函数是否只在父组件上调用一次而不在子组件上调用?
  2. 如何不为每个子路由重复 props 函数代码
  3. 如何从父组件继承 props

1:不会,路由函数会在每个子路由上调用。

2:抽象函数代码

您可以创建一个函数并使用它,而不是 copy-pasting 或重复函数代码:

const parseUrlIdtoInt = (route) => ({ id: parseInt(route.params.id, 10) });

// ...
{
  path: '...'
  props: parseUrlIdtoInt,
  children: [
    {
      path: '...',
      props: parseUrlIdtoInt 
    }
  ] 
}
//...

3: Vue router 向下传递 props

如果在路由器配置中指定了 props 属性,那么 Vue Router 会自动传递 props。

- 使用 props 选项,我们可以将 props 传递给组件 - 使用函数 props 我们可以控制传递什么 prop 的方式

// Router configuration
{
  path: '...',
  name: '...',
  props: true // or a function 
  // ...
}

你的解决方案

因此,为了在您的 ChildComponent 中访问 id 道具,您可以定义道具并使用它:

作文API

<script setup>
defineProps({ id: Number });
</script>

选项API

<script>
import { defineComponent } from 'vue';

export default defineComponent({
  props: {
    id: Number,
  },
});
</script>

其他non-so-recommended 解决方案

  • 如果你不想定义道具,你可以在模板中使用$attrs.id访问id。
  • 或者您可以使用 Vue Router 中的 useRoute() 函数并访问参数:
<script setup>
import { useRoute } from 'vue-router'

const route = useRoute()
</script>

<template>
 {{ route.params.id }}
</template>