【问题标题】:Populate heading each row in JavaScript在 JavaScript 中填充每一行的标题
【发布时间】:2021-05-14 08:40:55
【问题描述】:

如何在 JavaScript 方法中先填充标题然后再填充行? 我无法控制这些数据,这就是我试图弄清楚如何控制的原因。

我有这些数据:

const list = [{
    'name': 'Display',
    'group': 'Technical details',
    'id': '60',
    'value': 'Something'
  },
  {
    'name': 'Manufacturer',
    'group': 'Manufacturer',
    'id': '58',
    'value': 'Apple'
  },
  {
    'name': 'OS',
    'group': 'Technical details',
    'id': '37',
    'value': 'Apple iOS'
  }
];

有了上面的数据,我想在下面实现这个输出:

<div class="heading">
    <div>Technical details</div>
    <div class="container">
        <div class="row grid">
        <div class="grid-item">
            <div>Display</div>
            <div>Something</div>
        </div>
        <div class="grid-item">
            <div>OS</div>
            <div>Apple iOS</div>
        </div>
        </div>
    </div>
</div>
<div class="heading">
    <div>Manufacturer</div>
    <div class="container">
        <div class="row grid">
            <div class="grid-item">
                <div>Manu</div>
                <div>Apple</div>
            </div>
        </div>
    </div>
</div>

总结问题:我只想先显示标题,然后显示具有相同组值的行。

这是我需要帮助的代码:

function groupBy(collection, property) {
  var i = 0, val, index,
    values = [], result = [];
  for (; i < collection.length; i++) {
    val = collection[i][property];
    index = values.indexOf(val);
    if (index > -1) {
      result[index].push(collection[i]);
    }
    else {
      values.push(val);
      result.push([collection[i]]);
    }
  }
  return result;
}

var obj = groupBy(list, "group");

【问题讨论】:

  • 您是否可以控制list 中包含的数据格式?最好更改该数据结构以更适合您的需求。另外,请将您编写的JS代码添加到问题中,以便我们帮助您调试它。请记住,SO 不是来为您编写代码的。
  • 我已经更新了我的问题。

标签: javascript html jquery for-loop


【解决方案1】:

基本上,您要做的是按group 属性对数据进行分组,然后从中形成一些HTML。

分组很容易,然后只需使用您熟悉的任何语言来构建 html:

const list = [{
    'name': 'Display',
    'group': 'Technical details',
    'id': '60',
    'value': 'Something'
  },
  {
    'name': 'Manufacturer',
    'group': 'Manufacturer',
    'id': '58',
    'value': 'Apple'
  },
  {
    'name': 'OS',
    'group': 'Technical details',
    'id': '37',
    'value': 'Apple iOS'
  }
];

const grouped = list.reduce( (acc,i) => ({
  ...acc,
  [i.group]: (acc[i.group] ? [...acc[i.group], i] : [i])
}),{})

Object.entries(grouped).forEach( ([heading,values]) => {
  console.log(heading)
  values.forEach( ({name,value}) => {
    console.log("\t",name,"=",value)
  })
})

【讨论】:

  • 完美的解决方案,非常感谢您的想法。谢谢。
【解决方案2】:

此解决方案依赖于makeGroups 函数将原始列表重组 为更类似于最终 HTML 结构的对象,以及 createHeading 函数来创建 div 树(针对每个组)包含所需的类和文本内容。

(请参阅代码内的 cmets 以获得进一步的解释。)

const
  mainContainer = document.getElementById("main-container"), // Accesses DOM
  list = getList(), // Gets original list
  groups = makeGroups(list), // Restructers list into groups obj
  groupNames = Object.keys(groups); // Gets array of names

// Makes a ".heading" div for each group and adds it to the DOM
for(let name of groupNames){
  const members = groups[name];
  const headingDiv = createHeading(name, members);
  mainContainer.appendChild(headingDiv);
}


// Builds a div w/ the class "heading", with all its contents
function createHeading(headingName, members){

  // Makes all divs except those for individual member items
  const
    headingDiv = createDiv("", "heading"),
    headingNameDiv = createDiv(headingName),
    containerDiv = createDiv("", "container"),
    rowDiv = createDiv("", "row", "grid");
  headingNameDiv.style.fontWeight = "bold"; // Formats snippet output
  headingDiv.appendChild(headingNameDiv)

  // Makes divs for individual member items and appends them to row
  for(let member of members){
    const itemDiv = createDiv("", "grid-item");
    itemDiv.appendChild(createDiv(member.name));
    itemDiv.appendChild(createDiv(member.value));
    rowDiv.appendChild(itemDiv);
  }
  // Appends everything into the heading div, and returns it
  containerDiv.appendChild(rowDiv);
  headingDiv.appendChild(containerDiv);
  return headingDiv;
}

// Makes an obj where keys are group names, values are memeber objs
function makeGroups(list){
  const groups = {};
  list.forEach(entry => {
    const {group, name, value} = entry;
    if(!groups[group]){ groups[group] = []; }
    groups[group].push({name, value});
  });
  return groups;
}

// Makes a div with optional textContent and any number of classes
function createDiv(content, ...classes){
  const div = document.createElement("div");
  div.textContent = content || "";
  for(let name of classes){
    div.classList.add(name);
  }
  return div;
}

// Gets the original list
function getList(){
  const list = [
    {
      'name': 'Display', // Grid-item 1
      'group': 'Technical details', // Heading
      'id': '60',
      'value': 'Something' // Grid-item 2
    },
    {
      'name': 'Manufacturer',
      'group': 'Manufacturer',
      'id': '58',
      'value': 'Apple'
    },
    {
      'name': 'OS',
      'group': 'Technical details',
      'id': '37',
      'value': 'Apple iOS'
    }
  ];
  return list;
}
.heading{margin-top: 1em; }
.grid-item{ width: 15ch; border: 1px solid lightgrey; }
&lt;div id="main-container"&gt;&lt;/div&gt;

【讨论】:

    【解决方案3】:

    const list = [{
        'name': 'Display',
        'group': 'Technical details',
        'id': '60',
        'value': 'Something'
      },
      {
        'name': 'Manufacturer',
        'group': 'Manufacturer',
        'id': '58',
        'value': 'Apple'
      },
      {
        'name': 'OS',
        'group': 'Technical details',
        'id': '37',
        'value': 'Apple iOS'
      }
    ];
    
    const groupBy = (field, list) => 
      list.reduce((acc, cur) => {
        const { group } = cur
        if (group in acc) acc[group].push(cur)
        else acc[group] = [cur]
        return acc
      }, {})
    
    const App = () => <div>
      {Object.entries(groupBy('group', list)).map(([group, items]) =>
        <div className="heading">
          <div>{ group }</div>
          <div className="container">
            <div className="row grid">
            {items.map(({ name, value }) => 
              <div className="grid-item">
                <div>{name}</div>
                <div>{value}</div>
              </div>)}
            </div>
          </div>
        </div>
      )}
    </div>
    
    ReactDOM.render(<App/>,app)
    <script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
    <div id=app>

    【讨论】:

    • 这个解决方案如何在纯 JavaScript 中工作?
    • 用纯 JS 做这件事很烦人。您必须继续使用 createElement() 和 appendChild() 手动创建元素,并使用 innerText 插入文本,然后将所有内容附加到 DOM。
    • 通常认为包含不属于他们问题的库或框架对 OP 的帮助较小。 (人们经常使用 jQuery 来做这件事,然后 OP 不得不问“好的,但是没有 jQuery 我怎么能做到呢?”。)
    • 完全同意@Cat - 但是在这种情况下,问题标记为jQuery,所以如果你要在答案中包含任何框架,它应该是那个!
    • @Jamiec Totally -- jQuery 只是一个例子,但感谢您指出 jQuery 本身在回答这个特定问题时是受欢迎的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-30
    • 1970-01-01
    • 2016-12-30
    • 2021-03-30
    相关资源
    最近更新 更多