java json树 模糊搜索

package com.ican.kqyz.system.utils;

import com.alibaba.fastjson.JSON;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * @Description: 子集处理类
 * @Title: ChildHandle
 * @Package com.ican.kqyz.system.utils
 * @Author: zangdy
 * @CreateTime: 2022/10/20 10:06
 */
public class ChildHandle {
    /** id */
    private Integer id;
    /** 父级id */
    private Integer parentId;
    /** 名称 */
    private String name;
    /** 子集 */
    private List<ChildHandle> child;

    public static void main(String[] args) {
        // 模拟数据
        List<ChildHandle> list = mockData();
        // 获取层级关系
        list = getChild(0, list);
        System.out.println(JSON.toJSONString(list));
        // 搜索树形结构数据
        list = childSearchName(list,"测试011");
        System.out.println(JSON.toJSONString(list));
    }

    /**
     * 搜索树形结构数据
     *  1. 如果当前搜索值存在,那么不管子集存不存在,当前数据都需要查出来
     *  2. 如果当前搜索值不存在,同时他的子集存在,那么当前包含子集的数据都需要查出来
     *  3. 如果当前搜索值不存在,并且子集也不存在,那么当前数据需要移除掉
     * @param list
     * @param search
     * @return
     */
    private static List<ChildHandle> childSearchName(List<ChildHandle> list, String search) {
        if (CollectionUtils.isEmpty(list)){
            return null;
        }
        // 默认当前搜索含有该值
        for (int i = 0; i < list.size(); i++) {
            ChildHandle item = list.get(i);
            if(item.getName().contains(search)) {
                // 当前搜索含有该值
                childSearch(item.getChild(), search, true);
            }else {
                // 当前搜索不含有该值
                boolean flag = childSearch(item.getChild(), search, false);
                // 下级没有搜索到
                if(!flag){
                    // 移除
                    list.remove(i);
                    i--;
                }
            }
        }
        return list;
    }

    /**
     * 递归搜索值操作
     * @param list
     * @param search
     * @param flag
     * @return
     */
    private static boolean childSearch(List<ChildHandle> list, String search, boolean flag) {
    	if(flag){
    		// 如果父级存在,子集不需要判断了
            return true;
        }
        if(CollectionUtils.isEmpty(list)){
            return flag;
        }
        // 本次搜索默认不存在
        boolean newFlag = false;
        for (int i = 0; i < list.size(); i++) {
            // 当前搜索值是否存在
            boolean thisSearchFlag;
            ChildHandle item = list.get(i);
            if(item.getName().contains(search)) {
                // 当前搜索值存在
                thisSearchFlag = childSearch(item.getChild(), search, true);
            }else {
                // 当前搜索值不存在
                thisSearchFlag = childSearch(item.getChild(), search, flag);
                // 下级没有搜索到
                if(!thisSearchFlag){
                    // 移除
                    list.remove(i);
                    i--;
                }
            }
            // 如果上一级不存在则跟随当前搜索结果
            if(thisSearchFlag){
                newFlag = true;
            }
        }
        // 如果上次搜索不存在则用当前搜索结果
        if(!flag){
            flag = newFlag;
        }
        return flag;
    }

    /**
     * 获取子集
     *
     * @param parentId
     * @param list
     * @return
     */
    public static List<ChildHandle> getChild(Integer parentId, List<ChildHandle> list) {
        if (CollectionUtils.isEmpty(list) || parentId == null) {
            return null;
        }
        // 组装新的树形结构数据
        List<ChildHandle> newList = new ArrayList<>();
        for (ChildHandle child : list) {
            // 如果父级内码是当前内码,就继续
            if (parentId.equals(child.getParentId())) {
                // 寻找下级
                child.setChild(getChild(child.getId(), list));
                newList.add(child);
            }
        }
        return newList;
    }

    /**
     * 模拟数据
     * @return
     */
    private static List<ChildHandle> mockData() {
        List<ChildHandle> list = new ArrayList<>();
        ChildHandle ch1 = new ChildHandle();
        ch1.setId(1);
        ch1.setParentId(0);
        ch1.setName("测试000");
        list.add(ch1);

        ChildHandle ch2 = new ChildHandle();
        ch2.setId(2);
        ch2.setParentId(0);
        ch2.setName("测试011");
        list.add(ch2);

        ChildHandle ch3 = new ChildHandle();
        ch3.setId(3);
        ch3.setParentId(2);
        ch3.setName("测试333");
        list.add(ch3);

        ChildHandle ch4 = new ChildHandle();
        ch4.setId(4);
        ch4.setParentId(1);
        ch4.setName("测试020");
        list.add(ch4);

        ChildHandle ch5 = new ChildHandle();
        ch5.setId(5);
        ch5.setParentId(1);
        ch5.setName("测试030");
        list.add(ch5);

        ChildHandle ch6 = new ChildHandle();
        ch6.setId(6);
        ch6.setParentId(4);
        ch6.setName("测试20");
        list.add(ch6);

        ChildHandle ch7 = new ChildHandle();
        ch7.setId(7);
        ch7.setParentId(6);
        ch7.setName("测试203");
        list.add(ch7);
        return list;
    }

    public Integer getParentId() {
        return parentId;
    }

    public void setParentId(Integer parentId) {
        this.parentId = parentId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<ChildHandle> getChild() {
        return child;
    }

    public void setChild(List<ChildHandle> child) {
        this.child = child;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }
}

第二种方案

Java树结构展示条件筛选优化
效果图展示
总结
代码
效果图展示


总结
对于之前的两级树,博主首先想到的是实体类里面进行封装就可以了,并没有采用递归的形式,可后来随着树结构的增加,树的层级也越来越大,这种情况下显然是不可采取的,便想到了采用递归的方式,同时对于搜索也能采用递归的思想,这样对于无论多少层树同样适用,大大提高了工作效率


代码
话不多说,上代码

 /**
     * 树的展示加搜索
     *
     * @param map
     * @return
     */
    @RequestMapping("/findTree")
    public R findTree(@RequestBody Map<String, Object> map) {
        String keywords = (String) map.get("keywords");
        List<TreeVo> treeVos = treeDao.treeKeywords(keywords);
        List<String> list = new ArrayList<>();
        for (TreeVo treeVo : treeVos) {
            String nodeName = treeVo.getNodeName();
            list.add(nodeName);
        }
        List<TreeVo> oneTrees = treeDao.findOneTree();
        List<TreeVo> lists = new ArrayList<>();
        for (TreeVo oneTree : oneTrees) {
            traverse(oneTree);
            lists.add(oneTree);
        }
        if (keywords.isEmpty()) {
            return R.ok().setData(lists);
        }
        List<TreeVo> treeVos1 = screenTree(lists, list);
        return R.ok().setData(treeVos1);
    }

 /**
     * 树结构遍历
     *
     * @param oneTree
     */
    public void traverse(TreeVo oneTree) {
        List<TreeVo> treeVos = treeDao.findTwoTree(oneTree.getId());
        if (treeVos != null) {
            for (int i = 0; i < treeVos.size(); i++) {
                TreeVo treeVo = treeVos.get(i);
                traverse(treeVo);
            }
        }
        oneTree.setTreeVoList(treeVos);
    }

/**
     * 树形筛选查找
     *
     * @param treeDtoList 树形集合
     * @param idList      筛选条件(可以是其他条件)
     * @return 包含的节点数据
     */
    public static List<TreeVo> screenTree(List<TreeVo> treeDtoList, List<String> idList) {
        //最后返回的筛选完成的集合
        List<TreeVo> screeningOfCompleteList = new ArrayList<>();
        if (listIsNotEmpty(treeDtoList) && listIsNotEmpty(idList)) {
            for (TreeVo treeDto : treeDtoList) {
                List<TreeVo> subsetList = treeDto.getTreeVoList();
                //递归筛选完成后的返回的需要添加的数据
                TreeVo addTreeDto = getSubsetPmsPlanPo(treeDto, subsetList, idList);
                if (isNotEmpty(addTreeDto)) {
                    screeningOfCompleteList.add(addTreeDto);
                }
            }
            return screeningOfCompleteList;
        }
        return null;
    }


    /**
     * 筛选符合的集合并返回
     *
     * @param treeDto           树形类
     * @param subsetTreeDtoList 子集集合
     * @param idList            筛选条件
     * @return 筛选成功的类
     */
    public static TreeVo getSubsetPmsPlanPo(TreeVo treeDto, List<TreeVo> subsetTreeDtoList, List<String> idList) {
        //作为筛选条件的判断值
        String nodeName = treeDto.getNodeName();
        //有子集时继续向下寻找
        if (listIsNotEmpty(subsetTreeDtoList)) {
            List<TreeVo> addTreeDtoList = new ArrayList<>();
            for (TreeVo subsetTreeDto : subsetTreeDtoList) {
                List<TreeVo> subsetList = subsetTreeDto.getTreeVoList();
                TreeVo newTreeDto = getSubsetPmsPlanPo(subsetTreeDto, subsetList, idList);
                //当子集筛选完不为空时添加
                if (isNotEmpty(newTreeDto)) {
                    addTreeDtoList.add(newTreeDto);
                }
            }
            //子集满足条件筛选时集合不为空时,替换对象集合内容并返回当前对象
            if (listIsNotEmpty(addTreeDtoList)) {
                treeDto.setTreeVoList(addTreeDtoList);
                return treeDto;
                //当前对象子集对象不满足条件时,判断当前对象自己是否满足筛选条件,满足设置子集集合为空,并返回当前对象
            } else if (listIsEmpty(addTreeDtoList) && idList.contains(nodeName)) {
                if (listIsEmpty(addTreeDtoList) && treeDto.getLevel() == 6) {
                    treeDto.setTreeVoList(null);
                }
//                treeDto.setTreeVoList(null);
                return treeDto;
            } else {
                //未满足筛选条件直接返回null
                return null;
            }
        } else {
            //无子集时判断当前对象是否满足筛选条件
            if (idList.contains(nodeName)) {
                return treeDto;
            } else {
                return null;
            }
        }
    }

    /**
     * 判断集合为空
     *
     * @param list 需要判断的集合
     * @return 集合为空时返回 true
     */
    public static boolean listIsEmpty(Collection list) {
        return (null == list || list.size() == 0);
    }

    /**
     * 判断集合非空
     *
     * @param list 需要判断的集合
     * @return 集合非空时返回 true
     */
    public static boolean listIsNotEmpty(Collection list) {
        return !listIsEmpty(list);
    }

    /**
     * 判断对象为null或空时
     *
     * @param object 对象
     * @return 对象为空或null时返回 true
     */
    public static boolean isEmpty(Object object) {
        if (object == null) {
            return (true);
        }
        if ("".equals(object)) {
            return (true);
        }
        if ("null".equals(object)) {
            return (true);
        }
        return (false);
    }

    /**
     * 判断对象非空
     *
     * @param object 对象
     * @return 对象为非空时返回 true
     */
    public static boolean isNotEmpty(Object object) {
        if (object != null && !object.equals("") && !object.equals("null")) {
            return (true);
        }
        return (false);
    }


    public void selectById(Integer id, List<Integer> idList, List<Integer> list) {
        //查询数据库等于id的数据
        List<TreeVo> childList = treeDao.findTwoTree(id);
        //递归查询下一级id,同时将上一次查询结果添加到list集合
        childList.forEach(menu -> {
            idList.add(menu.getId());
            if (menu.getLevel() == 6) {
                list.add(menu.getId());
            }
            this.selectById(menu.getId(), idList, list);
        });
    }

    public void selectByIdFive(Integer id, List<Integer> idList, List<Integer> list) {
        //查询数据库等于id的数据
        List<TreeVo> childList = treeDao.findTwoTree(id);
        //递归查询下一级id,同时将上一次查询结果添加到list集合
        childList.forEach(menu -> {
            idList.add(menu.getId());
            if (menu.getLevel() < 6) {
                list.add(menu.getId());
            }
            this.selectById(menu.getId(), idList, list);
        });
    }


————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.youkuaiyun.com/S_yyuan/article/details/127283626

onReachBottom触底函数用这个但是无法保证搜索框和u-tabs标签页是吸顶的,该怎么解决?<template> <view class="deliveryOrder"> <u-toast ref="uToast"></u-toast> <view class="searchBtn"> <u-search placeholder="订单号" :showAction="true" v-model="orderValue" shape="round" actionText="查询" :animation="true" @search="searchClick()" @custom="searchClick()"></u-search> <text class="screening" @click="handleScreening">筛选</text> </view> <view class="tabsBox"> <u-sticky bgColor="#fff"> <u-tabs :list="list" :is-scroll="false" :current="current" bar-width="50" active-color="orange" @change="change"> </u-tabs> <view v-if="current===0"> <scroll-view @scrolltolower="lowerBottom" @refresherrefresh="getFresh" :refresher-enabled="true" :refresher-triggered="triggered" scroll-y="true" class="scrollHeight"> <view class="scrolllist" v-if="allList&&allList.length>0"> <view class="orderscrollItem" v-for="(item,index) in allList" :key="index" @click="toDetail(item)"> <view class="itemTitle"> {{item}} </view> </view> <view class="more_text" v-if="showMoreData"> 没有更多数据了... </view> </view> <view v-else class="empty_box"> <u-empty mode="order" icon="http://cdn.uviewui.com/uview/empty/car.png" > </u-empty> </view> </scroll-view> </view> <view v-if="current===1"> 待配送 </view> <view v-if="current===2"> 配送中 </view> <view v-if="current===3"> 待签收 </view> <view v-if="current===4"> 已完成 </view> </u-sticky> </view> <u-popup :show="showPopup" :round="10" mode="top" @close="showPopup=false"> <view class="popup"> <text class="popupTitle">筛选条件</text> <view class="formBox"> <u--form :model="form" ref="uForm" labelWidth="90px"> <u-form-item label="时间范围" prop="timeValue" borderBottom @click="showCalendar=true"> <u-input v-model="form.timeValue" :disabled="true" r
最新发布
03-28
<think>好的,用户的问题是在使用onReachBottom触底加载时,搜索框和u-tabs标签页无法保持吸顶效果。我需要根据提供的引用和知识库来找到解决方法。 首先,引用[4]提到,当body的overflow属性设置为scroll时,sticky吸顶可能会失效。用户可能遇到了类似的问题。需要检查页面或父容器的overflow设置,确保不是hidden或auto,可以尝试设为visible。 然后,引用[2]和[3]讨论了使用vant的sticky属性时的问题。虽然用户使用的是u-tabs,但可能原理类似。确保组件正确应用了sticky属性,可能需要调整z-index,防止被其他元素覆盖。 另外,触底加载时页面内容增加,可能导致布局变化,影响吸顶效果。需要确认吸顶元素在动态内容加载后仍然位于正确的位置。可能需要强制重新计算布局,比如使用nextTick或在加载完成后触发重绘。 还有,引用[3]提到最后一个van-tab可能影响布局,用户可能需要检查是否有类似的结构问题,比如最后一个标签导致布局溢出,从而影响吸顶。确保标签结构正确,没有多余的元素干扰。 最后,可能需要使用fixed定位替代sticky,但要注意兼容性和滚动处理。同时,检查父容器高度和滚动区域,确保吸顶元素在正确的容器内,避免滚动嵌套问题。</think>### 解决方案:保持吸顶效果的实现方法 #### 1. 检查父容器布局和样式 - **禁用父容器overflow属性**:若父容器(如外层`<view>`或页面容器)设置了`overflow: scroll`或`overflow: auto`,会导致`sticky`失效。需将其改为`overflow: visible`[^4]。 ```css .container { overflow: visible; /* 避免滚动容器干扰吸顶效果 */ } ``` #### 2. 确保吸顶组件层级正确 - **添加z-index层级**:吸顶元素需要设置较高`z-index`(建议≥100),避免被列表内容覆盖。 ```html <u-search :fixed="true" :sticky="true" style="z-index: 100;"></u-search> <u-tabs :sticky="true" :offset-top="搜索框高度" style="z-index: 99;"></u-tabs> ``` #### 3. 动态内容加载后的布局修复 - **触底后强制重绘**:在`onReachBottom`加载数据后,调用`this.$nextTick`等待渲染完成,再通过修改`key`强制组件重置。 ```javascript onReachBottom() { this.loading = true; this.fetchData().then(() => { this.loading = false; this.$nextTick(() => { this.tabsKey = Date.now(); // 强制u-tabs重新渲染 }); }); } ``` #### 4. 使用替代方案兼容特殊场景 - **手动实现吸顶效果**:若框架原生`sticky`不生效,改用`position: fixed`并动态计算位置: ```javascript onPageScroll(e) { const scrollTop = e.scrollTop; const searchHeight = 50; // 搜索框高度 this.isSticky = scrollTop > searchHeight; } ``` ```html <u-search :fixed="true"></u-search> <u-tabs :style="isSticky ? 'position: fixed; top: 50px; z-index: 100;' : ''"></u-tabs> ``` #### 5. 验证组件兼容性 - **检查u-tabs版本**:确认使用的UI库版本是否支持`sticky`属性,更新至最新版本或查看官方文档的已知问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值