JS分类树的模糊匹配

前言

最近遇到个模糊匹配的小需求,需要对树形结构的内容进行模糊匹配,对树中的节点,只要是出现了相应文本,就把节点以上的整个树都展示出来
之前我写过一些针对id的匹配,和这个还不太一样,因为id的匹配是唯一的,只要进行一次递归(遍历),找到就能返回相应节点,也做过将树形数据可视化的功能,但是要根据规则记录树形结构,就稍微麻烦点。

分类树
分类树.png

基本上就是这样一个分类树,数据结构如下:

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'
    }]
}]
要求

当我输入“测试”时,把所有包含“测试”节点都显示出来,也就是除了最后的“这里就不是”节点,其他的都要出来
当我输入“这里都不是”时,虽然他的父级节点都没有包含这个字符,但是作为他的父节点,所以也都要显示出来(作为树形结构)
当我输入“测试2”时,就只会显示根数组的第二个元素,因为只有这个分支中包含“测试2”的完整文本
总结一下,就是根据输入的文本,要显示出最深的包含此文本的节点的整个分支。

设计和代码

首先,根据需求,要对树进行遍历,给每一个节点一个字段,用来判断是否可以输出

// 给每个分支上有所匹配的设置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
    })
}

这个判断的函数isNeedBranch也是一个递归,需要遍历整个树的每一个节点,只有当子节点中没有匹配到,并且自身也没有匹配到时,才会返回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
}

最后,对遍历过的树进行筛选,通过filter进行递归,把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
    })
}

拿到数据后,还要进行渲染,渲染出树形DOM,当然,有jsx或者模板的话,就不用这么麻烦
但是,要把拿到的数据进行一次deepcopy,或者每次点击都重新拿取,因为forEachmap方法都改变原数组

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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容

  • 关于Mongodb的全面总结 MongoDB的内部构造《MongoDB The Definitive Guide》...
    中v中阅读 31,894评论 2 89
  • 前两天以前的很长一段时间我都没想过,在未来的某一天我会想起他,那个我不愿意去回忆的第四任前男友。 如果把只谈了一星...
    短暂的周沐晨阅读 267评论 2 1
  • 周末好像什么也没做,不过又好像自己挺满足,毕竟,吃吃喝喝,是开心的吧!一个相对舒适的环境。 后来我觉得我很讨厌那种...
    呆小周阅读 180评论 0 0
  • 我的项目是与家人的一次滑雪旅行。 自那一年潇洒姐在瑞士少女峰前令人惊鸿一瞥的照片深深地触动了我,我也向往能有一次难...
    Rosa努力中阅读 227评论 0 0