表单 Schema 应定义为含字段元信息与条件逻辑的结构化描述,包含 type、name、label、required 等基础字段,以及 visibleIf、disabledIf、validation 等动态控制字段,数组保序,name 使用空数组语法如 name="contact[]",并通过 template 标签安全渲染,避免 innerHTML XSS。
关键不是写 HTML,而是设计可被模板引擎消费的结构化描述。Schema 必须包含字段级元信息,且能表达条件逻辑。
type、name、label、required 是基础字段,但仅这些不够visibleIf 或 disabledIf 这类表达式字段,例如:{"visibleIf": "country === 'HK'"},后端传入上下文变量 {country: "HK"} 后由模板引擎求值pattern),应统一放在 Schema 的 validation 字段里,由渲染层注入——否则无法做国际化或运行时切换name="items[]" 提交顺序会错乱直接拼接字符串插入 innerHTML 极易引入 XSS,尤其当 Schema 中的 label 或 placeholder 来自配置中心时。
<template> 标签定义字段片段,例如:<template id="input-field"><input name="{{name}}" type="{{type}}"></template>
textContent 或 setAttribute 注入变量,绝不用 innerHTML = `<label>${label}</label>`
<a href>),且过滤逻辑在模板渲染前完成,不在 JS 插入时做template.content.cloneNode(true) 不会执行内联脚本,这是安全前提;若用了 onclick 等内联事件,得改用事件委托绑定动态表单最常崩在 name 设计上。浏览器提交机制不认索引,只认语义分组。
name="contact[]",不要生成 name="contact[0]"、name="contact[1]"
name="addresses[][street]"、name="addresses[][city]",这样 PHP/Python/Django 才能自动解析为数组对象<div class="form-item">... 节点,不能只清空 value 或设 display: none——后者仍会被 FormData 收集data-index 维护本地状态,但绝不映射到 name
这不是 HTML 自身能力,需要轻量 JS 表达式求值器配合模板逻辑。别用 eval(),也别引入完整 JS 引擎。
立即学习“前端免费学习笔记(深入)”;
Function 构造器沙箱化执行,例如:new Function('data', 'return ' + expression)(context),前提是 expression 是白名单内的简单表达式(===、&&、||、括号)<div class="field" data-visible-if="country === 'US' && hasTaxId">,渲染后 JS 扫描所有 data-visible-if 并求值,控制 style.display
data.hasTaxId 若为 undefined 或 null,&& 会短路,所以上下文必须补全默认值,比如后端传 {hasTaxId: false} 而非省略该字段region 值,但配置漏传或传错类型(如传字符串 "1" 而非数字 1),会导致所有 visibleIf 失效,且无任何报错提示。