在另一个组件中动态渲染Vue组件

mtb9vblg  于 2023-02-09  发布在  Vue.js
关注(0)|答案(3)|浏览(195)

使用Vue 3.2.41-英雄图标/版本2.0.14-惯性1.0-版本4.0.0
我使用以下代码调用Vue组件:
<TimelineItem icon="CalendarDaysIcon" />
该组件如下所示:

<template>
    <component :is="icon" /> <!-- doesn't work -->
    <CalendarDaysIcon /> <!-- works -->
</template>

<script setup>
    import {
        CalendarDaysIcon,
    } from '@heroicons/vue/20/solid'

    const props = defineProps(['icon'])
</script>

呈现的HTML如下所示:

<calendardaysicon></calendardaysicon> <!-- not what I want -->
<svg> ... </svg> <!-- correct but not dynamic -->

换句话说,<component :is />只是渲染了一些空的<calendardaysicon>标记,而我希望它渲染组件。我可以看到它将其变为小写,不知道如何强制它返回PascalCase,我甚至不确定这是否会对情况有所帮助。
我已经简化了一些代码,但完整版本将有一个10个不同的图标列表(所有的英雄包使用PascalCase名称的一部分),我希望能够轻松地从主组件调用。

nkhmeac6

nkhmeac61#

如果您直接在DOM中创作模板(例如,作为本地元素的内容),则模板将受浏览器的本地HTML解析行为的影响。在这种情况下,您需要对组件www.example.com使用kebab-case和显式结束标记https://vuejs.org/guide/essentials/component-basics.html#dom-template-parsing-caveats
尝试:<calendar-days-icon> </calendar-days-icon>

irlmq6kh

irlmq6kh2#

const { createApp, createElementVNode, openBlock, createElementBlock } = Vue;

const CalendarDaysIcon = {  
  render(_ctx, _cache) {
  return (openBlock(), createElementBlock("svg", {
    xmlns: "http://www.w3.org/2000/svg",
    viewBox: "0 0 20 20",
    fill: "currentColor",
    "aria-hidden": "true"
  }, [
    createElementVNode("path", { d: "M5.25 12a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H6a.75.75 0 01-.75-.75V12zM6 13.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V14a.75.75 0 00-.75-.75H6zM7.25 12a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H8a.75.75 0 01-.75-.75V12zM8 13.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V14a.75.75 0 00-.75-.75H8zM9.25 10a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H10a.75.75 0 01-.75-.75V10zM10 11.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V12a.75.75 0 00-.75-.75H10zM9.25 14a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H10a.75.75 0 01-.75-.75V14zM12 9.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V10a.75.75 0 00-.75-.75H12zM11.25 12a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H12a.75.75 0 01-.75-.75V12zM12 13.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V14a.75.75 0 00-.75-.75H12zM13.25 10a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H14a.75.75 0 01-.75-.75V10zM14 11.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V12a.75.75 0 00-.75-.75H14z" }),
    createElementVNode("path", {
      "fill-rule": "evenodd",
      d: "M5.75 2a.75.75 0 01.75.75V4h7V2.75a.75.75 0 011.5 0V4h.25A2.75 2.75 0 0118 6.75v8.5A2.75 2.75 0 0115.25 18H4.75A2.75 2.75 0 012 15.25v-8.5A2.75 2.75 0 014.75 4H5V2.75A.75.75 0 015.75 2zm-1 5.5c-.69 0-1.25.56-1.25 1.25v6.5c0 .69.56 1.25 1.25 1.25h10.5c.69 0 1.25-.56 1.25-1.25v-6.5c0-.69-.56-1.25-1.25-1.25H4.75z",
      "clip-rule": "evenodd"
    })
  ]))
}
}

const TimeLineItem = {   
  props: ['icon'],
  components: {
    CalendarDaysIcon
  },
  template: '<component :is="icon" class="icon"/>'
}

const App = {
  components: { 
    TimeLineItem
  } 
}

const app = createApp(App)
app.mount('#app')
.icon {
    width: 36px;
    height: 36px;
}
<div id="app">  
  <time-line-item icon="CalendarDaysIcon"></time-line-item>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
xu3bshqb

xu3bshqb3#

使用<component :is="icon" />只是使用包含CalendarDaysIcon的字符串
相反,在主组件中,按如下方式传递实际组件引用:

<template>
  <TimelineItem :icon="CalendarDaysIcon" />
</template>

<script setup>
    import {
        CalendarDaysIcon,
    } from '@heroicons/vue/20/solid'

    const props = defineProps(['icon'])
</script>

然后,在TimelineItem组件中,不需要引用任何图标:

<template>
    <component :is="icon" /> <!-- now works -->
</template>

<script setup>
    const props = defineProps(['icon'])
</script>

感谢惯性失调服务器上的@Robert Boes提供的指导。

相关问题