如何使用纯Javascript过滤非常大的引导表
我已经在bootstrap中构建了一个大表,大约5000行x 10列,我需要快速过滤表中的特定属性,只使用JavaScript。该表同时具有id列和属性列,即如何使用纯Javascript过滤非常大的引导表,javascript,twitter-bootstrap,dom,infinite-scroll,Javascript,Twitter Bootstrap,Dom,Infinite Scroll,我已经在bootstrap中构建了一个大表,大约5000行x 10列,我需要快速过滤表中的特定属性,只使用JavaScript。该表同时具有id列和属性列,即 id | attr | ... --------------- 2 | X | ... 3 | Y | ... 4 | X | ... 为了加快过滤过程,我构建了一个哈希表,将属性映射回列ID。例如,我有一个映射: getRowIds["X"] = [2,4] 用户可以在搜索框中输入属性“X”,然后哈希表查找包
id | attr | ...
---------------
2 | X | ...
3 | Y | ...
4 | X | ...
为了加快过滤过程,我构建了一个哈希表,将属性映射回列ID。例如,我有一个映射:
getRowIds["X"] = [2,4]
用户可以在搜索框中输入属性“X”,然后哈希表查找包含“X”的对应行(本例中为2和4),然后通过映射操作调用以下函数:
this.hideRow = function(id) {
document.getElementById(id).style.display="none"
}
this.showRow = function(id) {
document.getElementById(id).style.display=""
}
这个过程仍然相当缓慢,因为允许用户选择多个属性(比如X,Y)
有没有更快的方法隐藏行
如果我能以某种方式将表从DOM中分离出来,进行更改,然后重新连接,会更快吗?如何在javascript中实现这一点
还有其他更有效/更智能的过滤方法吗
谢谢:)我想问一下
- 为什么要为自己编写此代码?从个人经验来看,尝试在所有浏览器上高效过滤是一项不平凡的任务
- 若您将此作为一种学习体验,请查看下面列出的软件包的来源作为示例
- 对于5000行,进行服务器端筛选和排序会更有效。然后使用ajax更新显示的表
- -这是一个功能非常全面的软件包,可处理客户端和服务器端的筛选和排序
- -是一个轻量级客户端筛选和排序包
// Represents each row in our table
function MyModelKlass(attributes) {
this.attributes = attributes;
}
// Represents our table
function CollectionKlass() {
this.children = [];
this.visibleChildren = [];
this.limit = 50;
}
CollectionKlass.prototype = {
// accepts a callback to determine if things are in or out
filter: function(callback) {
// filter doesn't work in every browser
// you can loop manually or user underscorejs
var filteredObjects = this.children.filter(callback);
this.visibleChildren = filteredObjects;
this.filteredChildren = filteredObjects;
this.showPage(0);
},
showPage: function(pageNumber) {
// TODO: account for index out of bounds
this.visibleChildren = this.filteredChildren.slice(
pageNumber * this.limit,
(pageNumber + 1) * this.limit
);
},
// Another example mechanism, comparator is a function
// sort is standard array sorting in JS
sort: function(comparator) {
this.children.sort(comparator);
}
}
function render(el, collection, templateContent) {
// this part is hard due to XSS
// you need to sanitize all data being written or
// use a templating language. I'll opt for
// handlebars style templating for this example.
//
// If you opt for no template then you need to do a few things.
// Write then read all your text to a detached DOM element to sanitize
// Create a detached table element and append new elements to it
// with the sanitized data. Once you're done assembling attach the
// element into the DOM. By attach I mean 'appendChild'.
// That turns out to be mostly safe but pretty slow.
//
// I'll leave the decisions up to you.
var template = Handlebars.compile(templateContent);
el.innerHTML(template(collection));
}
// Lets init now, create a collection and some rows
var myCollection = new CollectionKlass();
myCollection.children.push(new MyModelKlass({ 'a': 1 }));
myCollection.children.push(new MyModelKlass({ 'a': 2 }));
// filter on something...
myCollection.filter(function(child) {
if (child.attributes.a === 1) {
return false;
}
return true;
});
// this will throw an out of bounds error right now
// myCollection.showPage(2);
// render myCollection in some element for some template
render(
document.getElementById('some-container-for-the-table'),
myCollection,
document.getElementById('my-template').innerHTML()
);
// In the HTML:
<script type="text/x-handlebars-template" id="my-template">
<ul>
{{#each visibleChildren}}
<li>{{a}}</li>
{{/each}}
</ul>
</script>
//表示表中的每一行
函数MyModelKlass(属性){
this.attributes=属性;
}
//代表我们的桌子
函数集合Klass(){
这是:children=[];
this.visibleChildren=[];
这个极限=50;
}
CollectionKlass.prototype={
//接受回调以确定事物是进入还是退出
过滤器:函数(回调){
//过滤器在每个浏览器中都不起作用
//您可以手动循环或使用下划线进行循环
var filteredObjects=this.children.filter(回调);
this.visibleChildren=过滤对象;
this.filteredChildren=filteredObjects;
此.showPage(0);
},
显示页面:功能(页码){
//TODO:说明索引超出范围
this.visibleChildren=this.filteredChildren.slice(
页码*这是一个限制,
(页码+1)*此限制
);
},
//另一个示例机制,比较器是一个函数
//排序是JS中的标准数组排序
排序:函数(比较器){
this.children.sort(比较器);
}
}
函数呈现(el、集合、模板内容){
//由于XSS的原因,这部分比较难
//您需要清理正在写入或删除的所有数据
//使用模板语言。我会选择
//此示例中的把手样式模板。
//
//如果您选择无模板,那么您需要做一些事情。
//将所有文本写入然后读取到分离的DOM元素以进行清理
//创建分离的表元素并向其附加新元素
//使用经过清理的数据。组装完成后,连接
//元素添加到DOM中。我指的是“appendChild”。
//结果证明,这是最安全的,但相当缓慢。
//
//我将把决定权留给你。
var template=handlebar.compile(templateContent);
el.innerHTML(模板(集合));
}
//现在让我们初始化,创建一个集合和一些行
var myCollection=new CollectionKlass();
myCollection.children.push(新的MyModelKlass({'a':1}));
myCollection.children.push(新的MyModelKlass({'a':2}));
//过滤某些东西。。。
myCollection.filter(函数(子级){
if(child.attributes.a==1){
返回false;
}
返回true;
});
//这将立即抛出一个越界错误
//myCollection.showPage(2);
//在某个模板的某个元素中呈现myCollection
渲染(
document.getElementById('some-container-for-the-table'),
我收集,
document.getElementById('my-template').innerHTML()
);
//在HTML中:
{{#每个可访问的儿童}
- {{a}
{{/每个}}
请参阅链接,它可能会有所帮助,唯一的问题是它不在纯javascript中,它也使用angularjs
app.service("NameService", function($http, $filter){
function filterData(data, filter){
return $filter('filter')(data, filter)
}
function orderData(data, params){
return params.sorting() ? $filter('orderBy')(data, params.orderBy()) : filteredData;
}
function sliceData(data, params){
return data.slice((params.page() - 1) * params.count(), params.page() * params.count())
}
function transformData(data,filter,params){
return sliceData( orderData( filterData(data,filter), params ), params);
}
var service = {
cachedData:[],
getData:function($defer, params, filter){
if(service.cachedData.length>0){
console.log("using cached data")
var filteredData = filterData(service.cachedData,filter);
var transformedData = sliceData(orderData(filteredData,params),params);
params.total(filteredData.length)
$defer.resolve(transformedData);
}
else{
console.log("fetching data")
$http.get("data.json").success(function(resp)
{
angular.copy(resp,service.cachedData)
params.total(resp.length)
var filteredData = $filter('filter')(resp, filter);
var transformedData = transformData(resp,filter,params)
$defer.resolve(transformedData);
});
}
}
};
return service;
});
使用确实是个好主意,
这使我们可以将您的行渲染为
<tr ng-repeat="row in rowArray">
<td>{{row.id}}</td>
<td>{{row.attr}}</td>
</tr>
话虽如此,向数组中抛出5K行显然是一个性能阻力。这将在你的眉毛中创建一个巨大的HTML
<tr ng-repeat="row in rowArray | yourCustomFilter:parameters">
<td>{{row.id}}</td>
<td>{{row.attr}}</td>
</tr>
document.getElementById(id).style.display="none"
hash[id] = document.getElementById(id).style.display
hash[id] = 'none'
hash[id] = 'block'
elem[id] = $('<tr>' +
'<td>' + id + '</td>' +
'<td>' + attr + '</td>' +
</tr>');
display[id] = elem[id].style.display;
elementArray = [rowElement1, ..., rowElementN]
var htmlToAppend = elementArray.join('');
parentElement.append(htmlToAppend);
addFilter(yourTable, 2, ['X','Y']);
function SearchRecordsInTable(searchBoxId, tableId) {
var searchText = document.getElementById(searchBoxId).value;
searchText = searchText.toLowerCase();
var targetTable = document.getElementById(tableId);
var targetTableColCount;
//Loop through table rows
for (var rowIndex = 0; rowIndex < targetTable.rows.length; rowIndex++) {
var rowData = '';
//Get column count from header row
if (rowIndex == 0) {
targetTableColCount = targetTable.rows.item(rowIndex).cells.length;
continue; //do not execute further code for header row.
}
//Process data rows. (rowIndex >= 1)
for (var colIndex = 0; colIndex < targetTableColCount; colIndex++) {
rowData += targetTable.rows.item(rowIndex).cells.item(colIndex).textContent;
rowData = rowData.toLowerCase();
}
console.log(rowData);
//If search term is not found in row data
//then hide the row, else show
if (rowData.indexOf(searchText) == -1)
targetTable.rows.item(rowIndex).style.display = 'none';
else
targetTable.rows.item(rowIndex).style.display = '';
}
}
function _addTableDataRows(paramObjectTDR) {
let { filterNode, limitNode, bodyNode, countNode, paramObject } = paramObjectTDR;
let { dataRows, functionArray } = paramObject;
_clearNode(bodyNode);
if (typeof dataRows === `string`) {
bodyNode.insertAdjacentHTML(`beforeend`, dataRows);
} else {
let filterTerm;
if (filterNode) {
filterTerm = filterNode.value.toLowerCase();
}
let serialNumber = 0;
let limitNumber = 0;
let rowNode;
dataRows.forEach(currentRow => {
if (!filterNode || _filterData(filterTerm, currentRow)) {
serialNumber++;
if (!limitNode || limitNode.value === `all` || limitNode.value >= serialNumber) {
limitNumber++;
rowNode = _getNode(`tr`);
bodyNode.appendChild(rowNode);
_addData(rowNode, serialNumber, currentRow, `td`);
}
}
});
_clearNode(countNode);
countNode.insertAdjacentText(`beforeend`, `Showing 1 to ${limitNumber} of ${serialNumber} entries`);
}
if (functionArray) {
functionArray.forEach(currentObject => {
let { className, eventName, functionName } = currentObject;
_attachFunctionToClassNodes(className, eventName, functionName);
});
}
}