【问题标题】:how do I best display matches from a large json object?如何最好地显示大型 json 对象的匹配项?
【发布时间】:2013-07-13 08:44:33
【问题描述】:

我正在将 json 对象中的数据加载到我页面上的表格中。然后我允许用户通过输入过滤该数据并仅显示匹配项。我这样做的方法肯定不是很好,但确实有效。

现在我想对机场列表及其代码执行完全相同的操作。问题是机场列表要长得多,并且在加载数据表以及在表中搜索用户输入时页面会严重卡顿。

以下是有效页面的信息,以便您了解我在做什么。

当我要搜索更大的数据集时,我可以采取哪些不同的措施来获得与此处相同的效果?

页面显示数据:(输入“美国航空公司”或“aa”为例) https://pnrbuilder.com/_popups/dataDecoder.php

包含航空公司信息的json对象: https://pnrbuilder.com/_java/airlineDecoder.js

将数据加载到页面并根据用户输入对其进行过滤的脚本: https://pnrbuilder.com/_java/decodeData.js


这是我的代码中最重要的部分:

// This function is called by a for loop on dom ready
// It basically prints data stored in a json object to a table on the page 



function fillInfo(line) {

    var table = document.getElementById('decodeTable');

    var row = document.createElement('tr');
    table.appendChild(row);

    var col1 = document.createElement('td');
    row.appendChild(col1);
    var curCode = document.createTextNode(arlnInfo.d[line].IATA);
    col1.appendChild(curCode);

    var col2 = document.createElement('td');
    row.appendChild(col2);
    var curArln = document.createTextNode(arlnInfo.d[line].Airline);
    col2.appendChild(curArln);

    var col3 = document.createElement('td');
    row.appendChild(col3);
    var curPre = document.createTextNode(arlnInfo.d[line].Prefix);
    col3.appendChild(curPre);

    var col4 = document.createElement('td');
    row.appendChild(col4);
    var curIcao = document.createTextNode(arlnInfo.d[line].ICAO);
    col4.appendChild(curIcao);

    var col5 = document.createElement('td');
    row.appendChild(col5);
    var curCnty = document.createTextNode(arlnInfo.d[line].Country);
    col5.appendChild(curCnty);


}


// This function checks user input against data in the table 
// If a match is found whitin a row, the row containing the match is shown
// If a match is not found that row is hidden 



function filterTable(input) {

    var decodeTable = document.getElementById('decodeTable');
    var inputLength = input.length;


// THis first part makes sure that all rows of the generated table are hidden when no input is present 

    if (inputLength == 0) {            

        for (var r = 1; r < decodeTable.rows.length; r++) {

            decodeTable.rows[r].style.display = "none";

        }

    } 


// This part checks just the airline codes "column" of the table when input is only one or two characters


    else if (inputLength < 3) {

        for (var r = 1; r < decodeTable.rows.length; r++) {

            var celVal = $(decodeTable.rows[r].cells[0])
                .text()
                .slice(0, inputLength)
                .toLowerCase();
            if (celVal == input) {
                decodeTable.rows[r].style.display = "";
            } else {
                decodeTable.rows[r].style.display = "none";
            }

        }
    }

// This part checks several "columns" of the table when input is more than two characters

    else if (inputLength > 2) {

        for (var r = 1; r < decodeTable.rows.length; r++) {

            var celVal = $(decodeTable.rows[r].cells[2])
                .text()
                .slice(0, inputLength)
                .toLowerCase();
            var celVal2 = $(decodeTable.rows[r].cells[1])
                .text();
            if (celVal == input || celVal2 == input) {
                decodeTable.rows[r].style.display = "";
            } else if (celVal2.replace(/<[^>]+>/g, "")
                .toLowerCase()
                .indexOf(input) >= 0) {
                decodeTable.rows[r].style.display = "";
            } else {
                decodeTable.rows[r].style.display = "none";
            }

        }
    }

}

【问题讨论】:

  • 您不能对照 JSON 数据检查输入吗?并为每个对象添加一个属性,例如 isVisible: true/false。全部设置好后,循环遍历 JSON 数组并: if (!isVisible) {...hide table row}
  • 我相信我可以。那会更快吗?在输入的每个 keyup 事件上都会调用“过滤器函数”。循环遍历分配/删除 isVisible 的 JSON 对象然后再次循环遍历 JSON 数组以将可见槽加载到表中会比我现在做的要少得多吗?不拒绝,只是想了解。

标签: javascript json search


【解决方案1】:

您可以应用的第一个小优化不是对每个按键都进行整个过滤器,等到用户完成输入,然后再延迟半秒调用它:

var timeOut = 0;
$("#deCode").keyup(function () {
    // cancel looking, the user typed another character
    clearTimeout(timeOut);
    // set a timeout, when user doesn't type another key
    // within half a second the filter will run
    var input = $("#deCode").val().toLowerCase().trim();
    timeOut=setTimeout(function(){
        filterTable(input)
    },500);
});

接下来是比较您的 json 数据而不是 jquery 对象,并在创建表后将您的 JSON 数据转换为小写,这样您就不必每次都检查 toLowerCase:

function filterTable(input) {
    var decodeTable = document.getElementById('decodeTable');
    var inputLength = input.length;
    if (inputLength ==0) {
        for (var r = 1; r < decodeTable.rows.length; r++) {
            decodeTable.rows[r].style.display = "none";
        }
    }
    else if (inputLength <3) {
        for (var r = 0; r < arlnInfo.d.length; r++) {
            if (arlnInfo.d[r].IATA.indexOf(input)===0) {
                decodeTable.rows[r+1].style.display = "";
            }
            else {
                decodeTable.rows[r+1].style.display = "none"; 
            }

        }
    }
    else if (inputLength > 2) {
        for (var r = 0; r < arlnInfo.d.length; r++) {
            if (arlnInfo.d[r].Prefix.indexOf(input)===0) {
                decodeTable.rows[r].style.display = "";
            }
            else if (arlnInfo.d[r].Airline.indexOf(input) >= 0) {
                decodeTable.rows[r + 1].style.display = "";
            }
            else {
                decodeTable.rows[r + 1].style.display = "none";
            }

        }
    }
}       

问题在于您的 JSON 数据:"Prefix": 430 导致 arlnInfo.d[r].Prefix.slice(0, inputLength) 抛出错误,因为数据不是字符串而是数字。如果您可以控制 JSON,那么您应该将这些值转换为字符串 ("Prefix":"430"),如果没有,则将其转换一次并使用JSON.stringify(arlnInfo);重新创建airlineDecoder.js

要转换您的 JSON,您可以将其复制并粘贴到 chrome 控制台(按 F12)并运行它(按 Enter)。它会记录转换后的 JSON,但您可能需要像 netbeans 这样的 IDE 来重新格式化它:

var i = 0;
for(i=0;i<arlnInfo.d.length;i++){
  arlnInfo.d[i].Prefix=arlnInfo.d[i].Prefix+"";
}
console.log("var arlnInfo = " + JSON.stringify(arlnInfo));

您可以应用的最后一个优化是使用 DocumentFragment 而不是直接将每一行添加到 DOM,这里我们将 JSON 数据转换为小写,因此我们不必为每次搜索都这样做:

var decodeTable = document.getElementById('decodeTable');
function createTable() {
    var df = document.createDocumentFragment();
    for (var i = 0; i < arlnInfo.d.length; i++) {
        fillInfo(i, df);
        arlnInfo.d[i].IATA = arlnInfo.d[i].IATA.toLowerCase()
        arlnInfo.d[i].Prefix = arlnInfo.d[i].Prefix.toLowerCase();
        arlnInfo.d[i].Airline = arlnInfo.d[i].Airline.toLowerCase();
    }
    decodeTable.appendChild(df);
}
createTable();
....
function fillInfo(line,df) {
    var row = document.createElement('tr');
        df.appendChild(row);
     ....
     row.style.display = "none";
}

【讨论】:

  • 啊,我明白了。因此,将 isVisible 设置为数组,然后仅加载那些确实比遍历表行更快。我当然喜欢延迟。但是,如果用户退格或继续输入,我如何从表中删除不再匹配输入的行?
  • @eosterberg 是的,我已经更新了答案,想测试一下是否可以使用 JSON 数据进行搜索,它有效,但 JSON 需要更改
  • 我确实可以更改 JSON(使用在线工具创建它,将它们全部变成数字)我曾希望避免更改它,因为我知道如何手动操作的唯一方法这个清单很大。看来我毕竟会添加所有这些引号。非常感谢您的帮助!
  • @DelightedD0D 我会在我的答案中添加一个转换脚本
  • 添加你是正式的真棒。再次感谢。
猜你喜欢
  • 1970-01-01
  • 2022-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-15
相关资源
最近更新 更多