无头WordPress+Nuxt:拆分HTML与Shortcode为对象数组方案咨询
解决方案:用正则拆分内容 + 动态组件渲染
对于结构简单的WordPress短代码(shortcode),正则是当前场景下的最优方案——轻量、无额外依赖,完全适配你的需求,没必要引入复杂的HTML解析库。下面是具体实现步骤:
1. 编写正则与内容拆分函数
先写一个能匹配短代码的正则,覆盖自闭合([my-shortcode attr="val"])和闭合式([my-shortcode]内部内容[/my-shortcode])两种简单结构,再通过循环将HTML内容拆分为目标数组:
function parseContentWithShortcodes(htmlContent) { const parts = []; // 匹配短代码的正则:捕获标签名、属性、内部内容(可选),忽略大小写 const shortcodeRegex = /\[([a-zA-Z0-9_-]+)(?:\s+([a-zA-Z0-9_-]+="[^"]*")*)*\s*\](.*?)(?:\[\/\1\])?/gsi; let lastIndex = 0; let match; while ((match = shortcodeRegex.exec(htmlContent)) !== null) { // 提取短代码之前的普通HTML内容 if (match.index > lastIndex) { parts.push({ type: 'html', content: htmlContent.slice(lastIndex, match.index) }); } const [_, tagName, attrStr, innerContent] = match; // 解析短代码的属性键值对 const attrs = {}; if (attrStr) { const attrMatchRegex = /([a-zA-Z0-9_-]+)="([^"]*)"/g; let attrMatch; while ((attrMatch = attrMatchRegex.exec(attrStr)) !== null) { attrs[attrMatch[1]] = attrMatch[2]; } } // 推入短代码对象 parts.push({ type: 'shortcode', content: { tag: tagName, // 短代码标签名,对应Vue组件名 attrs, inner: innerContent || '' } }); lastIndex = shortcodeRegex.lastIndex; } // 处理剩余的HTML内容 if (lastIndex < htmlContent.length) { parts.push({ type: 'html', content: htmlContent.slice(lastIndex) }); } return parts; }
2. 在Nuxt组件中渲染拆分后的内容
将拆分后的数组循环渲染,普通HTML用v-html输出,短代码用Vue动态组件匹配对应组件:
<template> <div class="article-content"> <template v-for="(item, idx) in parsedContent" :key="idx"> <!-- 渲染普通HTML --> <span v-if="item.type === 'html'" v-html="item.content"></span> <!-- 渲染短代码对应的Vue组件 --> <component v-else :is="resolveComponent(item.content.tag)" v-bind="item.content.attrs" > {{ item.content.inner }} </component> </template> </div> </template> <script setup> import { computed } from 'vue'; // 导入你的短代码组件,或者用Nuxt自动组件导入 import ProductCard from './components/ProductCard.vue'; import BannerBox from './components/BannerBox.vue'; const props = defineProps({ rawContent: { type: String, required: true } }); // 注册组件,确保短代码标签名与组件名对应(支持kebab-case) const components = { 'product-card': ProductCard, 'banner-box': BannerBox }; // 解析内容为目标数组 const parsedContent = computed(() => { return parseContentWithShortcodes(props.rawContent); }); // 匹配组件(处理标签名大小写/格式问题) const resolveComponent = (tag) => { return components[tag.toLowerCase()] || 'span'; // 找不到组件时用span兜底 }; </script>
关键注意事项
- 正则可按需调整:如果不需要支持闭合式短代码,去掉
(.*?)(?:\[\/\1\])?部分即可;如果属性不需要引号,修改属性匹配规则。 - 组件名要对应:WordPress短代码是
[product-card],Vue组件就注册为product-card,Vue原生支持kebab-case组件名。 - 性能优化:如果文章内容不会频繁变更,可把解析后的结果缓存到Vuex/Pinia或localStorage,避免重复执行正则解析。
- 边界处理:给无法匹配的短代码设置兜底组件(比如示例中的
span),避免渲染异常。
内容的提问来源于stack exchange,提问作者AndyJamesN
相关产品推荐
相关产品推荐

