JS分類樹的模糊匹配

前言

最近遇到個模糊匹配的小需求,需要對樹形結(jié)構(gòu)的內(nèi)容進(jìn)行模糊匹配,對樹中的節(jié)點(diǎn),只要是出現(xiàn)了相應(yīng)文本,就把節(jié)點(diǎn)以上的整個樹都展示出來
之前我寫過一些針對id的匹配,和這個還不太一樣,因?yàn)?code>id的匹配是唯一的,只要進(jìn)行一次遞歸(遍歷),找到就能返回相應(yīng)節(jié)點(diǎn),也做過將樹形數(shù)據(jù)可視化的功能,但是要根據(jù)規(guī)則記錄樹形結(jié)構(gòu),就稍微麻煩點(diǎn)。

分類樹
分類樹.png

基本上就是這樣一個分類樹,數(shù)據(jù)結(jié)構(gòu)如下:

const data = [{
    id: 1,
    txt: '測試1',
    children: [{
        id: 11,
        txt: '測試11',
        children: [{
            id: 111,
            txt: '測試111',
            children: [{
                id: 1111,
                txt: '這里就不是',
                children: []
            }]
        }]
    }, {
        id: 12,
        txt: '測試12',
        children: [{
            id: 121,
            txt: '測試121',
            children: [{
                id: 1211,
                txt: '測試1211',
                children: []
            }]
        }]
    }]
}, {
    id: 2,
    txt: '測試2',
    children: [{
        id: 21,
        txt: '測試21'
    }]
}]
要求

當(dāng)我輸入“測試”時,把所有包含“測試”節(jié)點(diǎn)都顯示出來,也就是除了最后的“這里就不是”節(jié)點(diǎn),其他的都要出來
當(dāng)我輸入“這里都不是”時,雖然他的父級節(jié)點(diǎn)都沒有包含這個字符,但是作為他的父節(jié)點(diǎn),所以也都要顯示出來(作為樹形結(jié)構(gòu))
當(dāng)我輸入“測試2”時,就只會顯示根數(shù)組的第二個元素,因?yàn)橹挥羞@個分支中包含“測試2”的完整文本
總結(jié)一下,就是根據(jù)輸入的文本,要顯示出最深的包含此文本的節(jié)點(diǎn)的整個分支。

設(shè)計(jì)和代碼

首先,根據(jù)需求,要對樹進(jìn)行遍歷,給每一個節(jié)點(diǎn)一個字段,用來判斷是否可以輸出

// 給每個分支上有所匹配的設(shè)置isNeed
function setFlag (data, keyword) {
    return data.map(item => {
        item.isNeed = isNeedBranch(item, keyword)
        if(item.children && item.children.length) {
            setFlag(item.children, keyword)
        }
        return item
    })
}

這個判斷的函數(shù)isNeedBranch也是一個遞歸,需要遍歷整個樹的每一個節(jié)點(diǎn),只有當(dāng)子節(jié)點(diǎn)中沒有匹配到,并且自身也沒有匹配到時,才會返回false

// 判斷這條分支上有沒有匹配到的
function isNeedBranch (item, keyword) {
    let flag1 = false,
        flag2 = false
    if(item.txt.indexOf(keyword) > -1) {
        flag1 = true
    } else if(item.children && item.children.length) {
        item.children.forEach(child => {
            if(isNeedBranch(child, keyword)) {
                flag2 = true
            }
        })
    }
    return flag1 || flag2
}

最后,對遍歷過的樹進(jìn)行篩選,通過filter進(jìn)行遞歸,把filter返回的值賦給chilren,完成篩選。

// 過濾掉分支上isNeed為false的元素
function treeFilter (data) {
    return data.filter((item, index) => {
        if(item && item.children && item.children.length) {
            item.children = treeFilter(item.children)
        }
        return item.isNeed
    })
}

拿到數(shù)據(jù)后,還要進(jìn)行渲染,渲染出樹形DOM,當(dāng)然,有jsx或者模板的話,就不用這么麻煩
但是,要把拿到的數(shù)據(jù)進(jìn)行一次deepcopy,或者每次點(diǎn)擊都重新拿取,因?yàn)?code>forEach或map方法都改變原數(shù)組

function getShowHTML(val, data) {
    if(!val) return ''
    let dataCopy = JSON.parse(JSON.stringify(data)) // 一個簡單的deepCopy
    let filterTree = treeFilter(setFlag(dataCopy, val))
    return (filterTree && filterTree.length) ? getTreeHtml(filterTree) : ''
}

function getTreeHtml(tree) {
    let rootHTML = document.createElement('ul')
    rootHTML.style.id = 'root'
    let search = (nodeHTML, nodeJSON) => {
        nodeJSON.forEach(item => {
            // console.log('nodeHTML', nodeHTML)
            if(item.children && item.children.length) {
                let thisNode = document.createElement('li')
                let thisNodeUl = document.createElement('ul')
                thisNode.append(item.txt)
                thisNode.append(thisNodeUl)
                // console.log('thisNode.children', thisNode)
                search(thisNode.children[0], item.children)
                nodeHTML && nodeHTML.append(thisNode)
            } else {
                let li = document.createElement('li')
                li.append(item.txt)
                li.style.id = item.id
                nodeHTML && nodeHTML.append(li)
            }
        })
    }
    search(rootHTML, tree)
    return rootHTML
}
image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容