从JavaScript数组生成动态HTML卡片

10
我想在HTML中显示一些卡片元素。我希望从JavaScript数组中获取卡片元素的变量(例如标题等)。卡片元素的数量也将取决于JavaScript数组的大小。我已经查看了其他问题,例如生成动态表格,但由于我有一个长的自定义HTML代码块,它不起作用。
这是我正在构建的网站。我已经通过HTTP GET请求从api端点获取了变量,但无法按照我的意愿显示。我查看了许多类似的问题,但找不到我要找的答案。
以下是使用HTTP GET请求获取变量的脚本。
<script>
const request = new XMLHttpRequest();

request.open('GET', 'api/seminars', true);
request.onload = function() {
  // Begin accessing JSON data here
  const data = JSON.parse(this.response);

  if (request.status >= 200 && request.status < 400) {
    data.forEach(resultArray => {
      document.getElementById('output').innerHTML = resultArray.name;
      document.getElementById('description').innerHTML =
        resultArray.description;
      document.getElementById('date').innerHTML = resultArray.date;
    });
  } else {
    console.log('error');
  }
};

request.send();
</script>

HTML 代码:

<div id="accordion">
    <div class="card">
        <div class="card-header" id="headingOne">
            <h5 class="mb-0">
                <button class="btn btn-link" data-toggle="collapse" data- target="#collapseOne" aria-expanded="true"
                    aria-controls="collapseOne">

                </button>
            </h5>
        </div>

        <div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#accordion">
            <div class="card-body">

                <h5 id="name"></h5>
                <p id="description"></p>
                <p id="description"></p>
                ...
            </div>
        </div>
    </div>
</div>

接下来我会持续展示HTML代码,但不涉及本次翻译内容。

如果我的数组中有三个对象,我希望能分别创建三张卡片并展示它们的名称、描述等属性。但是我的代码只创建了一张卡片,并显示了最后一个对象的属性。


1
你能给一个 API 返回的例子吗? - Silvio Biasiol
1
由于卡片数量取决于结果数组的长度,因此您需要动态生成每个卡片的HTML。您需要在HTML中拥有一个容器div。然后,在onload方法中动态生成每个卡片的HTML,并将其附加为容器元素的子元素。 - Sanjucta
1
Api返回有关会议的名称、描述和日期信息。但它只创建一个卡片元素,并在数组中显示最后一个会议的信息。我想为所有会议创建不同的卡片,并在这些不同的卡片中显示它们的信息。 - Ilker Kadir Ozturk
1
你能提供一个例子吗? - Ilker Kadir Ozturk
3个回答

10
你的代码实际上并不会根据API调用“创建”元素 - 它只是通过更新固定元素的innerHTML来更新(覆盖)现有的dom元素,这些元素由它们的ID引用。
如果我对你的代码的解释正确,那么你应该只看到API结果中的最后一项。还有一些其他奇怪的东西发生,比如重复的ID,我猜这些都是拼写错误。
为了解决这个问题,为API返回的每个项目创建一个新的
并将其附加到容器中。

const apiResult = [{
  title: "title1",
  description: "desc1",
  output: "out1"
}, {
  title: "title2",
  description: "desc2",
  output: "out2"
}, {
  title: "title3",
  description: "desc3",
  output: "out3"
}];


const container = document.getElementById('accordion');

apiResult.forEach((result, idx) => {
  // Create card element
  const card = document.createElement('div');
  card.classList = 'card-body';

  // Construct card content
  const content = `
    <div class="card">
    <div class="card-header" id="heading-${idx}">
      <h5 class="mb-0">
        <button class="btn btn-link" data-toggle="collapse" data-target="#collapse-${idx}" aria-expanded="true" aria-controls="collapse-${idx}">

                </button>
      </h5>
    </div>

    <div id="collapse-${idx}" class="collapse show" aria-labelledby="heading-${idx}" data-parent="#accordion">
      <div class="card-body">

        <h5>${result.title}</h5>
        <p>${result.description}</p>
        <p>${result.output}</p>
        ...
      </div>
    </div>
  </div>
  `;

  // Append newyly created card element to the container
  container.innerHTML += content;
})
.card {
padding: 1rem;
border: 1px solid black;
margin: 1rem;
}
<div id="accordion">
  
</div>

注意:

虽然这种方法可行,但不太具有可扩展性。如果您必须在许多地方执行此操作(并维护它),则可以考虑使用一些拥有更高级插值功能的优秀模板库。

jsRender

Underscore Templates

Handlebars

VueReact和Angular这样的UI框架将模板与数据模型绑定并处理自动更新DOM,以使类似于此类的事情变得更加容易。如果您的网页有很多动态更新部分,则值得研究。


1
谢谢您的回答,但它没有填充不同的卡对象。它会将所有信息写在一个卡片中。 - Ilker Kadir Ozturk
1
@IlkerKadirOzturk明白了。在这种情况下,你可以使用+=而不是=来保留元素的当前内容。我已经更新了我的答案。 - Chirag Ravindra
1
我认为问题在于一开始我没有这些卡对象,但是希望根据传入数组的大小来创建它们。这段代码是否根据大小填充卡对象?我仍然只得到一个卡对象。 - Ilker Kadir Ozturk
1
我的之前的代码就是这样做的。在你的评论后,我进行了编辑:“感谢您的回答,但它没有填充不同的卡对象。它将所有信息都写在一个卡片中。” 我以为你想要它在一个卡片中。现在我撤销了我的回答。 - Chirag Ravindra
1
我还更新了代码以模仿您的HTML标记 - 您可能需要根据需要进行微调。 - Chirag Ravindra
显示剩余6条评论

3
假设您已经查询了API,可通过以下方式实现:

// Supposing you already have queried the API and have your data
    let data = [
        {name: 'name0', description: 'description', date: 'XX/XX/XXXX'},
        {name: 'name1', description: 'description', date: 'XX/XX/XXXX'},
        {name: 'name2', description: 'description', date: 'XX/XX/XXXX'},
    ]

    data.forEach(res => {
        let card = document.createElement("div");

        let name = document.createTextNode('Name:' + res.name + ', ');
        card.appendChild(name);

        let description = document.createTextNode('Description:' + res.description + ', ');
        card.appendChild(description);

        let date = document.createTextNode('date:' + res.date);
        card.appendChild(date);

        let container = document.querySelector("#container");
        container.appendChild(card);
    });
<!-- At one point where you want to generate the cards you put this container -->
<div id="container"></div>

由于您一直更新相同的元素而不是添加新元素,因此您的代码不起作用 :)


但是我们如何添加CSS呢?是否可以使其模型驱动? - Srinath Kamath

2
你正在每次 for 循环 重写描述的 innerHTML。请更改此处:

document.getElementById('output').innerHTML = resultArray.name;
document.getElementById('description').innerHTML = resultArray.description;
document.getElementById('date').innerHTML = resultArray.date;

to this

var element = document.createElement('div'); // create new div

var name = document.createElement('h4');
name.innerHTML = resultArray.name;
element.appendChild(name);

var description = document.createElement('p');
description.innerHTML = resultArray.description;
element.appendChild(description);

var date = document.createElement('span');
date.innerHTML = resultArray.date;
element.appendChild(date);

document.body.appendChild(element);


1
当我使用console.log时,我单独看到了来自API的变量。但是这个div标签只包含h4标签中的date变量。Span和p为空。 - Ilker Kadir Ozturk
1
@Kadir。有一个打字错误,请将第二个和第三个 name.innerHTML 更改为正确的变量。答案现在应该已经修复了。 - Chirag Ravindra
1
@ChiragRavindra 谢谢您修复那个令人尴尬的错误。 - Jasper Lichte
1
@JasperLichte 我把责任归咎于 SO UI - 错误* ;) - Chirag Ravindra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接