在我深入研究jQuery / Sizzle源码之前,我想我会在这里询问如何加速以下方法。
这是标准的“全部检查”复选框。标题单元格(<thead><tr><th>
)有一个复选框,选中此复选框后会检查位于同一列中的表格tbody
中的所有其他复选框。
这有效:
// We want to check/uncheck all columns in a table when the "select all"
// header checkbox is changed (even if the table/rows/checkboxes were
// added after page load).
(function () {
// use this dummy div so we can reattach our table later.
var dummy = $("<div style=display:none />");
// hook it all up!
body.delegate(".js_checkAll", "change", function () {
// cache selectors as much as possible...
var self = $(this),
// use closest() instead of parent() because
// the checkbox may be in a containing element(s)
cell = self.closest("th"),
// Use "cell" here to make the "closest()" call 1 iteration
// shorter. I wonder if "parent().parent()" would be faster
// (and still safe for use if "thead" is omitted)?
table = cell.closest("table"),
isChecked,
index;
// detaching speeds up the checkbox loop below.
// we have to insert the "dummy" div so we know
// where to put the table back after the loop.
table.before(dummy).detach();
index = cell.index();
isChecked = this.checked;
// I'm sure this chain is slow as molasses
table
// get only _this_ table's tbody
.children("tbody")
// get _this_ table's trs
.children()
// get _this_ table's checkboxes in the specified column
.children(":eq(" + index + ") :checkbox")
// finally...
.each(function () {
this.checked = isChecked;
});
// put the table back and detach the dummy for
// later use
dummy.before(table).detach();
});
} ());
然而,对于250多行,它开始变慢(至少在我的机器上)。用户可能需要最多500行数据,因此分页数据不是解决方案(项目已经被分页@ 500 /页)。
任何想法如何加速它?
答案 0 :(得分:2)
我不会像.children()
那样使用所有这些电话。只需使用.find()
查找复选框,然后检查父母,你会好得多:
table.find('input:checkbox').each(function(_, cb) {
var $cb = $(cb);
if ($cb.parent().index() === index) cb.checked = isChecked;
});
只需使用标记名称('input')调用.find()
,Sizzle就会使用原生getElementsByTagName
(如果不是querySelectorAll
)获取输入,然后过滤通过那些复选框。我真的怀疑它会更快。
如果查找父级索引变得昂贵,您可以随时预先计算并将其存储在父级的.data()
元素中(或者在该复选框的右侧)。
答案 1 :(得分:1)
// I wonder if "parent().parent()" would be faster
// (and still safe for use if "thead" is omitted)?
没有。如果省略<thead>
,则在HTML中将自动添加<tbody>
元素,因为在HTML4中,开始标记和结束标记都是“可选的”。因此,在HTML中,它将是parent().parent().parent()
,但在XHTML-served-as-XML中,它没有作为可选标记的废话,它将是parent().parent()
。
最好坚持使用closest()
。它更清晰,它不是特别慢,而且你只使用它一次,所以它反正并不重要。
index = cell.index();
虽然,每个表只有一次这么不重要, 是一个标准的DOM属性来直接获取表格单元格的索引,这比要求jQuery搜索更快计算以前的兄弟姐妹:index= cell[0].cellIndex
。
// we have to insert the "dummy" div so we know
// where to put the table back after the loop.
这有点难看。标准DOM有一个更好的答案:记住元素的parentNode
和nextSibling
(如果这是最后一个兄弟,可能是null
)当你完成时你可以{{1 }}
parent.insertBefore(table, sibling)
您应该考虑使用 .children("tbody")
.children()
.children(":eq(" + index + ") :checkbox")
.each(function () {
this.checked = isChecked;
});
而不是将其隐藏在选择器中。不会产生大的差异,但它会更清晰。
在任何情况下,你都可以通过使用一些更标准的DOM来遍历表格来保存jQuery的选择器引擎:
.children().eq(index)
选择器查询可以快速,当他们对文档进行操作并仅使用标准CSS选择器时。在这种情况下,jQuery可以将工作传递给浏览器的快速$.each(table[0].tBodies[0].rows, function() {
$(this.cells[index]).find('input[type=checkbox]').each(function() {
this.checked = isChecked;
});
});
方法。但是由于jQuery和Selectors-API之间的分歧超出了它们的意思,并且非标准的Sizzle选择器如{{1},因此无法优化范围选择器(document.querySelectorAll
和find
的第二个参数)。 }和$()
将被拒绝。所以这个:
:eq
在使用:checkbox
的现代浏览器上,实际上可能会更快!