页面配置必须挂载在<html>标签上,如<html data-api-base="/api" data-env="prod">,因其在HTML解析最早阶段即存在,document.documentElement.dataset可立即访问;<body>为次选,避免挂载在业务容器中。

页面配置必须挂载在 <html> 或 <body> 上,用 data-* 属性传字符串或 JSON 序列化值,不能塞进 class、id 或自定义非标准属性里——否则 JS 读不到,SSR 渲染后也丢失。
配置该挂在哪一层 DOM 节点上
优先写在 <html> 标签上:<html data-api-base="/api" data-env="prod" data-timeout="5000">。它在 HTML 解析最早阶段就存在,document.documentElement.dataset 在任意脚本中可立即访问,不依赖 DOM 就绪。
<body> 是次选,适合只供前端 JS 使用、且无需 SSR 首屏直出的配置。别挂在某个业务容器(比如 <div id="app">)上——组件未挂载时就读不到,多实例还会冲突。
- 服务端模板(如 EJS、Jinja2)输出时,对 JSON 值必须做 HTML 实体转义,例如:
data-config=""{"theme":"dark"}"" - 敏感字段如
data-token、data-secret-key绝对禁止——源码里明文可见,等同于泄露 - 若配置含动态内容(如用户 ID),务必由服务端注入,不可前端拼接
data-* 属性命名和读取的硬规则
写错名字,JS 就读不到。data-userId、data_user_id、data-UserID 全部无效:浏览器只认全小写 + 连字符形式,且自动把连字符后首字母转驼峰。
立即学习“前端免费学习笔记(深入)”;
正确示例:data-api-url → JS 中为 el.dataset.apiUrl;data-2024-report → 必须用 el.dataset["2024Report"](点号无法访问数字开头)。
- 读取一律用
el.dataset.xxx,语义清晰且自动转换命名 - 写入必须用
el.setAttribute("data-xxx", "value"),否则只改内存副本,DOM 不更新 - 判断是否存在,先写
"xxx" in el.dataset,再取值,避免undefined导致报错 - 删除用
delete el.dataset.xxx,比removeAttribute("data-xxx")更安全
存 JSON、布尔值、数字时怎么防坑
dataset 暴露的永远是字符串。存 data-is-pending="false",读出来是字符串 "false",不是布尔 false;存 data-config='{"theme":"dark"}',读出来是字符串,不是对象。
- 布尔判断别用
Boolean(el.dataset.isPending),改用el.dataset.isPending === "true" - 数字转换用
+el.dataset.count或Number(el.dataset.count),别直接=== 0 - JSON 数据必须手动
JSON.parse(el.dataset.config || "{}"),且加try/catch——服务端漏转义会直接导致语法错误 - 多值场景(如权限列表)用空格分隔:
data-perms="read write delete",再用.split(" ")处理,比存 JSON 数组更鲁棒
SSR 和框架环境下的特殊处理
服务端渲染时,首次 JS 执行前 dataset 是空的;React/Vue 默认不透传 data-* 到根节点,必须显式处理。
SSR 安全读值方式:el.getAttribute("data-xxx") —— 它返回原始字符串,不依赖 dataset 初始化时机。
- Vue 中需在根组件
data-属性上加v-bind显式绑定,或通过provide/inject透传 - React 中 JSX 支持原生
data-*,但注意不要用data-config={obj}直接传对象,必须先JSON.stringify - 构建时能静态确定的配置(如版本号、CDN 域名),建议用 webpack DefinePlugin 注入,而非 runtime 读 DOM
最易被忽略的是路径解析上下文:如果配置里有 ,它相对于当前 HTML 文档 URL,不是相对于 JS 文件位置。单页应用路由切换后,这个相对路径可能突然失效——绝对路径才是稳解。



















