簡體   English   中英

過濾帶有輸入字段的嵌套 ul/li 結構,如果輸入為空則重置為原始狀態

[英]Filter through nested ul/li structure with input field, reset to original state if input is empty

我有一個 JSON 對象,用於使用列表構建樹視圖。 JSON 對象具有以下結構;

const data = [
    { "name": "Node 1", "children":
        [
            { "name": "Node 1.1", "children":
                [
                    { "name": "Node 1.1.1", "children": [], "leaf": true },
                    { "name": "Node 1.1.2", "children": [], "leaf": true }
                ]
            },
            { "name": "Node 1.2", "children":
                [ { "name": "Node 1.2.1", "children": [], "leaf": true } ]
            }
        ]
    },
    { "name": "Node 2", "children":
        [
            { "name": "Node 2.1", "children": [] },
            { "name": "Node 2.2", "children":
                [ { "name": "Node 2.2.1", "children": [], "leaf": true } ]
            }
        ]
    },
    { "name": "Node 3", "children": [] }
];

然后在createTree函數中使用該對象;

createTree(nodes, container)
{
    const list = document.createElement('ul');

    nodes.forEach((node) => {
        const listItem = document.createElement('li');
        listItem.textContent = node.name;
        list.appendChild(listItem);

        if (node.children) {
            const childList = document.createElement('li');
            this.createTree(node.children, childList);
            list.appendChild(childList);
        }
    });

    container.appendChild(list);
}

nodes最初是data對象, container是放置樹的元素。該函數構建以下樹視圖;

<ul>
    <li>Node 1</li>
    <li>
        <ul>
            <li>Node 1.1</li>
            <li>
                <ul>
                    <li>Node 1.1.1</li>
                    <li>
                        <ul></ul>
                    </li>
                    <li>Node 1.1.2</li>
                    <li>
                        <ul></ul>
                    </li>
                </ul>
            </li>
            <li>Node 1.2</li>
            <li>
                <ul>
                    <li>Node 1.2.1</li>
                    <li>
                        <ul></ul>
                    </li>
                </ul>
            </li>
        </ul>
    </li>
    <li>Node 2</li>
    <li>
        <ul>
            <li>Node 2.1</li>
            <li>
                <ul></ul>
            </li>
            <li>Node 2.2</li>
            <li>
                <ul>
                    <li>Node 2.2.1</li>
                    <li>
                        <ul></ul>
                    </li>
                </ul>
            </li>
        </ul>
    </li>
    <li>Node 3</li>
    <li>
        <ul></ul>
    </li>
</ul>

這幾乎是我想要的方式,有很多不必要的liul標簽,但是因為我使用的是list-style-type: none這並不重要,不必要的元素被折疊而不顯示。

我還添加了一個輸入字段,用於過濾樹並只顯示相關的葉子(因此是 JSON 對象中的leaf值)。 它應該只顯示相關的葉子,還有它們的父母。 我已經設法使用以下過濾器功能部分地做到了這一點;

$('#input').on('keyup', () => {
    const value = $('#input').val().toLowerCase().trim();
    const nodes = oldData.filter(function f(node) {
        if (node.name.toLowerCase().includes(value)) return true;

        if (node.children) {
            return (node.children = node.children.filter(f)).length;
        }
    });

    // Simply removes all children from the root element so there's only one tree, instead of the new tree being stacked on top of the new one
    this.removeTree();
    // Rebuild the new tree
    this.createTree(nodes, document.getElementById('root-element'));
});

這在某種意義上是有效的,它只顯示相關的葉子,包括它們的父節點,但是如果您清空輸入字段,則只有在搜索詞之后可見的元素才會可見。 我知道為什么會發生這種情況( filter功能會刪除所有不匹配項),但我不知道如何防止這種情況發生。 我嘗試將data的初始狀態存儲在keyup事件偵聽器之外的變量中,並在輸入字段為空時將nodes設置為該變量,但這似乎沒有幫助。

我也試過瀏覽實際的 HTML 樹,但我什至無法正確訪問節點 1、2 和 3 的子節點,所以我在那里也不知所措。

換句話說,過濾樹的葉子同時也顯示它們的父母並在過濾器為空后恢復原始的最佳方法是什么?

使用jQuery.grep()

const nodes = $.grep(data, function f(node) {
    if (node.name.toLowerCase().includes(value)) return true;
});

據我了解,您有兩個問題。

  1. 復制對象的方式。 當你寫let oldData = data; 您將獲得指向初始“數據”對象的鏈接,而不是另一個對象。 有很多方法可以復制對象,我通過 JSON 使用。
$(document).ready(() => {
  createTree(data, $('#container'));
  $('#asdf').on('keyup', () => {
    let dataCopy = JSON.parse(JSON.stringify(data));

    const value = $('#asdf').val().toLowerCase().trim();
    let nodes = {};
    if (!value) { nodes = data; } else {
      nodes = filterData(dataCopy, value);
    }

    // Simply removes all children from the root element so there's only one tree, instead of the new tree being stacked on top of the new one
    this.removeTree();
    // Rebuild the new tree
    this.createTree(nodes, $('#container'));
  });
});
  1. 在過濾器函數中,您應該檢查是否有任何子節點返回。
function filterData(data, name) {
  return data.filter(function(o) {
    if (o.children) o.children = filterData(o.children, name);
    return o.name.toLowerCase().includes(name) || o.children.length;
  });
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM