You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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);
// }

解决方案

错误原因

  1. pokeImgContainer[i].appendChild 报错:pokeImgContainer是单个DOM容器元素,不是数组,不能用下标[i]访问,这是直接触发报错的原因。
  2. 覆盖img元素:createImgTag = images[i].src;把刚创建的img DOM对象替换成了字符串路径,导致后续无法调用appendChild。
  3. 图片重复问题:当前逻辑给每个卡片添加所有图片,而非单张匹配,导致所有卡片显示相同内容。

修正后的代码

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);
}

关键修改点

  1. 添加全局计数器:用cardIndex记录生成卡片的顺序,确保每张卡片对应唯一的图片索引。
  2. 修正图片创建逻辑:不再覆盖img元素,正确设置src属性后添加到容器。
  3. 单张图片匹配:每个卡片只添加对应索引的图片,解决重复问题;通过imgIndex % gameImages.length实现图片循环复用,避免索引越界。
  4. 清理冗余代码:移除原代码中重复定义的函数,避免逻辑混乱。

内容的提问来源于stack exchange,提问作者manggae

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 16:09:45