Javascript - 对象循环和HTML中的组织数据

时间:2018-02-17 08:28:55

标签: javascript html json loops recursion

我正在尝试递归循环对象并在HTML中以有组织的方式输出数据。下面是我到目前为止,但我目前卡住了,因为我只能输出行而不是缩进级别。 preview元素中的样本数据是我正在尝试做的输出表示。

此外,如果有更好的方式来组织/构建数据(通过分组或类似),我将不胜感激。

var obj = {
    0: {
        "Shirts": 0,
        "Jeans": 1,
        "Brand": "Lorem ipsum"
    },
    1: {
        "Color": {
            "blue" : 1,
            "red" : 0
        },
        "Size": {
            "Man": {
                "small": 1,
                "medium": 0,
                "large": 0
            },
            "Women": {
                "small": 1,
                "medium": 1,
                "large": 1
            }
        }
    },
    2: {
        "Shipping": {
            "overNight": "$ 10",
            "3 days": "$ 4"
        }
    },
    3: {
        "Stock": {
            "Man": [
                {
                    "green jeans": 13,
                    "green shirts": 17,
                    "green shoes": 21
                },
                {
                    "black jeans": 1,
                    "black shirts": 12,
                    "black shoes": 53
                }
            ],
            "Women": [
                {
                    "green jeans": 2,
                    "green shirts": 53,
                    "green shoes": 11
                },
                {
                    "black jeans": 6,
                    "black shirts": 22,
                    "black shoes": 29
                }
            ]
        }
    }
}

var dataEl = document.getElementById('data');

var getProperties = function (obj) {
  for (var property in obj) {

    if (!obj.hasOwnProperty(property)) continue;

    if (obj.hasOwnProperty(property) && obj[property] !== null) {

      if (obj[property].constructor == Object) {
      
        dataEl.innerHTML += '<div class="row title">' + property + '</div>';
        getProperties(obj[property])
        
      } else if (obj[property].constructor == Array) {
        dataEl.innerHTML += '<div class="row title">' + property + '</div>';
        
        for (var i = 0; i < obj[property].length; i++) {
          getProperties(obj[property][i]);
        }
        
      } else {
      
        dataEl.innerHTML += '<div class="row"><span>' + property +'</span>: ' + obj[property] + '</div>';
        
      }

    }
  }
}
//getProperties(obj);
#data,
#preview {
  display: block;
  width: 80%;
  font-size: 12px;
  font-family: Arial, Helvetica;
  padding: 10px;
}
#data .row,
#preview .row {
  display: inline-block;
  width: 100%;
  margin-bottom: 2px;
}
#data .row.title,
#preview .row.title {
  font-weight: bold;
  font-size: 14px;
}
#data .row.indent-1,
#preview .row.indent-1 {
  padding-left: 20px;
}
#data .row.indent-2,
#preview .row.indent-2 {
  padding-left: 40px;
}
<div id="data"></div>

<!-- This is how it should be structured -->
<div id="preview">

  <div class="row"><span>Shirts:</span>0</div>
  <div class="row"><span>Jeans:</span>1</div>
  <div class="row"><span>Brand:</span>Lorem ipsum</div>
  
  <div class="row title">Color</div>
  <div class="row indent-1"><span>blue:</span> 1</div>
  <div class="row indent-1"><span>red:</span> 0</div>
  
  <div class="row title">Size</div>
  <div class="row title indent-1">Man</div>
  <div class="row indent-2"><span>small:</span> 1</div>
  <div class="row indent-2"><span>medium:</span> 0</div>
  <div class="row indent-2"><span>large:</span> 0</div>
  <div class="row title indent-1">Women</div>
  <div class="row indent-2"><span>small:</span> 1</div>
  <div class="row indent-2"><span>medium:</span> 1</div>
  <div class="row indent-2"><span>large:</span> 1</div>
  
  <div class="row title">Shipping</div>
  <div class="row indent-1"><span>overNight:</span> $ 10</div>
  <div class="row indent-1"><span>3 days:</span> $ 4</div>
  
  <div class="row title">Stock</div>
  <div class="row title indent-1">Man</div>
  <div class="row indent-2"><span>green jeans:</span> 13</div>
  <div class="row indent-2"><span>green shirts:</span> 17</div>
  <div class="row indent-2"><span>green shoes:</span> 21</div>
  <div class="row indent-2"><span>black jeans:</span> 1</div>
  <div class="row indent-2"><span>black shirts:</span> 127</div>
  <div class="row indent-2"><span>black shoes:</span> 53</div>
  <div class="row title indent-1">Women</div>
  <div class="row indent-2"><span>green jeans:</span> 2</div>
  <div class="row indent-2"><span>green shirts:</span> 53</div>
  <div class="row indent-2"><span>green shoes:</span> 11</div>
  <div class="row indent-2"><span>black jeans:</span> 6</div>
  <div class="row indent-2"><span>black shirts:</span> 22</div>
  <div class="row indent-2"><span>black shoes:</span> 29</div>
  
</div>

1 个答案:

答案 0 :(得分:2)

当您使用html构造的递归函数时,不是将结果字符串直接附加到元素中,而是将其存储到变量&amp;在函数完成后返回它,这使得将结果更容易封装在分组元素中 - 请参阅与源对象兼容的示例方法:

function getProperties(obj, depth) {
  depth = depth === undefined ? 0 : depth + 1;
  var html = '';

  // first handle arrays
  if (obj && obj.forEach) {
    html += '<div class="list" data-indent="' + depth + '">';
    obj.forEach(function (elems, index) {
      html += '<div class="item ' + (index % 2 ? 'even' : 'odd') + '" data-index"' + index + '">'
        + getProperties(elems, depth)
        + '</div>';
    });
    html += '</div>';
  }
  // the main block (comes after arrays as an array would pass this condition too)
  else if (obj && typeof obj === 'object') {
    // uncomment if you'd like the whole group enclosed in a parent:
    // if (depth === 0) html += '<div class="group">';
    Object.keys(obj).forEach(function (key) {
      html += '<div class="row" data-indent="' + depth + '">';
      if (depth > 0)
        html += '<span class="title">' + key + '</span>'
      html += getProperties(obj[key], depth)
      html += '</div>';
    });
    // if (depth === 0) html += '</div>';
  }
  // else the object is just a value
  else {
    html += '<span class="value">' + obj + '</span>';
  }

  return html;
}

document.getElementById('data').innerHTML = getProperties(obj);

您可以看到内部迭代(forEach调用)我只是将另一个getProperties调用的结果附加到结果字符串(html变量)。

另一个优点是你不会搞&&#34;全球状态&#34; (#data元素的innerHTML),因此无论元素的内容是什么,函数总是返回相同的结果 - 这就是所谓的函数方法。

如上所述,嵌套元素包含在父元素中,这使得缩进更容易 - 只需在父元素上设置margin-left(参见下面的CSS)。

我用迭代函数(forEach)替换for循环以获得更多功能样式,并且在数组的情况下防止引入中间变量(i),但它只是一个问题偏好;使用特征检测时,条件也有点不同(对象是否具有我将要使用的功能,例如forEach?)Object.keys可以使用在object类型的任何对象上(这是为什么数组resp。forEach检测之前出现,数组也是object类型)并且不建议检查构造函数因为它可以被自定义覆盖。

我还添加了depthdata-indent属性的内容,这里没有任何意义,但你可能会以某种方式使用它)&amp;由数组迭代产生的组的奇数/偶数类,我认为这些都是不言自明的。

我改变了css类,试图让它更具上下文意义,使用这个css应该说清楚:

.row {
  margin-left: 10px;
}
.title {
  font-weight: bold;
}
.value {
  padding-left: 10px;
}
.list .odd {
  background-color: lightgray;
}
/* just to see how to target a custom attribute */
[data-indent="3"] {
  color: red;
}

(需要自定义属性的data-前缀才能使其符合HTML验证程序。)