v0.10.5 首页 H2 产品线入口 ×6:ImageBoxWidget 重构为 Elementor 忠实 DOM + slim 白名单补齐 + H2 scoped CSS(post-18 对齐,桌面/移动/hover 实测一致)
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* # 模块 Elementor 文档瘦身
|
||||
* WordPress 导入的 Elementor JSON 包含大量桌面/平板/移动端响应式字段与空值,
|
||||
* 整份文档会随 TanStack Router 脱水序列化进 SSR HTML(首页曾达 391KB),
|
||||
* 严重影响 SEO 与首字节体积。本模块只保留渲染器实际读取的字段。
|
||||
*/
|
||||
|
||||
/** # 成员变量 渲染器(Renderer.tsx)实际读取的 settings 字段白名单 **/
|
||||
const SETTING_KEYS = new Set([
|
||||
// 通用布局/背景/边框
|
||||
"__globals__",
|
||||
"align",
|
||||
"background_background",
|
||||
"background_color",
|
||||
"background_color_b",
|
||||
"background_color_stop_b",
|
||||
"background_image",
|
||||
"border_border",
|
||||
"border_color",
|
||||
"border_radius",
|
||||
"border_width",
|
||||
"content_width",
|
||||
"custom_height",
|
||||
"padding",
|
||||
"layout",
|
||||
"height",
|
||||
"size",
|
||||
"space",
|
||||
"color",
|
||||
"text_color",
|
||||
"title_color",
|
||||
"button_text_color",
|
||||
// image-box 系列:图定位(position 默认 top)与标题标签(title_size 默认 h3)
|
||||
"position",
|
||||
"title_size",
|
||||
"gradient_angle",
|
||||
"color_a",
|
||||
"color_b",
|
||||
"header_size",
|
||||
// 列结构
|
||||
"_column_size",
|
||||
"_inline_size",
|
||||
// 各 widget 数据
|
||||
"heading_title",
|
||||
"title",
|
||||
"title_text",
|
||||
"description",
|
||||
"description_text",
|
||||
"selected_icon",
|
||||
"url",
|
||||
"width",
|
||||
"text",
|
||||
"editor",
|
||||
"html",
|
||||
"source_code",
|
||||
"image",
|
||||
"link",
|
||||
"prefix",
|
||||
"suffix",
|
||||
"ending_number",
|
||||
"icon_list",
|
||||
"social_icon_list",
|
||||
"slides",
|
||||
"slides_height",
|
||||
"tabs",
|
||||
"video_url",
|
||||
"youtube_url",
|
||||
"map",
|
||||
"posts_per_page",
|
||||
"cards_posts_per_page",
|
||||
"post_type",
|
||||
"eael_ticker_tag_text",
|
||||
// EAEL Infobox / flip-box / 高级标签页 / 数据表 / 评价等(Renderer 对应组件读取)
|
||||
"custom_css",
|
||||
"_css_classes",
|
||||
"eael_infobox_title",
|
||||
"eael_infobox_text",
|
||||
"eael_infobox_title_tag",
|
||||
"title_text_a",
|
||||
"description_text_a",
|
||||
"button_text",
|
||||
"background_a_image",
|
||||
"eael_adv_tabs_tab",
|
||||
"eael_data_table_header_cols_data",
|
||||
"eael_data_table_content_rows",
|
||||
"eael_testimonial_name",
|
||||
"eael_testimonial_company_title",
|
||||
"eael_testimonial_description",
|
||||
]);
|
||||
|
||||
/** # 函数 收窄对象型 settings 值(渲染器只读 url/alt/target 等少数字段)
|
||||
* 参数 key settings 键名;val 原始值
|
||||
* 返回值 收窄后的值;非命中键原样返回
|
||||
*/
|
||||
function slimSettingValue(key: string, val: unknown): unknown {
|
||||
if (!val || typeof val !== "object" || Array.isArray(val)) return val;
|
||||
const v = val as Record<string, unknown>;
|
||||
if (key === "image" || key === "background_image" || key === "background_a_image") {
|
||||
// 渲染器只读 url / alt
|
||||
return { url: v.url, alt: v.alt };
|
||||
}
|
||||
if (key === "link") {
|
||||
// 渲染器只读 url / target / is_external(is_external=on → target=_blank,与原站 link_attributes 一致)
|
||||
return { url: v.url, target: v.target, is_external: v.is_external };
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/** # 函数 递归瘦身单个 Elementor 元素
|
||||
* 参数 el 原始元素(section/column/widget 通用结构)
|
||||
* 返回值 仅含 id/elType/widgetType/isInner/白名单 settings/elements 的新对象
|
||||
*/
|
||||
function slimElement(el: unknown): unknown {
|
||||
if (!el || typeof el !== "object") return el;
|
||||
const src = el as Record<string, unknown>;
|
||||
const out: Record<string, unknown> = {};
|
||||
if (src.id != null) out.id = src.id;
|
||||
if (src.elType != null) out.elType = src.elType;
|
||||
if (src.widgetType != null) out.widgetType = src.widgetType;
|
||||
if (src.isInner) out.isInner = true;
|
||||
const st = src.settings;
|
||||
if (st && typeof st === "object" && !Array.isArray(st)) {
|
||||
const slim: Record<string, unknown> = {};
|
||||
for (const key of Object.keys(st as Record<string, unknown>)) {
|
||||
if (SETTING_KEYS.has(key)) slim[key] = slimSettingValue(key, (st as Record<string, unknown>)[key]);
|
||||
}
|
||||
if (Object.keys(slim).length > 0) out.settings = slim;
|
||||
}
|
||||
if (Array.isArray(src.elements) && src.elements.length > 0) {
|
||||
out.elements = src.elements.map(slimElement);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** # 函数 瘦身整份 Elementor 文档(数组或 {elements:[]} 包装均支持)
|
||||
* 参数 doc 原始文档(来自 meta.elementor)
|
||||
* 返回值 瘦身后的文档;非对象/数组输入原样返回
|
||||
*/
|
||||
export function slimElementorDoc(doc: unknown): unknown {
|
||||
if (Array.isArray(doc)) return doc.map(slimElement);
|
||||
if (doc && typeof doc === "object" && Array.isArray((doc as Record<string, unknown>).elements)) {
|
||||
const wrapped = doc as Record<string, unknown>;
|
||||
return { elements: (wrapped.elements as unknown[]).map(slimElement) };
|
||||
}
|
||||
return doc;
|
||||
}
|
||||
|
||||
/** # 函数 瘦身内容 meta:替换 meta.elementor 为瘦身版(原 meta 其余字段保留)
|
||||
* 参数 meta 原始 meta JSON(可能为 null)
|
||||
* 返回值 elementor 已瘦身的 meta;无 elementor 时原样返回
|
||||
*/
|
||||
export function slimMetaElementor<T>(meta: T): T {
|
||||
if (!meta || typeof meta !== "object") return meta;
|
||||
const m = meta as Record<string, unknown>;
|
||||
if (!m.elementor) return meta;
|
||||
return { ...m, elementor: slimElementorDoc(m.elementor) } as T;
|
||||
}
|
||||
Reference in New Issue
Block a user