Vue 3resolveComponent 返回 [object Object]

问题描述 投票:0回答:3

我正在尝试替换来自 REST API 的 (WordPress) 短代码字符串。
现在我想用名为“FAqItem”的 Vue 3 组件替换“[faq]”。
为此,我使用函数resolveComponent()。

REST API 数据:

{
  "flow": "col",
  "subtitle": "Programma",
  "title": "Wat ga je doen?",
  "text": "Test\r\n\r\n[faq]"
}

这是我的代码:

const html = ref(props.data.text)
const FaqItem = resolveComponent('FaqItem')
if (html.value.includes('[faq]')) {
    html.value = html.value.replace('[faq]', FaqItem);
}

然后在我的模板中我使用:

<div class="block prose xl:mt-12" v-html="html"></div>

现在这似乎有效,但替换函数正在返回

[object Object]

我怎样才能让它显示我的组件本身? 重要的是只替换[常见问题解答]。

提前致谢!

javascript vuejs3 shortcode
3个回答
1
投票

好的,所以问题来自于这一行:

html.value = html.value.replace('[faq]', FaqItem);

FaqItem
变量包含一个对象,然后将其插入到字符串中。所以 JS 对它调用
.toString()
,返回
[object Object]

使用模板语法(即

<FaqItem />
)也不起作用,因为
v-html
只处理纯 HTML。

不确定是不是只有我一个人这么认为,但我认为 Vue 并不真的希望你做那样的事情。因此,如果有办法避免它,那就是您最好的选择。

但是,可以选择编译和插入模板(这意味着如果您搜索网络,您可能会找到更好的模板)。一种是将

h()
与临时组件一起使用:

<script lang="ts" setup>
  import { h } from 'vue';

  const myTemplateRenderer = () => {
    const myTemplate = 'asdf <FaqItem /> asdf'
    return h({template: myTemplate, components: {FaqItem} });
  };

</script>
<template>

  <myTemplateRenderer />

</template>

还有像 vue3-runtime-template 这样的插件您可以使用。

请注意,这意味着您的生产构建需要包含模板编译器,这将使您的构建大小增加约 80kB/30kB gzipped。


1
投票

如果您只有简单且不复杂的组件,例如

v-for
v-slot
,则不需要编译器可执行文件:

import { openBlock, createElementBlock, Fragment, createVNode, createElementVNode, toDisplayString, createTextVNode} from 'vue'

/// your code

const html = ref(props.data.text)
const FaqItem = resolveComponent('FaqItem')

const Result = {
    setup() {
      return (_ctx, _cache) => {
        
        const indexFaq = html.value.indexOf("[faq]")
        
        if (indexFaq === -1)
            return toDisplayString(msg)
        
        openBlock()
        return createElementBlock(Fragment, null, [
          createTextVNode(html.value.slice(0, indexFaq), 1),
          createVNode(FaqItem),
          createTextVNode(html.value.slice(indexFaq + 5), 1)
        ], 64 /* STABLE_FRAGMENT */ )
      }
    }
}

<div class="block prose xl:mt-12">
  <Result />
</div>

这里有一个使用

low api
的方法,可以让你在不增加编译包大小和降低性能的情况下解决问题,正如@MoritzRingler建议的那样

无论如何,对于正常应用程序来说,这不会增加任何大小,不用担心输入,因为如果您使用 vue 组件(片段、文本),它总是会导入

如果你不喜欢

Fragment
你可以使用
createElementBlock('div',...)

查看演示


0
投票

v-html 只能处理简单的 HTML。 我假设您的组件已经存在并且它用于所有常见问题解答。如果每次通话有不同的常见问题解答,您可以将它们作为道具传递。

因此,如果您的组件已经存在,只需导入它并将其包含在 v-html 之后的模板中,并使用 v-if 指令,如果 props.data.text 包含“[faq]”,您可以设置该指令。您可以将“[faq]”替换为空白。

如果必须动态加载组件,则需要使用带有 v-bind:is="YourComponent" 的 Vue“组件”以将其包含在模板中。

© www.soinside.com 2019 - 2024. All rights reserved.