簡體   English   中英

JavaScript 對 JSON 數據進行排序並動態生成<ul>和<li>基於鍵值的元素

[英]JavaScript Sort JSON data and dynamically generate <ul> and <li> elements based on key value

我試圖根據從 PHP 腳本獲取的 JSON 數據動態生成一些 HTML 列表。 返回的數據格式如下:

示例 JSON 數據:

[{"animal":"Dog","breed":"German Shepard","image":"germanshepard.png","ownerID":"885","Status":"Check In"},
{"animal":"Dog","breed":"Poodle","image":"poodle.png","ownerID":"131","Status":"Checked In"},
{"animal":"Dog","breed":"Labrador","image":"labrador.png","ownerID":"6","Status":"Waiting Consultation"},
{"animal":"Bird","breed":"Parrot","image":"parrot.png","ownerID":"22","Status":"Checked In"},
{"animal":"Bird","breed":"Finch","image":"finch.png","ownerID":"31","Status":"Checked In"},
{"animal":"Cat","breed":"Persian","image":"persian.png","ownerID":"19","Status":"Waiting Consultation"},
{"animal":"Cat","breed":"Sphynx","image":" sphynx.png","ownerID":"44","Status":"Allocated Kennel"}]

我正在嘗試為每個獨特的動物創建一個 div,即。 每個獨特的動物 1 div。 例如。

<div class='dog'></div>

在每個 div 中,我試圖為每個獨特的品種添加一個 ul,例如。

<ul class='Poodle'></ul>

最終結果如下所示:

 ul { background: #fff; color: #000; border: 1 px thin solid #000; } /* repeat for all status classes */ .Checked In { color: 'green'; }
 <section id='container'> <div class='Dog'> <ul class='German Shepard'> <li><img src='germanshepard.png'/></li> <li class='${ownerID}'>885</li> <li class='${Status}'>Check In</li> </ul> <ul class='Poodle'> <li><img src='poodle.png'/></li> <li class='${ownerID}'>131</li> <li class='${Status}'>Checked In</li> </ul> </div> <div class='Bird'> <ul class='Parrot'> <li><img src='parrot.png'/></li> <li class='${ownerID}'>22</li> <li class='${Status}'>Checked In</li> </ul> <ul class='Finch'> <li><img src='finch.png'/></li> <li class='${ownerID}'>31</li> <li class='${Status}'>Checked In</li> </ul> </div> </section>

我像這樣返回數據:

function getAnimalData() {
let url = "php/getAnimalData.php";
fetch(url)
    .then((res) => res.json())
    .then((data) => {
        for (const [key, value] of Object.entries(data)) {
            byID('container').insertAdjacentHTML('afterend', 
            `<div class="${value['animal']}">
              <ul class="${value['breed']}">
               <li class="${value['image']}"></li>
               <li class="${value['owner']}"></li>
               <li class="${value['status']}"></li>
              </ul>
            </div>`);
        }
    }).catch(err => {
        return Promise.reject(err.message);
    });
}

如您所知,這不會過濾獨特的動物,而是為每個動物及其下方的每個品種創建一個 div。 我在stackoverflow上嘗試了一些解決方案( 例如1 ) - 其中大部分涉及創建一個不同動物名稱的數組,然后循環遍歷該數組以創建多個ul元素,然后通過再次循環遍歷一組獨特的品種和適當地附加。 不幸的是,我還沒有找到一個有效的解決方案,任何接近工作的方法都是使用 jQuery、淘汰賽等(我非常不想使用 jQuery)。

我願意接受有關如何使用 Vanilla JavaScript 實現這一目標的建議 - 或者這是回到繪圖板並以不同方式格式化 JSON 數據的情況。

您可以使用此 groupBy 功能

function groupBy(list, props) {
  return list.reduce((a, b) => {
     (a[b[props]] = a[b[props]] || []).push(b);
     return a;
  }, {});
}
//https://gist.github.com/ramsunvtech/102ac0267d33c2cc1ccdf9158d0f7fca

usage: groupBy([{
  id: 1,
  group: 'user',
  name: 'User #1',
}, {
  id: 2,
  group: 'admin',
  name: 'User #2',
}, {
  id: 3,
  group: 'moderator',
  name: 'User #3',
}], 'group');

然后使用 Object.entries 遍歷分組列表以填充您的模板

首先,操作您的數據:

fetch(url)
    .then((res) => res.json())
    .then((data) => { // assuming data is an array of items
        const hash = {}
        for (let item of data) {
           if (!hash[item.animal])
              hash[item.animal] = []
           hash[item.animal].push(item)

這將導致一個對象具有每個動物種類的嵌套值

下一步:僅填充標題

for (let kind in hash) {
     byID('container').insertAdjacentHTML('afterend', `<div>${kind}</div>`)
}

最后一步:在每個標題下添加相關控件

for (let kind in hash) {
   byID('container').insertAdjacentHTML('afterend', `<div>${kind}</div>`)
   for (const value of hash[kind])) {
        byID('container').insertAdjacentHTML('afterend', 
        `<div class="${value['animal']}">
          <ul class="${value['breed']}">
           <li class="${value['image']}"></li>
           <li class="${value['owner']}"></li>
           <li class="${value['status']}"></li>
          </ul>
        </div>`);
    }

}

您需要對接收的數據進行分組

您的代碼應該像這樣更新

function getAnimalData() {
let url = "php/getAnimalData.php";
fetch(url)
    .then((res) => res.json())
    .then((data) => {
        const groupedData = data.reduce((a,obj) => {
        if (a[obj.animal] === undefined) a[obj.animal] = [obj]
        else a[obj.animal].push(obj)
        return a;
        }, {})
        groupedData.forEach((animals) => {
          animals.forEach((animal) => {
          for (const [key, value] of Object.entries(animal)) {
            byID('container').insertAdjacentHTML('afterend', 
            `<div class="${value['animal']}">
              <ul class="${value['breed']}">
               <li class="${value['image']}"></li>
               <li class="${value['owner']}"></li>
               <li class="${value['status']}"></li>
              </ul>
            </div>`);
          }
        })
      })
    }).catch(err => {
        return Promise.reject(err.message);
    });
}

請注意,我對動物進行了分組,然后查看了每個動物。

干杯

我能想到的最好方法是使用 .reduce() 方法。 這是JS實現。 您可以定義一個全局變量並使用方法來附加/替換 DOM 元素,而不是對象方法。

 const array = [ { "animal": "Dog", "breed": "German Shepard", "image": "germanshepard.png", "ownerID": "885", "Status": "Check In" }, { "animal": "Dog", "breed": "Poodle", "image": "poodle.png", "ownerID": "131", "Status": "Checked In" }, { "animal": "Dog", "breed": "Labrador", "image": "labrador.png", "ownerID": "6", "Status": "Waiting Consultation" }, { "animal": "Bird", "breed": "Parrot", "image": "parrot.png", "ownerID": "22", "Status": "Checked In" }, { "animal": "Bird", "breed": "Finch", "image": "finch.png", "ownerID": "31", "Status": "Checked In" }, { "animal": "Cat", "breed": "Persian", "image": "persian.png", "ownerID": "19", "Status": "Waiting Consultation" }, { "animal": "Cat", "breed": "Sphynx", "image": " sphynx.png", "ownerID": "44", "Status": "Allocated Kennel" } ] const result = array.reduce((prev, curr) => ({ ...prev, [curr.animal]: { ...prev[curr.animal], [curr.breed]: { ...(prev[curr.animal] || {})[curr.breed] || {}, image: curr.image, owner: curr.ownerID, status: curr.Status } } }), {}) console.log(result)

該解決方案首先按動物整理數據。 然后枚舉這個經過整理的對象並計算 HTML。

 const data = [{"animal":"Dog","breed":"German Shepard","image":"germanshepard.png","ownerID":"885","status":"Check In"},{"animal":"Dog","breed":"Poodle","image":"poodle.png","ownerID":"131","status":"Checked In"},{"animal":"Dog","breed":"Labrador","image":"labrador.png","ownerID":"6","status":"Waiting Consultation"},{"animal":"Bird","breed":"Parrot","image":"parrot.png","ownerID":"22","status":"Checked In"},{"animal":"Bird","breed":"Finch","image":"finch.png","ownerID":"31","status":"Checked In"},{"animal":"Cat","breed":"Persian","image":"persian.png","ownerID":"19","status":"Waiting Consultation"},{"animal":"Cat","breed":"Sphynx","image":"sphynx.png","ownerID":"44","status":"Allocated Kennel"}] const collate = (data) => data.reduce((acc, {animal, breed, image, ownerID, status}) => { acc[animal] = acc[animal] || {} acc[animal][breed] = acc[animal][breed] || {} acc[animal][breed] = { image, ownerID, status } return acc }, {}) const toHTML = (data) => `<section id='container'>${Object.entries(collate(data)).reduce((str, e) => str += animalHTML(e), '')} </section>` const animalHTML = ([animal, breeds]) => ` <div class='${animal}'> ${Object.entries(breeds).reduce((str, b) => str += breedHTML(b), '')}</div>` const breedHTML = ([breed, {image, ownerID, status}]) => `<ul class='${breed}'> <li><img src='${image}'/></li> <li class='${ownerID}'></li> <li class='${status}'></li> </ul> ` console.log(toHTML(data))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM