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

如何遍历值为数组的嵌套对象并实现手风琴式展示?

动态手风琴组件实现方案

需求说明

有一个嵌套对象,其键为动态名称(如“Product Details”“_General”),对应的值是属性数组。需要遍历该对象,将每个键作为手风琴组件的标题,同时遍历对应数组元素,把属性的label和value展示为手风琴内容。

示例数据:

{
  "Product Details": [
    {"attribute_code": "type2","label": "Variant / Model","value": "100 4jet Vario"}
  ],
  "_General": [
    {"attribute_code": "designer","label": "Design by","value": "Hansgrohe"},
    {"attribute_code": "delivery_time","label": "Delivery Time","value": "on stock"}
  ],
  "_Characteristics": [
    {"attribute_code": "shape_outside","label": "Shape","value": "round"},
    {"attribute_code": "water_heater","label": "Water heater","value": "suitable for instantaneous water heaters"}
  ],
  "_Color-Material-Surface": [
    {"attribute_code": "material","label": "Material","value": "metal / plastic"}
  ]
}

实现方案

1. 原生JavaScript实现

无需框架,直接用HTML+CSS+JS实现:

<!DOCTYPE html>
<html>
<head>
  <style>
    .accordion {
      width: 100%;
      max-width: 600px;
      margin: 20px auto;
    }
    .accordion-item {
      border: 1px solid #ddd;
      margin-bottom: 10px;
    }
    .accordion-header {
      background-color: #f5f5f5;
      padding: 15px;
      cursor: pointer;
      font-weight: bold;
      display: flex;
      justify-content: space-between;
      align-items: center;
    }
    .accordion-content {
      padding: 15px;
      display: none;
    }
    .accordion-content.active {
      display: block;
    }
    .attribute-item {
      margin-bottom: 8px;
      display: flex;
      justify-content: space-between;
    }
    .attribute-label {
      color: #555;
    }
    .attribute-value {
      font-weight: 500;
    }
  </style>
</head>
<body>
  <div class="accordion" id="productAccordion"></div>

  <script>
    const productData = {
      "Product Details": [{"attribute_code": "type2","label": "Variant / Model","value": "100 4jet Vario"}],
      "_General": [{"attribute_code": "designer","label": "Design by","value": "Hansgrohe"},{"attribute_code": "delivery_time","label": "Delivery Time","value": "on stock"}],
      "_Characteristics": [{"attribute_code": "shape_outside","label": "Shape","value": "round"},{"attribute_code": "water_heater","label": "Water heater","value": "suitable for instantaneous water heaters"}],
      "_Color-Material-Surface": [{"attribute_code": "material","label": "Material","value": "metal / plastic"}]
    };

    const accordionContainer = document.getElementById('productAccordion');

    Object.entries(productData).forEach(([title, attributes]) => {
      const accordionItem = document.createElement('div');
      accordionItem.className = 'accordion-item';

      const header = document.createElement('div');
      header.className = 'accordion-header';
      header.textContent = title.replace(/^_/, '');
      header.innerHTML += ' <span>▼</span>';

      const content = document.createElement('div');
      content.className = 'accordion-content';

      attributes.forEach(attr => {
        const attrItem = document.createElement('div');
        attrItem.className = 'attribute-item';
        attrItem.innerHTML = `
          <span class="attribute-label">${attr.label}:</span>
          <span class="attribute-value">${attr.value}</span>
        `;
        content.appendChild(attrItem);
      });

      header.addEventListener('click', () => {
        content.classList.toggle('active');
        header.querySelector('span').textContent = content.classList.contains('active') ? '▲' : '▼';
      });

      accordionItem.appendChild(header);
      accordionItem.appendChild(content);
      accordionContainer.appendChild(accordionItem);
    });
  </script>
</body>
</html>

2. Vue 3 实现

<template>
  <div class="accordion">
    <div v-for="(attributes, title) in productData" :key="title" class="accordion-item">
      <div class="accordion-header" @click="toggleAccordion(title)">
        {{ title.replace(/^_/, '') }}
        <span>{{ activeAccordion === title ? '▲' : '▼' }}</span>
      </div>
      <div class="accordion-content" :class="{ active: activeAccordion === title }">
        <div v-for="attr in attributes" :key="attr.attribute_code" class="attribute-item">
          <span class="attribute-label">{{ attr.label }}:</span>
          <span class="attribute-value">{{ attr.value }}</span>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const productData = ref({
  "Product Details": [{"attribute_code": "type2","label": "Variant / Model","value": "100 4jet Vario"}],
  "_General": [{"attribute_code": "designer","label": "Design by","value": "Hansgrohe"},{"attribute_code": "delivery_time","label": "Delivery Time","value": "on stock"}],
  "_Characteristics": [{"attribute_code": "shape_outside","label": "Shape","value": "round"},{"attribute_code": "water_heater","label": "Water heater","value": "suitable for instantaneous water heaters"}],
  "_Color-Material-Surface": [{"attribute_code": "material","label": "Material","value": "metal / plastic"}]
});

const activeAccordion = ref(null);

const toggleAccordion = (title) => {
  activeAccordion.value = activeAccordion.value === title ? null : title;
};
</script>

<style scoped>
.accordion {
  width: 100%;
  max-width: 600px;
  margin: 20px auto;
}
.accordion-item {
  border: 1px solid #ddd;
  margin-bottom: 10px;
}
.accordion-header {
  background-color: #f5f5f5;
  padding: 15px;
  cursor: pointer;
  font-weight: bold;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.accordion-content {
  padding: 15px;
  display: none;
}
.accordion-content.active {
  display: block;
}
.attribute-item {
  margin-bottom: 8px;
  display: flex;
  justify-content: space-between;
}
.attribute-label {
  color: #555;
}
.attribute-value {
  font-weight: 500;
}
</style>

3. React 实现

import { useState } from 'react';

const ProductAccordion = () => {
  const productData = {
    "Product Details": [{"attribute_code": "type2","label": "Variant / Model","value": "100 4jet Vario"}],
    "_General": [{"attribute_code": "designer","label": "Design by","value": "Hansgrohe"},{"attribute_code": "delivery_time","label": "Delivery Time","value": "on stock"}],
    "_Characteristics": [{"attribute_code": "shape_outside","label": "Shape","value": "round"},{"attribute_code": "water_heater","label": "Water heater","value": "suitable for instantaneous water heaters"}],
    "_Color-Material-Surface": [{"attribute_code": "material","label": "Material","value": "metal / plastic"}]
  };

  const [activeTitle, setActiveTitle] = useState(null);

  const toggleAccordion = (title) => {
    setActiveTitle(activeTitle === title ? null : title);
  };

  return (
    <div className="accordion">
      {Object.entries(productData).map(([title, attributes]) => (
        <div key={title} className="accordion-item">
          <div 
            className="accordion-header"
            onClick={() => toggleAccordion(title)}
          >
            {title.replace(/^_/, '')}
            <span>{activeTitle === title ? '▲' : '▼'}</span>
          </div>
          <div 
            className={`accordion-content ${activeTitle === title ? 'active' : ''}`}
          >
            {attributes.map(attr => (
              <div key={attr.attribute_code} className="attribute-item">
                <span className="attribute-label">{attr.label}:</span>
                <span className="attribute-value">{attr.value}</span>
              </div>
            ))}
          </div>
        </div>
      ))}
    </div>
  );
};

export default ProductAccordion;

对应CSS(单独文件引入):

.accordion {
  width: 100%;
  max-width: 600px;
  margin: 20px auto;
}
.accordion-item {
  border: 1px solid #ddd;
  margin-bottom: 10px;
}
.accordion-header {
  background-color: #f5f5f5;
  padding: 15px;
  cursor: pointer;
  font-weight: bold;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.accordion-content {
  padding: 15px;
  display: none;
}
.accordion-content.active {
  display: block;
}
.attribute-item {
  margin-bottom: 8px;
  display: flex;
  justify-content: space-between;
}
.attribute-label {
  color: #555;
}
.attribute-value {
  font-weight: 500;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 08:45:12