利用纯 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);
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);
<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>
JS Fiddle demo.
参考资料: