我正在尝试替换来自 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]
。提前致谢!
好的,所以问题来自于这一行:
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。
如果您只有简单且不复杂的组件,例如
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',...)
查看演示
v-html 只能处理简单的 HTML。 我假设您的组件已经存在并且它用于所有常见问题解答。如果每次通话有不同的常见问题解答,您可以将它们作为道具传递。
因此,如果您的组件已经存在,只需导入它并将其包含在 v-html 之后的模板中,并使用 v-if 指令,如果 props.data.text 包含“[faq]”,您可以设置该指令。您可以将“[faq]”替换为空白。
如果必须动态加载组件,则需要使用带有 v-bind:is="YourComponent" 的 Vue“组件”以将其包含在模板中。