Javascript复杂数组“元素缩减” - 基于数组元素构建HTML表

时间:2009-09-14 05:29:07

标签: javascript html arrays loops html-table

我有一个项目需要以下内容。

将在代码中声明四个数组:

var ROW1 = ['module1'];
var ROW2 = ['module2', 'module3'];
var ROW3 = ['module4', 'module5', 'module6'];
var ROW4 = ['module7', 'module8'];

这些数组的每个元素代表可配置HTML小部件中的模块。根据每个数组中指定的元素,代码将构建一个代表这些“模块”的HTML - 每个“ROWx”数组将是一个表行(),每个模块将是表格中的表格单元格。

ROW1可以为空(在这种情况下它不会包含在HTML中)或者有一个模块“module1”。

ROW2,ROW3和ROW4每个都有0到3个模块(任何模块2 - 模块8,任何顺序)。

使用上面的示例数组,我将以编程方式生成这样的HTML表:

<table>
  <tr id="row1">
    <td colspan="6">[module1]</td>
  </tr>
  <tr id="row2">
    <td colspan="3">[module2]</td>
    <td colspan="3">[module3]</td>
  </tr>
  <tr id="row3">
    <td colspan="2">[module4]</td>
    <td colspan="2">[module5]</td>
    <td colspan="2">[module6]</td>
  </tr>
  <tr id="row4">
    <td colspan="3">[module7]</td>
    <td colspan="3">[module8]</td>
  </tr>
</table>

(colspans就是为了保持正确的表格布局; 6是1,2和3之间的最低公倍数。)

问题是,这些模块的内容是动态填充的(我从AJAX调用到返回JSON对象的URL),并且内容并不总是可用于每个模块。我没有为没有内容的模块创建一个空单元格(),而是希望从布局中完全删除该单元格,就像从未在原始配置中那样(即顶部的数组)。

我已经花了很多时间创建抽象模块创建的代码 - 它根据每行中有多少个模块创建一个“shell”HTML布局,然后将内容附加到相应的表格单元格中模块应该在那里。我希望能够继续使用该代码,所以我认为最好的方法是在构建“shell”之前遍历数组中的每个元素,如果我没有内容,则删除该元素从阵列。然后我可以使用新修改的数组按照惯例构建“shell” - 我基本上只是事先处理它来检查每个模块中的内容,如果没有可用的话,就像那个模块一样从未在初始数组中设置(通过在新数组中删除它然后使用它来构建“shell”)。

例如,假设配置如下:

var ROW1 = ['module1'];
var ROW2 = ['module4', 'module2'];
var ROW3 = ['module5'];
var ROW4 = ['module7', 'module3', 'module8'];

我想浏览每个数组中的每个元素,并检查模块中的可用内容。假设“module3”和“module5”没有可用的内容。我想最终得到这些数组:

var ROW1 = ['module1'];
var ROW2 = ['module4', 'module2'];
var ROW3 = ['module7', 'module8'];

请注意行发生了什么 - 因为“module5”被删除,ROW4数组中的元素被转移到ROW3,然后删除了ROW4。此外,在新的ROW3(以前的ROW4)中,删除了“module3”,将“module8”从位置[2]滑动到位置[1]。

所以:

  • 对于在删除没有任何内容的模块后剩余一个或多个元素的任何行,我想保持该行不变,即使只有一个模块。
  • 对于任何最终没有剩余元素的行,我想将每个连续的行“向上”移动到前一个数组中,基本上将一行拉出并将较低的行向上移动。此示例中的HTML如下所示:

BEFORE(根据配置要求):

<table>
  <tr id="row1">
    <td colspan="6">[module1]</td>
  </tr>
  <tr id="row2">
    <td colspan="3">[module4]</td>
    <td colspan="3">[module2]</td>
  </tr>
  <tr id="row3">
    <td colspan="6">[module5]</td>
  </tr>
  <tr id="row4">
    <td colspan="2">[module7]</td>
    <td colspan="2">[module3]</td>
    <td colspan="2">[module8]</td>
  </tr>
</table>

AFTER(基于实际可用的内容)

<table>
  <tr id="row1">
    <td colspan="6">[module1]</td>
  </tr>
  <tr id="row2">
    <td colspan="3">[module4]</td>
    <td colspan="3">[module2]</td>
  </tr>
  <tr id="row3">
    <td colspan="3">[module7]</td>
    <td colspan="3">[module8]</td>
  </tr>
</table>

回想一下ROW1是一种特殊情况,因为它不会影响其他行。如果内容可用于“module1”(唯一可以进入ROW1的模块),那么ROW1应该保持不变。如果没有可用的内容,则可以删除ROW1,但仍然保留ROW2,ROW3和ROW4(即不将它们各自向上移动一行)。我真的只需要一个处理ROW2,ROW3和ROW4的解决方案,因为ROW1的逻辑非常简单。

我是初学者/中级JavaScript程序员,对数组没有太多经验。我一直在打开和关闭这几个小时,但只是不觉得我想出的是一个强大或优雅/紧凑的方法。

如果任何JavaScript大师可以共享此解决方案,我会非常感激!非常感谢。

1 个答案:

答案 0 :(得分:4)

首先,将行存储在一个数组中,你的ROW1-ROW4会让你头疼。

var ROWS = [
 ['module1'],
 ['module4', 'module2'],
 ['module5'],
 ['module7', 'module3', 'module8']
];

您还想要一种删除元素的方法。 .splice()内置于数组中,可以很好地删除元素。

// lets clear out our disabled modules

var disabledModules = ['module3', 'module5'];

// quick sample function - yours might check for empty content or whatever else...
function isDisabled(module) {  
  for (var i=0, test; test=disabledModules[i]; i++) {
    if (test === module) return true;
  }
  return false;
}

for(var i=0,row; row=ROWS[i]; i++) {
  for (var j=0,module; module=row[j]; j++) {
    // is this module in our disabled modules list?

    if (isDisabled(module)) { // the module is disabled
      row.splice(j,1);
      j--; // so we recheck this point in the array
    }
  }
  if (row.length < 1) {
    // all items were deleted
    ROWS.splice(i,1);
    i--; // so we recheck this point..
  }
}

// ROWS === [["module1"], ["module4", "module2"], ["module7", "module8"]]

您的评论询问了所使用的for循环语法。这是一种非常快速的方法来循环遍历您不知道“假”值的数组。分开一个并打开详细记录:

 for(
  // Part 1 of for loop: Setup, create two variables, i=0, and row.
  var i=0,row; 
  // Part 2: The test - when false, loop will exit, gets executed pre-loop every time
  // Assignment operator returns the value assigned, so row=ROWS[i] will be undefined
  // (false) when we reach then end of the array.
  row=ROWS[i]; 
  // Part 3: Post loop - increment i
  i++) {

使用此方法的危险确实存在,例如,如果它是一个数字数组,并且其中一个数字为0,则循环将提前退出。另一种方法是写:

for(var i=0; i<ROWS.length; i++) { 
  var row = ROWS[i];
}