迭代表行中的选择性单元格JavaScript / jQuery

时间:2018-02-05 11:27:21

标签: javascript jquery

我一直有这个问题,我通过其他给定的解决方案无法解决这个问题。

我试图获取表格中每行的某些值。 问题来自一个相当未格式化的表,因此我必须根据其索引或位置获取单元格值。

这是有问题的表格:

<table width="100%">
    <thead>
        <tr>
            <td>Item Description</td>
            <td>Colour</td>
            <td>Size</td>
            <td class="text-right">Price</td>
            <td class="text-right">Qty</td>
            <td class="text-right">Total</td>
        </tr>
    </thead>
    <tbody>
        <tr id="row_24551">
            <td width="40%">Item 1</td>
            <td>Ivory</td>
            <td>10</td>
            <td class="text-right">$ 19.00</td>
            <td class="text-right">1</td>
            <td class="text-right">$ 19.00</td>
        </tr>
        <tr id="row_24550">
            <td width="40%">Item 2</td>
            <td>Grey Marle</td>
            <td>10</td>
            <td class="text-right">$ 18.95</td>
            <td class="text-right">1</td>
            <td class="text-right">$ 18.95</td>
        </tr>
    </tbody>
</table>

我一直在用

获取行值

var table = $('tr[id^="row"]') 由于所需信息位于具有ID的行中。

可以用

输出每个单元格的内容
var table = $('tr[id^="row"]');
table.each(function(){
    console.log('row');
    $.each(this.cells, function(){
        console.log($(this).text());
    });
});

我遇到的问题是我只想要单元格[0,2,4,5]而且我不确定如何通过.each函数进行选择。

对于循环而言,在选择性时对我来说更有意义,但我还没有能够通过行获得单元格的迭代:

var table = $('tr[id^="row"]');
for(i = 0; i < table.length; i++) { 
    console.log("row");
}

也尝试了这个

var table = $('tr[id^="row"]');
for(var i = 0, row; row = table[i]; i++) { 
    console.log("row");
    for (var j = 0, col; col = row[j]; j++) {
        console.log("cell");
    }  
}

但细胞价值似乎没有实现。

最终希望将所需的每个单元格值([0,2,4,5])推送到一个产品数组中,该数组将映射{名称,大小,数量,价格}。但是对细胞的帮助将非常感激!

4 个答案:

答案 0 :(得分:0)

您可以像这样使用单元格的索引:

var table = $('tr[id^="row"]')
var tabCells = {0: "name", 2: "size", 4: "quantity", 5: "price"} //These are the names of the needed cells
var tabRows = []; //This will store the rows data
table.each(function(){
    var tabRow = {}; //This will store the current row data
    $.each(this.cells, function(index){
      if($.inArray(index, [0,2,4,5]) > -1)
        tabRow[tabCells[index]] = $(this).text();
        //e.g: tabRow[tabCells[0]] => tabRow["name"]
    })
    tabRows.push(tabRow);
})

答案 1 :(得分:0)

尝试cellIndex:

var table = $('tr[id^="row"]');
table.each(function() {
    $.each(this.cells, function() {
        if ([0, 2, 4, 5].indexOf(this.cellIndex) > -1) {
            console.log($(this).text());
        }
    });
});

答案 2 :(得分:0)

以下是仅使用JavaScript的解决方案。如果您需要支持旧浏览器,那么我可以重写它。

var rows = document.querySelectorAll('tr[id^="row"]');

//const rowArray = Array.from(rows);
var rowArray = Array.prototype.slice.call(rows);

var products = rowArray.reduce((sum, element) => {
    var children = element.children;
    var name = children[0].innerHTML;
    var size = children[2].innerHTML;
    var quantity = children[4].innerHTML;
    var prize = children[5].innerHTML;
    var newElement = {name: name, size: size, quantity: quantity, prize: prize};
    sum.push(newElement);
    return sum;
},[]);

console.log(products);
// [{name: "Item 1", size: "10", quantity: "1", prize: "$ 19.00"},
// {name: "Item 2", size: "10", quantity: "1", prize: "$ 18.95"}]

答案 3 :(得分:0)

利用纯JavaScript,虽然这确实需要相对最新的浏览器,但我还是建议采用以下方法:

function collateDataByIndices(opts) {
  // settings, used to define some defaults for the function,
  // passing in the opts Object allows those defaults to be
  // overridden.


  // 'table':              DOM Node, HTMLTableElement,
  // 'indices :            Array of numbers, the indices of which
  //                       cells from which you wish to obtain data,
  // 'rowIndexStartAt :    Number, the rowIndex at which you
  //                       wish to start collecting data.
  // 'tableHeadRowIndex' : the row index of the column
  //                       headings,
  // 'namedByTable':       Uses the table's column headings
  //                       to identify the data in the returned
  //                       Array of Objects,
  // 'keys':               Array of Strings, if you wish to use
  //                       different keys to identify the data
  //                       in the returned Array of Objects.
  let settings = {
    'table': document.querySelector('table'),
    'indices': null,
    'rowIndexStartAt': 1,
    'tableHeadRowIndex': 0,
    'namedByTable': true,
    'keys': false
  };

  // here we use the Object.keys() method to retrieve an array
  // of the keys from the supplied 'opts' Object (or an empty
  // Object, to avoid errors being thrown if 'opts' is not supplied):
  Object.keys(opts || {}).forEach(

    // we then use Array.prototype.forEach() to iterate over each
    // key of the opts Object (if supplied), and update the
    // settings Object so that supplied options override the
    // defaults:
    key => settings[key] = opts[key]
  );

  // if we have no indices supplied, or the length of the supplied
  // Array of indices is 0 (although '!settings.indices.length'
  // would also work, as 0 is a falsey value):
  if (!settings.indices || settings.indices.length === 0) {

    // we retrieve the cells of the HTMLTableElement's first
    // row, and use Array.from() to convert that HTMLCollection
    // into an Array (note this is a naive check, since cells
    // that use a `colspan` attribute may cause inaccurate cell
    // counts ('columns') to be retrieved):
    settings.indices = Array.from(
      settings.table.rows[0].cells

    // we then use Array.prototype.map(), along with an Arrow
    // function:
    ).map(

      // here we pass both 'cell' (the current cell of the
      // Array of cells over which we're iterating) and the
      // 'index' of that cell in the Array to the function,
      // and simply return the index to create an Array of
      // all indices (there is almost certainly a better way
      // to do this):
      (cell, index) => index
    );
  }

  // here we retrieve the <tr> elements, using document.querySelectorAll(),
  // and use Array.from() to convert that NodeList into an Array of element
  // nodes:
  let rows = Array.from(
      settings.table.querySelectorAll('tr')

    // we then slice that collection from the supplied, or default,
    // settings.rowIndexStartAt to retrieve the relevant subset of
    // rows (note that this remains naive, since there's no check
    // that such an argument is supplied or available):
    ).slice(
      settings.rowIndexStartAt

    // we then use Array.prototype.map() on the Array returned from
    // Array.prototype.slice():
    ).map(

      // here we pass 'row' (the current HTMLTableRowElement of the
      // Array of HTMLTableRowElement nodes over which we're iterating)
      // to the Arrow function; in which create an Array of that row's
      // children (child elements) and filter that collection of children
      // using Array.prototype.filter():
      row => Array.from(row.children).filter(

        // here we pass both 'cell' (the current cell of the Array of
        // cells), and the'index' of that cell from the collection;
        // we then use Array.prototype.indexOf() to determine if the
        // current cell's index is in the Array of indices we wish to
        // keep. Array.prototype.indexOf() returns the index of the
        // supplied value if it was found, and -1 if it was not found;
        // therefore any returned index greater than -1 means the
        // supplied value was found, and should be kept in the filtered
        // Array:
        (cell, index) => settings.indices.indexOf(index) > -1
      )
    ),
    keyNames, headingSource, headings;

  // if an Array of keys were supplied, in order to assign custom
  // keys/names to identify the retrieved values/data:
  if (settings.keys && settings.keys.length > 0) {

    // keyNames is equal to the supplied keys:
    keyNames = settings.keys;

  // otherwise, if settings.namedByTable is (Boolean) true:
  } else if (settings.namedByTable === true) {

    // ...and settings.tableHeadRowIndex, parsed as a base-ten
    // integer, is equal-to or greater-than zero (zero is itself
    // a falsey value, so must be explicitly tested for):
    if (parseInt(settings.tableHeadRowIndex, 10) >= 0) {

      // we retrieve the settings.table HTMLTableElement:
      headingSource = settings.table
        // and retrieve the HTMLTableRowElement at the
        // index supplied in the settings.tableHeadRowIndex
        // argument:
        .rows[ settings.tableHeadRowIndex ]
        // and retrieve its child elements:
        .children;

    // otherwise, if the HTMLTableElement has a non-zero number of
    // <th> elements within a <thead> element:
    } else if (settings.table.querySelectorAll('thead th').length) {

      // we retrieve those elements:
      headingSource = settings.table.querySelectorAll('thead th')

    // otherwise, if the HTMLTableElement has a non-zero number of
    // <td> elements within a <thead> element:
    } else if (settings.table.querySelectorAll('thead td').length) {

      // we retrieve those elements:
      headingSource = settings.table.querySelectorAll('thead td')

    // otherwise, if the parsed integer of settings.rowIndexStartAt
    // in base-ten, is greater than zero:
    } else if (parseInt(settings.rowIndexStartAt, 10) > 0) {

      // we retrieve the HTMLTableRowElement at the index before the
      // the settings.rowIndexStartAt variable:
      headingSource = settings.table.rows[
        settings.rowIndexStartAt - 1 
      // and retrieve its child elements:
      ].children;
    }

    // here we convert the array-like headingSource variable
    // into an explicit Array (using Array.from):
    keyNames = Array.from(headingSource)
      // and then use Array.prototype.filter() to filter that
      // Array using an Arrow function:
      .filter(
        // here we do as we did earlier, and retain only those
        // elements whose index is found in the settings.indices
        // Array:
        (header, index) => settings.indices.indexOf(index) > -1

    // we then use Array.prototype.map() on the filtered Array:
    ).map(

      // and modify the Array to contain the trimmed text-content
      // of each cell:
      header => header.textContent.trim()
    )

  // otherwise:
  } else {

    // we simply use the numeric indices (if names cannot be found,
    // or appear to be unwanted):
    keyNames = settings.indices;
  }

  // here we iterate over the Array of HTMLTableRowElements:
  return rows.map(

    // pass the current row of the Array of rows:
           // here we reduce the current HTMLTableRowElement
           // and convert that array-like collection into an
           // Array:
    row => Array.from(row)

      // reducing the Array in order to convert it to an Object:
      .reduce(function(accumulator, current, index) {
        // the accumulator is the Object literal supplied after
        // this anonymous function; and we set the key to identify
        // the current value (from the keyNames Array) to be the
        // key located at the same index as the current cell; and
        // we supply the textContent of the current cell as the
        // value associated with that key:
        accumulator[keyNames[index]] = current.textContent;

      // here we return the accumulator:
      return accumulator;
    }, {})
  );
}

let found = collateDataByIndices({
  indices: [0, 2, 4, 5]
});

console.log(found);

&#13;
&#13;
function collateDataByIndices(opts) {
  let settings = {
    'table': document.querySelector('table'),
    'indices': null,
    'rowIndexStartAt': 1,
    'tableHeadRowIndex': 0,
    'namedByTable': true,
    'keys': false
  };

  Object.keys(opts || {}).forEach(
    key => settings[key] = opts[key]
  );

  if (!settings.indices || settings.indices.length === 0) {
    settings.indices = Array.from(
      settings.table.rows[0].cells
    ).map(
      (cell, index) => index
    );
  }

  let rows = Array.from(
      settings.table.querySelectorAll('tr')
    ).slice(
      settings.rowIndexStartAt
    ).map(
      row => Array.from(row.children).filter(
        (cell, index) => settings.indices.indexOf(index) > -1
      )
    ),
    keyNames, headingSource, headings;

  if (settings.keys && settings.keys.length > 0) {
    keyNames = settings.keys;
  } else if (settings.namedByTable === true) {
    if (parseInt(settings.tableHeadRowIndex, 10) >= 0) {
      headingSource = settings.table.rows[settings.tableHeadRowIndex].children
    } else if (settings.table.querySelectorAll('thead th').length) {
      headingSource = settings.table.querySelectorAll('thead th')
    } else if (settings.table.querySelectorAll('thead td').length) {
      headingSource = settings.table.querySelectorAll('thead td')
    } else if (parseInt(settings.rowIndexStartAt, 10) > 0) {
      headingSource = settings.table.rows[settings.rowIndexStartAt - 1].children;
    }

    keyNames = Array.from(headingSource).filter(
      (header, index) => settings.indices.indexOf(index) > -1
    ).map(
      header => header.textContent.trim()
    )

  } else {
    keyNames = settings.indices;
  }


  return rows.map(
    row => Array.from(row).reduce(function(accumulator, current, index) {
      accumulator[keyNames[index]] = current.textContent;
      return accumulator;
    }, {})
  );
}

let found = collateDataByIndices({
  indices: [0, 2, 4, 5]
});

console.log(found);
&#13;
<table width="100%">
  <thead>
    <tr>
      <td>Item Description</td>
      <td>Colour</td>
      <td>Size</td>
      <td class="text-right">Price</td>
      <td class="text-right">Qty</td>
      <td class="text-right">Total</td>
    </tr>
  </thead>
  <tbody>
    <tr id="row_24551">
      <td width="40%">Item 1</td>
      <td>Ivory</td>
      <td>10</td>
      <td class="text-right">$ 19.00</td>
      <td class="text-right">1</td>
      <td class="text-right">$ 19.00</td>
    </tr>
    <tr id="row_24550">
      <td width="40%">Item 2</td>
      <td>Grey Marle</td>
      <td>10</td>
      <td class="text-right">$ 18.95</td>
      <td class="text-right">1</td>
      <td class="text-right">$ 18.95</td>
    </tr>
  </tbody>
</table>
&#13;
&#13;
&#13;

JS Fiddle demo

参考文献: