Files
yunzerwebsiteallinone/website/src/directives/yz.ts
T
2026-09-15 00:08:36 +08:00

49 lines
1.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* {yz:xxx} 站点标签指令(dedecms 风格)
*
* 用法:在模板里直接写标签,元素加 v-yz 即可
* <p v-yz>{yz:icp}</p>
* <p v-yz>备案号:{yz:icp} | {yz:policeicp}</p>
*
* 元素内所有 {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<HTMLElement, () => 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<HTMLElement> = {
mounted(el) {
// watchEffect 会追踪 render 中读取到的标签值;
// 站点设置是异步拉取的,数据到位后会自动重新渲染
stops.set(el, watchEffect(() => render(el)));
},
unmounted(el) {
stops.get(el)?.();
stops.delete(el);
},
};
export default yz;