【问题标题】:My dynamic component (layout) doesn't work with named slots in vuejs我的动态组件(布局)不适用于 vuejs 中的命名插槽
【发布时间】:2021-06-30 12:02:27
【问题描述】:

我无法将动态生成的布局与命名槽结合起来。

为了定义我的布局,我使用“component :is”

//app.vue
<template>
  <component :is="layout">
   <router-view />
  </component>
</template>
<script>
  computed: {
    layout() {
      const layout = this.$route.meta.layout || 'default'
      return () => import(`@/app/layouts/${layout}.vue`)
    }
  },
</script>
//layouts/default.vue
<template>
  <div>
    <div>
      <slot name="header" />
    </div>
    <div>
      <div>
        <slot name="sidebar" />
       </div>
       <div>
         <slot name="default"/>
       </div>
    </div>
  </div>
</template>
// views/page.vue
<template>
  <div>
    <template #header>
      <h1>Primitives</h1>
    </template>
    <template #sidebar>
      <ul>
        <li v-for="primitive in sections.sections" :key="primitive">
          <router-link :to="`/primitives/${primitive}`">{{primitive}}</router-link>
        </li>
      </ul>
    </template>
    <template #default>
      <router-view :key="$router.path" />
    </template>
  </div>
</template>

但现在我的代码中出现了这个错误

'v-slot' 指令必须由自定义元素拥有,但 'div' 不是。

控制台显示此错误

只能出现在接收组件内部的根级别

如果我删除主 div 我会收到错误

模板根只需要一个元素。

我做错了什么?

【问题讨论】:

  • 你使用的是哪个版本的 Vue?
  • 我使用的是 V2.6。

标签: vue.js layout named v-slot


【解决方案1】:

这不好解释,请多多包涵……

我真的理解你想要做什么,但不幸的是,在 Vue 中这是不可能的。

原因是插槽比 Vue 的 运行时功能 具有更多 模板编译器 功能。我的意思是什么?当 Vue 模板编译器看到类似 &lt;template #header&gt; 的内容时,它会获取内部内容并将其编译为返回虚拟 DOM 元素的函数。这个函数必须传递给某个组件,该组件可以调用它并将结果包含在它自己生成的虚拟 DOM 中。要做到这一点,模板编译器需要知道它应该将函数传递给哪个组件(这是'v-slot' directive must be owned by a custom element, but 'div' is not. 错误消息的真正含义......即编译器正在“寻找”一个组件将插槽内容传递给......)

但是您尝试使用插槽,就好像它们在运行时是“可发现的”一样。为了让您的代码正常工作,动态布局组件必须在运行时以某种方式发现它的子组件(感谢&lt;router-view /&gt; 也是动态的)有一些可以使用的插槽内容。这不是 Vue 中插槽的工作方式。您可以pass the slot content your component receives from parent to a child components,但不要期望父组件(在这种情况下为布局)可以“发现”其子组件中定义的插槽内容...

不幸的是,解决您的问题的唯一方法是在每个“页面”中导入布局组件并将其用作模板中的根元素。您可以使用mixins 来减少代码重复(定义layout 计算)

@/mixins/withLayout.js

export default = {
  computed: {
    layout() {
      const layout = this.$route.meta.layout || 'default'
      return () => import(`@/app/layouts/${layout}.vue`)
    }
  }
}

views/page.vue

<template>
  <component :is="layout">
    <template #header>
      <h1>Primitives</h1>
    </template>
    <template #sidebar>
      <ul>
        <li v-for="primitive in sections.sections" :key="primitive">
          <router-link :to="`/primitives/${primitive}`">{{primitive}}</router-link>
        </li>
      </ul>
    </template>
    <template #default>
      <router-view :key="$router.path" />
    </template> 
  </component>
</template>
<script>
import withLayout from '@/mixins/withLayout'

export default {
  mixins: [withLayout]
}
</script>

【讨论】:

  • 好的,我明白了。这与 vue3 可能吗?因为你问我使用的是哪个版本。
  • 没有。我的第一个想法是,由于模板中可能有多个根节点,因此在 Vue 3 中可能是可能的,但后来我意识到这是另一个问题(在我的回答中描述)
  • 好的,导入我的“布局”,将其添加到“组件:{布局}”并在我的页面中使用它作为我的根元素的作品。但是“定义计算布局”是什么意思,我为什么需要它?
  • 添加了一些代码...未经测试但应该可以工作;)
  • 但这当然只是一个练习。如果您直接在每个页面中使用布局组件,那么仅使用静态导入并在页面中使用选定的布局组件会更加容易和可读...
猜你喜欢
  • 1970-01-01
  • 2019-10-07
  • 2021-06-21
  • 2019-12-01
  • 1970-01-01
  • 2019-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多