/**
* {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;