1. 问题说明

一般来说,要渲染 HTML 内容我们用 v-html 指令传递内容就可以了:

<div v-html="<p>段落</p>"></div>

如果这里不是一个 div 标签,而是一个自定义组件:

<CustomElement v-html="<p>段落</p>"></CustomElement>

在服务端渲染(SSR)时,HTML 内容是不会被渲染出来的。

然而有时候还真有这样的应用场景,比如在展示文章内容时,我们经常会自定义其展示样式,用 JavaScript 处理代码块的一键复制等。将内容放到自定义组件中统一处理显然是个不错的选择。怎么实现呢?

2. 解决方案

既然 v-html 作用在自定义组件上有问题,我们通过 props 传递即可:

Typography.vue

<template>
    <div v-if="htmlContent" v-bind="$attrs" v-html="html"></div>
    <div v-else v-bind="$attrs">
        <slot></slot>
    </div>
</template>

<script setup>
defineOptions({
    inheritAttrs: false
});

const props = defineProps({
    html: String
});
</script>

有两种使用方式:

在 Vue 组件中,通过插槽传递内容:

<Typography>
    <p>段落</p>
<Typography>

对于博客、CMS 等存储在数据库中的 HTML 内容,通过 props 传递内容:

<Typography html="<p>段落</p>" />