/** * {yz:xxx} 站点标签指令(dedecms 风格) * * 用法:在模板里直接写标签,元素加 v-yz 即可 *

{yz:icp}

*

备案号:{yz:icp} | {yz:policeicp}

* * 元素内所有 {yz:标签名} 会被替换为「官网管理 - 站点设置」中对应的值, * 未配置的标签输出空字符串(与后端 themes 模板行为一致)。 * * 注意:指令通过 innerHTML 替换内容,因此元素内只能放纯文本/HTML 片段, * 不要放子组件或需要响应式绑定的内容;需要条件渲染的地方请用 siteInfo.xxx。 */ import { watchEffect, type Directive } from "vue"; import { siteTags } from "@/config/site"; /** 与后端 tagengine 的全局标签正则保持一致 */ const TAG_PATTERN = /\{yz:([a-zA-Z_]\w*)\}/g; /** 每个元素对应的 watchEffect 停止函数 */ const stops = new WeakMap void>(); /** 依据当前标签值渲染元素内容;始终基于首次保存的原文,避免重复替换 */ function render(el: HTMLElement): void { if (!el.dataset.yzRaw) { el.dataset.yzRaw = el.innerHTML; } const raw = el.dataset.yzRaw; el.innerHTML = raw.replace( TAG_PATTERN, (_match: string, key: string) => siteTags[key] ?? "" ); } export const yz: Directive = { mounted(el) { // watchEffect 会追踪 render 中读取到的标签值; // 站点设置是异步拉取的,数据到位后会自动重新渲染 stops.set(el, watchEffect(() => render(el))); }, unmounted(el) { stops.get(el)?.(); stops.delete(el); }, }; export default yz;