pin_drop当前位置:知识文库 ❯ 图文
布局结构:HTML模板template - 完整教程与代码示例
一、教程简介
HTML <template> 标签是Web Components技术栈的重要组成部分,它提供了一种声明式的方式来定义可复用的内容模板。template中的内容在页面加载时不会被渲染,只有在JavaScript中通过代码实例化后才会显示。本教程将详细讲解template标签的使用方法、内容模板的创建以及克隆使用技巧。
二、核心概念
什么是template标签
<template> 是HTML5引入的一个特殊元素,用于声明不会被立即渲染的HTML内容片段。它相当于一个"蓝图"或"模具",可以被JavaScript多次克隆和插入到文档中。
template的特点
template vs 普通隐藏元素
代码示例
<!-- 普通隐藏:内容仍在DOM中,脚本会执行,样式会应用 -->
<div style="display:none;">
<img src="image.jpg" alt="图片"> <!-- 会加载 -->
<script>alert('执行了');</script> <!-- 会执行 -->
</div>
<!-- template:内容不在活动DOM中,不加载不执行 -->
<template id="myTemplate">
<img src="image.jpg" alt="图片"> <!-- 不会加载 -->
<script>alert('不会执行');</script> <!-- 不会执行 -->
</template>三、语法与用法
基本语法
代码示例
<template id="templateId">
<!-- 模板内容 -->
<div class="card">
<h3>标题</h3>
<p>内容</p>
</div>
</template>JavaScript操作template
代码示例
// 1. 获取template元素
const template = document.getElementById('myTemplate');
// 2. 获取template的内容(DocumentFragment)
const content = template.content;
// 3. 克隆template内容
const clone = template.content.cloneNode(true); // 深克隆
// 4. 修改克隆内容
clone.querySelector('h3').textContent = '新标题';
// 5. 插入到DOM
document.getElementById('container').appendChild(clone);template的关键属性
四、代码示例
示例1:template基本使用
代码示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>template基本使用</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: "Microsoft YaHei", sans-serif;
background: #f5f5f5;
padding: 20px;
}
h1 { color: #2c3e50; margin-bottom: 20px; }
.controls { margin-bottom: 20px; }
.btn {
padding: 10px 20px;
background: #3498db;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
margin-right: 10px;
}
.btn:hover { background: #2980b9; }
.btn-danger { background: #e74c3c; }
.btn-danger:hover { background: #c0392b; }
.card-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 20px;
}
.user-card {
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
transition: transform 0.3s;
}
.user-card:hover { transform: translateY(-3px); }
.user-card .avatar {
width: 60px; height: 60px;
border-radius: 50%;
background: #3498db;
color: white;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
font-weight: bold;
margin-bottom: 15px;
}
.user-card h3 { color: #2c3e50; margin-bottom: 5px; }
.user-card .role { color: #3498db; font-size: 13px; margin-bottom: 10px; }
.user-card p { color: #666; font-size: 14px; line-height: 1.6; }
</style>
</head>
<body>
<h1>template模板使用演示</h1>
<div class="controls">
<button class="btn" onclick="addCard()">添加卡片</button>
<button class="btn btn-danger" onclick="clearCards()">清空所有</button>
</div>
<div class="card-container" id="cardContainer"></div>
<!-- 用户卡片模板 -->
<template id="userCardTemplate">
<div class="user-card">
<div class="avatar"></div>
<h3 class="name"></h3>
<div class="role"></div>
<p class="bio"></p>
</div>
</template>
<script>
var users = [
{ name: '张三', role: '前端工程师', bio: '专注于React和Vue开发', initial: '张' },
{ name: '李四', role: '后端工程师', bio: '精通Java和Go语言', initial: '李' },
{ name: '王五', role: 'UI设计师', bio: '擅长用户体验设计', initial: '王' }
];
var currentIndex = 0;
function addCard() {
if (currentIndex >= users.length) { alert('所有卡片已添加完毕!'); return; }
var template = document.getElementById('userCardTemplate');
var clone = template.content.cloneNode(true);
var user = users[currentIndex];
clone.querySelector('.avatar').textContent = user.initial;
clone.querySelector('.name').textContent = user.name;
clone.querySelector('.role').textContent = user.role;
clone.querySelector('.bio').textContent = user.bio;
document.getElementById('cardContainer').appendChild(clone);
currentIndex++;
}
addCard(); addCard(); addCard();
</script>
</body>
</html>示例2:template高级应用 - 动态表格
代码示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>template高级应用</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: "Microsoft YaHei", sans-serif; background: #f5f5f5; padding: 20px; }
h1 { color: #2c3e50; margin-bottom: 20px; }
.panel { background: white; border-radius: 8px; padding: 20px; margin-bottom: 20px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
.btn { padding: 8px 20px; background: #3498db; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; }
.btn:hover { background: #2980b9; }
.btn-sm { padding: 4px 12px; font-size: 12px; }
.btn-danger { background: #e74c3c; }
.btn-danger:hover { background: #c0392b; }
table { width: 100%; border-collapse: collapse; }
th, td { padding: 12px 15px; text-align: left; border-bottom: 1px solid #eee; font-size: 14px; }
th { background: #f8f9fa; color: #2c3e50; font-weight: bold; }
.status { display: inline-block; padding: 2px 10px; border-radius: 12px; font-size: 12px; font-weight: bold; }
.status-active { background: #d4edda; color: #155724; }
.status-inactive { background: #f8d7da; color: #721c24; }
.status-pending { background: #fff3cd; color: #856404; }
</style>
</head>
<body>
<h1>template动态表格</h1>
<div class="panel">
<table>
<thead><tr><th>ID</th><th>姓名</th><th>部门</th><th>状态</th><th>操作</th></tr></thead>
<tbody id="tableBody"></tbody>
</table>
</div>
<!-- 行模板 -->
<template id="rowTemplate">
<tr>
<td class="cell-id"></td>
<td class="cell-name"></td>
<td class="cell-dept"></td>
<td class="cell-status"></td>
<td><button class="btn btn-sm btn-danger" onclick="deleteRow(this)">删除</button></td>
</tr>
</template>
<script>
var idCounter = 1;
var statusMap = {
active: { text: '在职', class: 'status-active' },
inactive: { text: '离职', class: 'status-inactive' },
pending: { text: '试用期', class: 'status-pending' }
};
function addRecord(name, dept, status) {
var template = document.getElementById('rowTemplate');
var clone = template.content.cloneNode(true);
clone.querySelector('.cell-id').textContent = idCounter++;
clone.querySelector('.cell-name').textContent = name;
clone.querySelector('.cell-dept').textContent = dept;
var statusInfo = statusMap[status];
var statusSpan = document.createElement('span');
statusSpan.className = 'status ' + statusInfo.class;
statusSpan.textContent = statusInfo.text;
clone.querySelector('.cell-status').appendChild(statusSpan);
document.getElementById('tableBody').appendChild(clone);
}
addRecord('张三', '技术部', 'active');
addRecord('李四', '产品部', 'pending');
addRecord('王五', '设计部', 'active');
</script>
</body>
</html>五、浏览器兼容性
IE兼容性处理
代码示例
// 检测template支持
if ('content' in document.createElement('template')) {
// 原生支持
} else {
// IE回退方案:使用script标签
// <script type="text/template" id="myTemplate">...</script>
var html = document.getElementById('myTemplate').innerHTML;
var div = document.createElement('div');
div.innerHTML = html;
document.getElementById('container').appendChild(div.firstElementChild);
}六、注意事项与最佳实践
1. 始终使用深克隆
代码示例
// 推荐:深克隆(true参数)
var clone = template.content.cloneNode(true);
// 不推荐:浅克隆(只克隆DocumentFragment本身,不包含子节点)
var clone = template.content.cloneNode(false);2. template内容是DocumentFragment
代码示例
// DocumentFragment的特点:插入DOM后自动解包
var fragment = template.content.cloneNode(true);
// 修改fragment中的元素
fragment.querySelector('.title').textContent = '新标题';
// 插入时,fragment本身不会成为DOM节点,其子节点直接插入
container.appendChild(fragment);3. 避免在template中使用id
代码示例
<!-- 不推荐:多次克隆会产生重复id -->
<template id="cardTemplate">
<div id="card">...</div>
</template>
<!-- 推荐:使用class -->
<template id="cardTemplate">
<div class="card">...</div>
</template>4. 模板内容中的事件绑定
代码示例
// 方式1:克隆后绑定事件
var clone = template.content.cloneNode(true);
clone.querySelector('.btn').addEventListener('click', handleClick);
container.appendChild(clone);
// 方式2:使用事件委托(推荐)
container.addEventListener('click', function(e) {
if (e.target.classList.contains('btn')) {
handleClick(e);
}
});七、代码规范示例
代码示例
<!-- 模板定义规范 -->
<template id="cardTemplate">
<div class="card" data-type="user">
<div class="card__header">
<h3 class="card__title"></h3>
</div>
<div class="card__body">
<p class="card__text"></p>
</div>
</div>
</template>
<script>
// 模板使用规范
function createCard(data) {
// 1. 获取模板
var template = document.getElementById('cardTemplate');
// 2. 深克隆内容
var clone = template.content.cloneNode(true);
// 3. 填充数据
clone.querySelector('.card__title').textContent = data.title;
clone.querySelector('.card__text').textContent = data.text;
// 4. 返回克隆节点(由调用者决定插入位置)
return clone;
}
// 使用
var card = createCard({ title: '标题', text: '内容' });
document.getElementById('container').appendChild(card);
</script>八、常见问题与解决方案
常见问题
克隆后事件监听器丢失怎么办?
原因:cloneNode不会克隆事件监听器。
解决方案:克隆后重新绑定事件,或使用事件委托方式管理动态元素的事件。
template中的样式不生效如何处理?
原因:template内容不在活动DOM中,其中的<style>在克隆插入后才生效。
解决方案:将样式放在template外部或主文档的<style>中。
多次克隆产生重复id怎么解决?
解决方案:使用class替代id,或在克隆后动态生成唯一id。推荐在模板中统一使用class来标识元素。
九、总结
HTML template是创建可复用内容模板的重要工具:
-
惰性渲染:template内容不会自动渲染,节省资源
-
安全隔离:template中的脚本不执行,图片不加载
-
高效克隆:通过cloneNode快速创建多个实例
-
DocumentFragment:template.content是DocumentFragment,插入时自动解包
-
与Web Components配合:template是Shadow DOM和Custom Elements的基础
-
避免重复id:多次克隆template时使用class而非id
-
事件委托:对动态克隆的元素使用事件委托管理事件
本文涉及AI创作
内容由AI创作,请仔细甄别