createelement 搭配模板字符串构建嵌套组件需通过封装 html 函数解析模板并递归创建节点,支持组件工厂复用、事件属性显式绑定及 documentfragment 批量插入优化性能。
用 createelement 搭配模板字符串构建嵌套组件,关键在于把模板字符串作为结构描述,再由 createelement 解析并生成真实 dom 节点。这不是原生 api 的直接组合(浏览器不支持直接用模板字符串调 createelement),但可以通过轻量解析或函数封装实现——既保持声明式表达的清晰性,又拥有 createelement 的灵活性和性能优势。
用函数封装:把模板字符串转成 createElement 调用链
核心思路是写一个辅助函数(比如叫 html),接收带占位符的模板字符串,自动调用 createElement 创建元素,并递归处理子节点。
示例:
const html = (strings, ...values) => {
const node = document.createElement(strings[0].trim());
let i = 0;
for (const str of strings.slice(1)) {
if (values[i] instanceof Node) {
node.appendChild(values[i]);
} else if (typeof values[i] === 'string') {
node.appendChild(document.createTextNode(values[i]));
}
if (str.trim()) {
node.appendChild(document.createTextNode(str.trim()));
}
i++;
}
return node;
};
// 使用:嵌套结构一目了然
const card = html`
<article class="card"><header><h2>${'用户资料'}</h2></header><div class="body">
<p>姓名:<span>${'张三'}</span></p>
<p>城市:<span>${'杭州'}</span></p>
</div>
<footer><button>${'编辑'}</button></footer></article>
`;
document.body.appendChild(card);
支持组件化:用函数返回可复用的“组件工厂”
把模板逻辑封装成函数,输入数据,输出 DOM 节点。这样既能复用,又能自然嵌套。
- 每个组件函数只负责自身结构,子组件通过函数调用插入
- 避免字符串拼接,保留类型安全与 IDE 支持(如 TypeScript 可约束参数)
- 嵌套时直接调用子组件函数,返回的 Node 自动插入父结构中
例如:
const Badge = (text) => {
const el = document.createElement('span');
el.className = 'badge';
el.textContent = text;
return el;
};
const UserCard = (user) => {
const el = document.createElement('div');
el.className = 'user-card';
el.append(
html`<h3>${user.name}</h3>`,
html`<p>邮箱:${user.email}</p>`,
Badge(user.role) // 嵌套组件调用
);
return el;
};
document.body.append(UserCard({ name: '李四', email: 'lisi@example.com', role: '管理员' }));
处理事件与属性:在 createElement 阶段注入行为
模板字符串只管结构,交互逻辑应在 createElement 后显式绑定,这样职责清晰、调试方便。
- 用
setAttribute设置 HTML 属性(id、class、data-等) - 用
el.onclick = handler或addEventListener绑定事件 - 避免在模板里写
onclick="..."—— 无法访问闭包变量,也不利于调试
例如给按钮加点击行为:
const Button = (label, onClick) => {
const btn = document.createElement('button');
btn.textContent = label;
btn.addEventListener('click', onClick);
return btn;
};
const toolbar = html`
<div class="toolbar"></div>
`;
toolbar.appendChild(Button('保存', () => console.log('已保存')));
进阶:配合 DocumentFragment 批量插入提升性能
构建深层嵌套结构时,频繁操作 DOM 会触发多次重排。用 DocumentFragment 先离线组装,最后一次性挂载。
改造上面的 html 函数,让它支持 Fragment 作为根容器;或在组件函数末尾统一用 Fragment 收集子节点:
const renderList = (items) => {
const frag = document.createDocumentFragment();
items.forEach(item => {
frag.appendChild(UserCard(item));
});
return frag; // 返回 fragment,外部 append 一次即可
};
document.body.appendChild(renderList([
{ name: '王五', email: 'wuwu@example.com', role: '用户' },
{ name: '赵六', email: 'zhaoliu@example.com', role: '审核员' }
]));










