Skip to content

Markdown 中的 Vue3 WebComponent

之前尝试了将 Markdown 文档渲染为 Vue3 组件来实现在 Markdown 中使用 Vue3 语法,但同时也遇到了我解决不了的问题,这次是对 Vue3 defineCustomElement() 方法定义 WebComponent 原生 HTML 标签的方式来尝试实现同样的功能。

Vue3 新版中文 API 文档
https://staging-cn.vuejs.org/api/general.html#definecustomelement

网上的博文基本都是在照抄官方文档,我翻了一圈下来基本没有额外收获,此处官方文档提供的内容已足够理解。

defineComponent() 和 defineCustomElement() 接收的参数相同,即可以传入一个对象

js
defineCustomElement({
  template: `<h1>{{title}}</h1>`,
  data() {
    return {
      title: "hello world",
    };
  },
});
// 或者
defineCustomElement({
  data() {
    return {
      title: "hello world",
    };
  },
  render: () => h("h1", [title]),
});

还可以传入一个 setup 函数

js
defineCustomElement(()=>{
  const title = ref('hello world')
  return () => h("h1", [title]),
});

定义完组件之后需要使用原生方法 customElements.define() 来对组件进行注册

js
// 第一个参数为自定义标签名
// 第二个参数为 defineCustomElement() 方法生成的组件实例
customElements.define("my-vue-element", MyVueElement);

也可用 SFC 单文件的方式来声明组件,开启此功能需要文件名以 .ce.vue 结尾,贴出官方文档的示例代码

js
import { defineCustomElement } from "vue";
import Example from "./Example.ce.vue";

// 转换为自定义元素构造器
const ExampleElement = defineCustomElement(Example);

// 注册
customElements.define("my-example", ExampleElement);

可以通过修改构建工具的配置文件来开启将所有 SFC 视为自定义标签,在组件比较多的情况下可以通过构建工具的批量导入功能进行集中注册

集中注册代码示例(非批量导入):

js
import { defineCustomElement } from "vue";
import MyFoo from "./MyFoo.ce.vue";
import MyBar from "./MyBar.ce.vue";

export default function () {
  customElements.define("my-foo", defineCustomElement(MyFoo));
  customElements.define("my-bar", defineCustomElement(MyBar));
}

关于 Props,官方文档中说明了 DOM attribute 只能为字符串值,需要传复杂数据时,需要用以下方式

html
<my-element :user.prop="{ name: 'jack' }"></my-element>

<!-- 等价简写 -->
<my-element .user="{ name: 'jack' }"></my-element>

但是经过实测,这种方式只在 Vue3 组件中使用时可以成功过传递

在 v-html 渲染的 markdown 中,只能接受到字符串类型的值,使用上面的方法传递复杂类型时,接收到的 props 均为 undefined。且使用简写时,html 不再正常渲染,直接显示为不完整的 innerText,原因不明

宣告失败,作此纪录

Release time: 6/4/2022, 11:15:00

Last updated:

⟣ Growing, with you. ⟢