油老师

covercover

文章短代码在 Vue 中如何实现?

之前我在使用 Gridea 的时候由于没有 “文章短代码” 功能,但我又想在文章中添加音乐播放器、添加视频等等。考虑到 Markdown 的特性是支持插入 HTML ,我将 <div class="功能" data-*="字段"></div> 作为短代码,这样的好处是即使页面渲染时没有执行 JS 代码,也可以保证我的文章内容不会凭空多出一段莫名的 短代码

所以自己就在 “自定义 JS” 里写了一段,大概就是当页面加载完成时,遍历所有 div.class,相应功能做相应处理即可。

在去年我和苏米乐聊过这个话题,当时他是要做在博客上的,我给他提供了这个思路。后面我们找到另外一种解决方式:MDX。MDX 是 Markdown 的超集,可以在写 Markdown 的同时,导入 React 组件,后面苏米乐同学就用这个思路开发了一版。

因为最近一直在做主题,而 MDX 并不满足能在 Typecho 的场景下使用,而且我是在 Vue3 环境下开发的,所以我需要另寻方式。

一般在获取 Markdown 之后,我们会先解析成 html 代码,再用 v-html 将代码输出

在这个思路下,其实用我最上面说的 div.class 方式写一段页面加载完成后的代码即可。但是这样会失去使用 Vue 的便利。于是我想到可以使用文本模板的方式,创建一个 Vue 组件

这样的话,我们只需要在 Markdown 解析后,将 html 代码定义为 Vue 组件即可,示例如下:

<template>
  <div>
    <Cpt :key="renderTime" />
    <br />
    <a-button @click="handleChange">切换内容</a-button>
  </div>
</template>

<script setup lang="ts">
import { Button } from '@arco-design/web-vue';
import { computed, defineComponent, ref } from 'vue';
import Test from './Test.vue';

// html 代码
const html = ref(`
<a-button>html 按钮</a-button>
<br>
<Test msg="哈哈哈" />
`)
// 渲染时间
const renderTime = ref(new Date().getTime())

// 定义组件
const Cpt = computed(() => defineComponent({
  name: 'Cpt',
  template: html.value,
  components: {
    AButton: Button,
    Test: Test,
  },
}))

// 切换组件内容
const handleChange = () => {
  html.value = `
<Test msg="不是" />
<br>
<a-button>html 按钮</a-button>
  `
  renderTime.value = new Date().getTime()
}

</script>

在上述代码中,定义一个 html 变量作为 Markdown 解析后的代码,再定义一个渲染时间作为自定义组件的 key(关于为什么要使用 key,请查看这篇文章),最后使用计算属性来定义组件(保证切换组件内容功能)。

通过这个方式,我们可以在 defineComponent 时,将预定义的组件在 components 字段中传入,就可以实现我们想要的功能。

另外这个方式需要将 Vue 全量打包,通常打包时只会打包 runtime,是不带模板编译器的

评论

Copyright © 2014 - 2025 油老师.