如何用JavaScript为动态生成的Div添加不同图片并解决DOM报错
问题描述
我正尝试为JavaScript动态生成的Div元素添加不同的本地图片,目标是每个Div对应一张独特图片,但这些Div不存在于index.html中。用for循环遍历图片src添加时,出现错误:Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'appendChild')。目前所有卡片都显示同一张图片,希望每张卡片对应不同的本地图片,可忽略CSS部分。
原代码
HTML
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link type="text/css" rel="stylesheet" href="css/materialize.min.css" media="screen,projection"/> <link rel="stylesheet" href="style.css"> <title>Pokemon Games</title> </head> <body> <div id="poke-container"> </div> <script type="text/javascript" src="js/materialize.min.js"></script> <script src="script.js"></script> </body> </html>
CSS
#poke-container { margin: auto; width: 90%; padding: 10px; display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; } .gameTitle { text-transform: capitalize; font-size: 25px; font-weight: bold; margin: 7px; } .game { display: flex; justify-content: center; align-items: center; flex-direction: column; padding: 20px 10px; } .card { width: 300px; }
JavaScript
function getGame(){ fetch('https://pokeapi.co/api/v2/version/?limit=40') .then(function (response) { return response.json(); }) .then(function(data){ data.results.forEach(function(version){ fetchPokemonData(version); }) }) } getGame(); function fetchPokemonData(version){ var url = version.url fetch(url) .then(function (response) { return response.json(); }) .then(function(pokeData){ console.log(pokeData); renderPokemon(pokeData) }) } function renderPokemon(pokeData){ var allPokemonContainer = document.getElementById('poke-container'); var pokeContainer = document.createElement("div") pokeContainer.classList.add('game', 'card',) function getGame(){ fetch('https://pokeapi.co/api/v2/version/?limit=40') .then(function (response) { return response.json(); }) .then(function(data){ data.results.forEach(function(version){ fetchPokemonData(version); }) }) } getGame(); function fetchPokemonData(version){ var url = version.url fetch(url) .then(function (response) { return response.json(); }) .then(function(pokeData){ console.log(pokeData); renderPokemon(pokeData) }) } function renderPokemon(pokeData){ var allPokemonContainer = document.getElementById('poke-container'); var pokeContainer = document.createElement("div") var gameLink = document.createElement('a') gameLink.classList.add('gameLink') pokeContainer.classList.add('game', 'card',) gamesImage(pokeContainer); var pokeName = document.createElement('h4') pokeDataName = pokeData.name pokeName.innerText = pokeDataName const hyphenRemove = pokeDataName.replace(/-/g, ' '); pokeName.innerText = hyphenRemove pokeName.classList.add('gameTitle') pokeContainer.append(pokeName); allPokemonContainer.append(pokeContainer) } var pokeName = document.createElement('h4') pokeDataName = pokeData.name pokeName.innerText = pokeDataName const hyphenRemove = pokeDataName.replace(/-/g, ' '); pokeName.innerText = hyphenRemove pokeName.classList.add('gameTitle') pokeContainer.append(pokeName); allPokemonContainer.append(pokeContainer) } function gamesImage(containerDiv) { const images = [{ src: 'https://picsum.photos/id/237/200/300' }, { src: 'https://picsum.photos/seed/picsum/200/300' },{ src: 'https://picsum.photos/200/300?grayscale' }] // There will be more src imgs here. I haven't added them yet. var pokeImgContainer = document.createElement('div') pokeImgContainer.classList.add('image') for (var i = 0; i < images.length; i++){ var createImgTag = document.createElement('img'); createImgTag = images[i].src; pokeImgContainer[i].appendChild(createImgTag); } containerDiv.append(pokeImgContainer); } //This is another approach I tried that didn't work: // function gamesImage(containerDiv) { // const imageFolder = [{ // src: 'https://picsum.photos/id/237/200/300' // }, { // src: 'https://picsum.photos/seed/picsum/200/300' // },{ // src: 'https://picsum.photos/200/300?grayscale' // }] // var pokeImgContainer = document.createElement('div') // pokeImgContainer.classList.add('image') // document.querySelectorAll('.image').forEach((el, index) => { // var images = document.createElement('img'); // images.setAttribute('src', imageFolder[index].src); // el.appendChild(images); // pokeImgContainer.appendChild.el; // }) // containerDiv.appendChild(pokeImgContainer); // }
解决方案
错误原因
pokeImgContainer[i].appendChild报错:pokeImgContainer是单个DOM容器元素,不是数组,不能用下标[i]访问,这是直接触发报错的原因。- 覆盖img元素:
createImgTag = images[i].src;把刚创建的img DOM对象替换成了字符串路径,导致后续无法调用appendChild。 - 图片重复问题:当前逻辑给每个卡片添加所有图片,而非单张匹配,导致所有卡片显示相同内容。
修正后的代码
JavaScript部分
// 定义全局图片数组,可替换为本地路径 const gameImages = [ { src: 'https://picsum.photos/id/237/200/300' }, { src: 'https://picsum.photos/seed/picsum/200/300' }, { src: 'https://picsum.photos/200/300?grayscale' }, // 可继续添加更多图片路径 ]; // 全局计数器,记录卡片生成顺序,用于匹配图片索引 let cardIndex = 0; function getGame() { fetch('https://pokeapi.co/api/v2/version/?limit=40') .then(response => response.json()) .then(data => { data.results.forEach(version => { fetchPokemonData(version); }); }); } getGame(); function fetchPokemonData(version) { fetch(version.url) .then(response => response.json()) .then(pokeData => { renderPokemon(pokeData); }); } function renderPokemon(pokeData) { const allPokemonContainer = document.getElementById('poke-container'); const pokeContainer = document.createElement('div'); pokeContainer.classList.add('game', 'card'); // 传入当前卡片索引,匹配对应图片 gamesImage(pokeContainer, cardIndex); // 计数器自增,确保下一张卡片用下一张图片 cardIndex++; const pokeName = document.createElement('h4'); const pokeDataName = pokeData.name.replace(/-/g, ' '); pokeName.innerText = pokeDataName; pokeName.classList.add('gameTitle'); pokeContainer.append(pokeName); allPokemonContainer.append(pokeContainer); } function gamesImage(containerDiv, imgIndex) { const pokeImgContainer = document.createElement('div'); pokeImgContainer.classList.add('image'); // 根据索引获取对应图片,若图片数量不足则循环使用 const targetImg = gameImages[imgIndex % gameImages.length]; const createImgTag = document.createElement('img'); createImgTag.src = targetImg.src; // 可添加图片alt属性 createImgTag.alt = 'Game cover'; pokeImgContainer.appendChild(createImgTag); containerDiv.append(pokeImgContainer); }
关键修改点
- 添加全局计数器:用
cardIndex记录生成卡片的顺序,确保每张卡片对应唯一的图片索引。 - 修正图片创建逻辑:不再覆盖img元素,正确设置
src属性后添加到容器。 - 单张图片匹配:每个卡片只添加对应索引的图片,解决重复问题;通过
imgIndex % gameImages.length实现图片循环复用,避免索引越界。 - 清理冗余代码:移除原代码中重复定义的函数,避免逻辑混乱。
内容的提问来源于stack exchange,提问作者manggae
相关产品推荐
相关产品推荐

