0

我在将动态生成的布局与命名插槽结合起来时遇到问题。

要定义我的布局,我使用“组件: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' 不是。

在此处输入图像描述

和控制台显示此错误

<\template v-slot> 只能出现在接收组件内部的根级别

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

模板根只需要一个元素。

我做错了什么?

4

1 回答 1

2

这并不容易解释,所以请与我相处......

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

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

但是您正在尝试使用插槽,就好像它们在运行时是“可发现的”一样。为了让您的代码正常工作,动态布局组件必须在运行时以某种方式发现它是子组件(由于 也是动态的<router-view />)有一些可以使用的插槽内容。这不是 Vue 中插槽的工作方式。您可以将组件从父组件接收到的插槽内容传递给子组件,但不要期望父组件(在这种情况下为布局)可以“发现”在其子组件中定义的插槽内容......

不幸的是,解决您的问题的唯一方法是在每个“页面”中导入布局组件并将其用作模板中的根元素。您可以使用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>
于 2021-04-04T12:04:07.017 回答