繁体   English   中英

将 Vue 3 组件渲染为 HTML 字符串

[英]Rendering Vue 3 component into HTML string

我正在开发一个 vue.js 项目(版本 3)。 我遇到了一种情况,我想将组件的渲染 HTML 视图用于当前组件的方法。

我在我的 Vue 项目中创建了以下 SVG 组件。

CircleWithTextSvg.vue

<template>
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" width="20" height="20">
        <g id="UrTavla">
            <circle cx="10" cy="10" r="10" stroke="gray" stroke-width="1" :fill="fill" />
            <text x="50%" y="50%" text-anchor="middle" stroke="black" stroke-width="1px" dy=".3em">{{text}}</text>
        </g>
    </svg>
</template>

<script>
    export default {
        props: {
            text: { 
                type: String, 
                default: "1"
            },
            fill: { 
                type: String, 
                default: "white"
            }
        }
    }
</script>

该组件基本上呈现一个带有文本的圆圈。 如果我在我的主要组件的模板部分使用这个组件,如下所示,那么它工作正常(显然)

主组件.vue

<template>
    <circle-with-text-svg />
</template>

但我想将此 SVG 组件渲染输出作为选项发送给第三方。

实际用例:-实际上,我创建了这个单独的组件以在我的传单地图上显示为标记。 现在的问题是我想在 MainComponent 的方法中使用这个 SVG 组件,这样我就可以将它用作 L.divIcon 的一个选项

当我尝试以下

export default {
    methods: {
        generateMap(element) {
            // ...
            let icon = L.divIcon({ 
                html: <circle-with-text-svg 
                    fill="'#D3D5FF'"
                    text="1" />, 
                iconSize: [10, 10]
            });
            // ...
        }
    }
}

然后它给出了错误

支持实验性语法“JSX 当前未启用”

在react中,我们可以正常使用另一个组件的模板内部的组件。 但是我们如何在 vue.js 中实现这一点

通过查看错误,似乎未启用 JSX 实验性。

有人可以解决我如何实现这一目标?

好的,所以在评论中,我推荐了问题的答案如何在 vuejs 中获取组件的已编译 html 内容,该内容实际上是为 Vue 2 实现的

我很好奇这是否适用于 Vue 3,你可以在下面看到结果。 以下是所需的更改:

  1. 明显的变化是用createApp替换new Vue并使用全局 h()而不是传递给render()
  2. 在 Vue 2 中,您可以不带参数调用主 Vue 实例的$mount()函数。 之所以有效,是因为 Vue 创建了要挂载到内存中的 DOM 元素。 在 Vue 3 中不是这种情况——你需要自己提供元素
  3. 在我的示例中没有使用对某些用例非常重要的一项重大更改是,在使用app.component()在主应用程序实例中注册为全局的 Vue 3 组件在用于呈现 HTML 的tempApp中无法访问。 使用中的所有组件都必须在适当的实例中注册 - 请参阅迁移指南

 // We use component options object with string template // In the proper Vue app (with Webpack and Vue SFC) this whole block can be replaced with "import CircleWithTextSvg from CircleWithTextSvg.vue" const CircleWithTextSvg = { name: 'CircleWithTextSvg', props: { text: { type: String, default: "1" }, fill: { type: String, default: "white" } }, template: ` <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" width="20" height="20"> <g id="UrTavla"> <circle cx="10" cy="10" r="10" stroke="gray" stroke-width="1" :fill="fill" /> <text x="50%" y="50%" text-anchor="middle" stroke="black" stroke-width="1px" dy=".3em">{{text}}</text> </g> </svg> ` } const app = Vue.createApp({ mounted() { console.log(this.getIconHtml('Hello!')) }, methods: { getIconHtml(text, type) { const tempApp = Vue.createApp({ render() { return Vue.h(CircleWithTextSvg, { text, type }) } }) // in Vue 3 we need real element to mount to unlike in Vue 2 where mount() could be called without argument... const el = document.createElement('div'); const mountedApp = tempApp.mount(el) return mountedApp.$el.outerHTML } } }) app.mount('#app')
 <script src="https://unpkg.com/vue@3.1.4/dist/vue.global.js"></script> <div id='app'> </div>

注 1:上面的代码旨在直接在无法import的浏览器中运行。 出于这个原因,我们使用 Vue 全局构建并使用例如Vue.createAppVue.h访问 Vue 全局 API。 在常规 Vue 应用程序中,您需要将这些函数import { createApp, h } from 'Vue'import { createApp, h } from 'Vue'

注 2:可以说,如果与 Leaflet 组件一起使用的 HTML 片段像您的CircleWithTextSvg组件一样简单,那么将它们定义为模板文字而不是 Vue 组件会更简单和CircleWithTextSvg

我尝试了上面的解决方案,但它并没有让我让步, $el.outerHTML感觉不对,并且由于我应用程序其余部分的生命周期而不断抛出 null 和 undefined 。 在 vue3 中我做到了。 它仍然感觉不对。 但是到达那里:)


const getIconHtml = (item, element) => render(h(CircleWithTextSvg, {
  onSomeEmit: (ev) => {
    
  },
  text: item, //props
}), element //element to render to
)

在我的问题中,我不得不为 3rd 方 js(visjs) 库返回一个模板

所以我如何使用它是这样的。

import {render, h} from 'vue';

const itemTemplate = async (item, element) => render(h(bar, {
  onDelete: (ev) => {
    vis.removeItem(item.id)
  },
  item: item,
}), element
)

//note this template key does not refer to vuejs template
  template: (item, element) => {
    if (!item) return;
    return itemTemplate(item, element);
  }


使用这种方法需要考虑的事情。 这在技术上创建了一个新的 vue 实例,因此您想要使用的任何其他应用程序、道具、组件、指令,您可能需要手动注册到此组件。 一些全局变量可能会起作用,但由于一些deep问题,我在获取指令时遇到了问题,

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM