如何使用Fetch API获取数据并在HTML页面中渲染展示
问题核心原因
当前代码仅完成了「接口请求、控制台打印返回结果」两个环节,完全缺失了DOM渲染逻辑,同时HTML结构没有预留作品信息的展示位置,这就是控制台能看到接口返回数据、页面却没有对应内容的根本原因。
现有代码的具体问题
- 艺术品ID获取逻辑容错率极低:靠
document.getElementsByTagName('img')[art_index].attributes[2].value按属性顺序读取ID,只要后续给img标签新增任意属性(比如class、自定义属性),就会读错值导致接口请求失败。 - HTML结构缺失信息容器:所有
<figure>标签内只有图片标签,没有预留放置作品标题、作者、年代信息的DOM节点,数据没有插入的位置。 - 接口请求逻辑有隐患:构造请求URL时随意折行,会导致URL拼接多余空格,直接触发接口404错误。
- 声明了
showArtInfo状态变量、stopShow切换方法,但完全没有实现对应逻辑,无法实现「点击展开/再次点击收起、切换作品时自动关闭上一个展开项」的交互。 - JS文件放在
<head>中加载时,页面DOM还未渲染完成,后续加DOM操作逻辑时很容易出现找不到元素的报错。
分步修复方案
第一步:调整HTML结构
- 把head里引入main.js的script标签移到body末尾,和bootstrap、popper的script标签放在一起,避免DOM未加载完成就执行JS。
- 给每个作品图片加
data-art-id自定义属性存作品ID(就是你之前写在img alt里的数字编号),同时在每个figure标签内新增信息展示容器,默认用Bootstrap的d-none类隐藏,示例结构如下:
<figure class="gallery__item gallery__item--1" id="blackmirror" onclick="event.stopPropagation(); getArt(this.id, event)"> <img class="gallery__img shadow-lg" src="images/black-mirror.jpeg" alt="黑镜" data-art-id="126414"> <!-- 新增作品信息容器 --> <div class="art-info card p-3 mt-2 d-none"></div> </figure>
6个作品的figure都按这个结构修改,替换对应data-art-id的值即可。
第二步:补全JS逻辑
修改clickedEvent函数,替换成如下可运行的代码,核心补全了ID读取、DOM插入、显示状态切换、错误处理的逻辑:
// 记录当前处于展开状态的作品信息容器 let showArtInfo = null; async function clickedEvent(art_index, info_index) { // 稳妥获取目标图片、对应作品ID、信息容器 const targetImg = document.getElementsByTagName('img')[art_index]; const artId = targetImg.dataset.artId; const infoContainer = targetImg.closest('.gallery__item').querySelector('.art-info'); // 点击已展开的作品时,直接收起 if (showArtInfo === infoContainer) { infoContainer.classList.add('d-none'); showArtInfo = null; return; } // 切换作品前先收起之前展开的信息 if (showArtInfo) { showArtInfo.classList.add('d-none'); } try { const headers = new Headers([ ['Content-Type', 'application/json'], ['Accept', 'application/json'] ]); // 注意接口URL不要折行,避免拼接多余空格 const request = new Request(`https://api.artic.edu/api/v1/artworks/${artId}?fields=id,title,artist_display,date_display,main_reference_number`, { method: 'GET', headers: headers }); const result = await fetch(request); const response = await result.json(); const artData = response.data; console.log(artData); // 拼接作品信息插入容器 infoContainer.innerHTML = ` <h5 class="card-title">${artData.title}</h5> <p class="card-text mb-1"><strong>创作者:</strong>${artData.artist_display}</p> <p class="card-text mb-1"><strong>创作时间:</strong>${artData.date_display}</p> <p class="card-text text-muted small mb-0">馆藏编号:${artData.main_reference_number}</p> `; // 显示信息容器 infoContainer.classList.remove('d-none'); showArtInfo = infoContainer; } catch (err) { console.error('作品信息加载失败', err); infoContainer.innerHTML = '<p class="text-danger mb-0">信息加载失败,请稍后重试</p>'; infoContainer.classList.remove('d-none'); } } function getArt(id, event){ switch(id){ case 'blackmirror' : { event.stopPropagation(); clickedEvent(0,0) break; } case 'manymansions' : { event.stopPropagation(); clickedEvent(1,0) break; } case 'nightlife' : { event.stopPropagation(); clickedEvent(2,0) break; } case 'room' : { event.stopPropagation(); clickedEvent(3,0) break; } case 'opo' : { event.stopPropagation(); clickedEvent(4,0) break; } case 'weaving' : { event.stopPropagation(); clickedEvent(5,0) break; } } }
可选优化(功能跑通后再调整)
- 当前
getArt函数靠硬编码索引匹配作品,写法冗余,可以通过事件对象直接拿到点击的figure元素,不用写一长串switch判断。 - 可以给信息容器加CSS过渡动画,让展开收起的效果更流畅。
- 可以加加载态,接口请求过程中在容器里显示“加载中”提示,提升体验。
入门学习方向
- 优先掌握DOM核心操作:元素选择、属性读写、class切换、内容插入、节点关系查找,接口返回的数据必须通过这些操作才能渲染到页面上。
- 熟悉自定义
data-*属性的用法,不要靠属性顺序、硬编码索引传递页面数据,容错率极低。 - 异步请求必须加错误捕获,避免网络异常时整个页面交互崩溃。
- 写交互前先梳理页面结构:需要展示什么内容,就先在HTML里预留对应容器,不要等拿到数据才发现没有渲染位置。
内容的提问来源于stack exchange,提问作者Schadre
相关产品推荐
相关产品推荐

