
本文介绍如何使用原生 javascript 实现从 json 文件加载联系人数据,并在页面中动态切换「姓名列表视图」与「单个联系人详情视图」,无需后端渲染或框架依赖。
本文介绍如何使用原生 javascript 实现从 json 文件加载联系人数据,并在页面中动态切换「姓名列表视图」与「单个联系人详情视图」,无需后端渲染或框架依赖。
在构建轻量级前端数据展示应用时,常需从静态 JSON 文件读取结构化数据并实现交互式视图切换。本教程以“联系人管理”为典型场景,完整演示:① 安全加载并解析 JSON 数据;② 渲染可点击的姓名列表;③ 点击后动态生成并插入详情面板;④ 点击关闭按钮销毁详情视图——全程采用现代原生 Web API(fetch、addEventListener、Element.append()),避免全局变量污染与重复 DOM 操作。
✅ 核心思路:数据绑定 + 事件委托
关键在于将原始数据直接绑定到 DOM 元素上,而非依赖索引或 ID 查找。在创建
同时,采用事件委托策略:不在每个
- ,通过 e.target.nodeName === 'LI' 判断触发源。此举显著提升性能(尤其数据量大时),并天然支持后续动态增删列表项。
✅ 完整可运行代码示例
以下为优化后的 HTML、JavaScript 与关键 CSS 片段(已剔除冗余样式,聚焦功能逻辑):
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>联系人管理</title> <link rel="stylesheet" href="style.css"> </head> <body> <header><h1>联系人管理</h1></header> <main class="view"></main> <script src="script.js"></script> </body> </html>
// script.js
fetch('data.json')
.then(res => {
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
return res.json();
})
.then(data => createListContact(data))
.catch(err => console.error('加载数据失败:', err));
function createListContact(data) {
const main = document.querySelector('main.view');
main.innerHTML = ''; // 清空旧内容
const ol = document.createElement('ol');
ol.classList.add('list-view');
ol.addEventListener('click', showDetails);
data.personen.forEach((person, index) => {
const li = document.createElement('li');
li.classList.add('button');
li.id = `person-${index}`;
li.textContent = `Name: ${person.nachname}, ${person.vorname}`;
li.personData = person; // ✅ 关键:数据直连 DOM
ol.appendChild(li);
});
main.appendChild(ol);
}
function showDetails(e) {
if (e.target.nodeName !== 'LI') return;
const { personData } = e.target;
const details = document.createElement('div');
details.className = 'details';
details.id = 'contact-details';
const closeBtn = document.createElement('button');
closeBtn.className = 'close-btn';
closeBtn.textContent = '×';
closeBtn.type = 'button';
closeBtn.addEventListener('click', () => details.remove());
const infoEl = document.createElement('div');
infoEl.className = 'contact-info';
infoEl.innerHTML = `
<h2>${personData.vorname} ${personData.nachname}</h2>
<p><strong>电话:</strong>${personData.telefonnummer || '未提供'}</p>
<p><strong>邮箱:</strong>${personData.email || '未提供'}</p>
`;
details.append(closeBtn, infoEl);
document.body.appendChild(details);
}/* style.css */
body {
font-family: "Segoe UI", system-ui, sans-serif;
background-color: #f5f5f5;
margin: 0;
padding: 20px;
}
main.view {
max-width: 800px;
margin: 0 auto;
background: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
overflow: hidden;
}
.list-view {
list-style: none;
padding: 0;
margin: 0;
}
.list-view .button {
padding: 12px 20px;
margin: 4px;
background: #4a6fa5;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
text-align: left;
transition: background 0.2s;
}
.list-view .button:hover {
background: #3a5a80;
}
.details {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
border-radius: 8px;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
width: 90%;
max-width: 500px;
z-index: 1000;
padding: 24px;
border: 1px solid #e0e0e0;
}
.close-btn {
float: right;
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: #999;
padding: 0;
margin: -8px -8px 16px 0;
}
.close-btn:hover {
color: #333;
}
.contact-info h2 {
margin-top: 0;
color: #2c3e50;
}
.contact-info p {
margin: 8px 0;
line-height: 1.5;
}⚠️ 注意事项与最佳实践
- JSON 结构一致性:确保 data.json 中 personen 是数组,且每个对象包含 vorname、nachname、telefonnummer、email 字段(缺失字段建议用 || '未提供' 防错)。
- 错误处理必须显式添加:fetch 可能因网络、CORS 或 JSON 格式错误失败,务必用 .catch() 捕获并提示用户(示例中已包含基础错误日志)。
- 内存与性能:details.remove() 比 parentNode.removeChild() 更简洁安全;避免在循环中频繁调用 document.body.appendChild(),应先构建完整 DOM 片段再插入。
- 无障碍与体验:生产环境建议为 .button 添加 role="button" 和键盘事件(Enter/Space 触发),并为模态框添加 aria-modal="true" 和焦点管理。
- 样式隔离:.details 使用 position: fixed 并设 z-index,确保覆盖其他内容;关闭按钮浮动右上角,符合用户直觉。
通过以上实现,你获得了一个零依赖、高可维护、语义清晰的前端数据展示方案。它不仅解决了“视图切换”的核心问题,更体现了现代 Web 开发中数据驱动、事件委托与关注点分离的设计思想。










