裴大头-秦可爱

裴大头-秦可爱

Element UI 级联选择器 el-cascader 实现懒加载和搜索功能

发表于 2023-12-07
裴大头
阅读量 1195
更新于 2023-12-12

当代的 Web 应用程序通常需要提供高度灵活和易用的用户界面,以满足用户对数据选择和搜索的需求。在前端开发中,级联选择器(Cascader)是一种常见的组件,可以帮助用户从多层级的数据中进行选择。 Element UI 是一个流行的 Vue.js 组件库,提供了丰富的 UI 组件,其中包括了 <el-cascader> 组件。该组件可以实现级联选择功能,但默认情况下不支持懒加载和搜索的结合。在本篇博客中,我们将重点介绍如何结合懒加载和搜索来增强 <el-cascader> 的功能。

先看效果

20231207123931_rec_.gif#685px #282px 基础功能:!!#00ff00 级联!!、!!#00ffff 懒加载!!!、!!#ff0000 搜索!!

后端代码

Controller.java

/**
 * 获取地区信息列表
 * @param pxRegion 地区信息
 * @return 地区信息列表
 */
@GetMapping(value = "/getRegionList")
public AjaxResult getRegionList(PxRegion pxRegion) {
    return AjaxResult.success(pxRegionService.getRegionList(pxRegion));
}
java

地区管理Service接口

/**
 * 地区管理Service接口
 *
 * @author 裴浩宇
 * @date 2023-12-06
 */
public interface IPxRegionService {
    /**
     * 查询地区管理列表
     *
     * @param pxRegion 地区管理
     * @return 地区管理集合
     */
    List<PxRegion> getRegionList(PxRegion pxRegion);
}
java

地区管理Service业务层处理

/**
 * 地区管理Service业务层处理
 *
 * @author 裴浩宇
 * @date 2023-12-06
 */
@Service
public class PxRegionServiceImpl implements IPxRegionService {
    @Resource
    private PxRegionMapper pxRegionMapper;

    /**
     * 查询地区管理列表
     *
     * @param pxRegion 地区管理
     * @return 地区管理
     */
    @Override
    public List<PxRegion> getRegionList(PxRegion pxRegion) {
        List<PxRegion> regionList = pxRegionMapper.getRegionList(pxRegion);
        // 如果名称不为空,说明是模糊查询需要处理数据
        if (StringUtils.isNotEmpty(pxRegion.getName())) {
            // 遍历所有地区
            for (PxRegion region : regionList) {
                if (region.getLb() == 1) {
                    // 市的话默认带出该市的区
                    // 参数
                    PxRegion param = new PxRegion();
                    param.setLb(2L);
                    param.setSsdqdm(region.getId());
                    // 获取该市下的区
                    List<PxRegion> children = pxRegionMapper.getRegionList(param);
                    region.setChildren(children);
                } else if (region.getLb() == 2) {
                    region.setChildren(null);
                    // 区的话
                    // 参数
                    PxRegion param = new PxRegion();
                    // 找到区的所属市
                    param.setId(region.getSsdqdm());
                    List<PxRegion> city = pxRegionMapper.getRegionList(param);
                    city.get(0).setChildren(Collections.singletonList(region));
                    // 将市加入
                    regionList.add(city.get(0));
                    regionList.remove(region);
                }
            }
        }
        return regionList;
    }
}
java

地区管理Mapper接口

/**
 * 地区管理Mapper接口
 *
 * @author 裴浩宇
 * @date 2023-12-06
 */
public interface PxRegionMapper {

    /**
     * 查询地区管理列表
     *
     * @param pxRegion 地区管理
     * @return 地区管理集合
     */
    public List<PxRegion> getRegionList(PxRegion pxRegion);
}
java

地区管理Mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.pnkx.mapper.PxRegionMapper">

    <resultMap type="PxRegion" id="PxRegionResult">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="py" column="py"/>
        <result property="ssdqdm" column="ssdqdm"/>
        <result property="lb" column="lb"/>
        <result property="yb" column="yb"/>
        <result property="jlzt" column="jlzt"/>
    </resultMap>

    <sql id="selectPxRegionVo">
        select id, name, py, ssdqdm, lb, yb, jlzt
        from yy_dq_ybdmk
    </sql>

    <select id="getRegionList" parameterType="PxRegion" resultMap="PxRegionResult">
        <include refid="selectPxRegionVo"/>
        <where>
            <if test="id != null ">
                and id = #{id}
            </if>
            <if test="name != null  and name != ''">
                and name like concat('%', #{name}, '%')
            </if>
            <if test="py != null  and py != ''">
                and py = #{py}
            </if>
            <if test="ssdqdm != null ">
                and ssdqdm = #{ssdqdm}
            </if>
            <if test="lb != null ">
                and lb = #{lb}
            </if>
            <if test="yb != null ">
                and yb = #{yb}
            </if>
            <if test="jlzt != null ">
                and jlzt = #{jlzt}
            </if>
        </where>
    </select>
</mapper>
xml

前端代码

Region组件

<template>
    <div class="cascader">
        <el-cascader
            v-model="selectedValues"
            :options="options"
            @change="handleChange"
            :before-filter="handleFilter"
            :props="props"
            separator=" - "
            filterable
            clearable
            placeholder="请选择省市区"
        />
    </div>
</template>

<script>
import {getRegionList} from "@/api/px/blog/region";

export default {
    name: "Region",
    props: {
        address: {
            type: Array,
            default: ""
        }
    },
	watch: {
	  address: {
		async handler() {
		  // 获取省列表
		  await this.getRegionList(0);
		  // 获取市列表
		  if (this.address[0]) await this.getRegionList(1, this.address[0]);
		  // 获取区列表
		  if (this.address[1]) await this.getRegionList(2, this.address[1]);
		  // 赋值
		  this.selectedValues = [
			Number(this.address[0]),
			Number(this.address[1]),
			Number(this.address[2]),
		  ];
		},
		immediate: true,
		deep: true
	  },
	},
    data() {
        const _this = this;
        return {
            // 选中的省市区值
            selectedValues: [],
            // 数据源,省市区的JSON数据
            options: [],
            // 映射关系
            props: {
                // value对应属性
                value: "id",
                // label对应属性
                label: "name",
                // 开启懒加载
                lazy: true,
                lazyLoad: function (node, resolve) {
                    const {level} = node;
                    getRegionList({
                        lb: level,
                        ssdqdm: node.value
                    }).then(res => {
                        resolve(res.data.filter(item => {
                            if (level === 0) {
                                // 判断是否已存在省
                                return !_this.options?.find(province => province.id === item.id)
                            } else if (level === 1) {
                                // 判断是否已存在市
                                return !_this.options.find(province => province.id === item.ssdqdm)?.children.find(city => city.id === item.id)
                            } else if (level === 2) {
                                // 找到省
                                const theProvince = _this.options.find(province => province.children.find(city => city.id === item.ssdqdm));
                                // 判断是否已存在区
                                return !theProvince?.children.find(city => city.id === item.ssdqdm)?.children.find(area => area.id === item.id)
                            }
                        }).map(item => {
                            return {
                                ...item,
                                children: [],
                                leaf: level >= 2
                            }
                        }));
                    })
                }
            }
        };
    },
    methods: {
        /**
         * 搜索
         * @param searchValue
         */
        async handleFilter(searchValue) {
            if (searchValue) {
                await this.getRegionList(undefined, undefined, searchValue);
				this.selectedValues = Number(searchValue);
            }
        },
        /**
         * 选择省市区
         * @param value
         */
        handleChange(value) {
            this.$emit("update:address", value);
        },
        /**
         * 获取地区列表
         * @param level
         * @param parentCode
         * @param name
         */
        async getRegionList(level, parentCode, name) {
            await getRegionList({
                lb: level,
                ssdqdm: parentCode,
                name
            }).then(res => {
                res.data.forEach(item => {
                    if (item.lb === 0) {
                        // 省
                        this.options.find(province => province.id === item.id) || this.options.push(item);
                    } else if (item.lb === 1) {
                        // 市
                        this.options.find(province => province.id === item.ssdqdm)?.children?.find(city => city.id === item.id) || this.options.find(province => province.id === item.ssdqdm).children.push({
                            ...item,
                            children: item.children.map(area => {
                                return {
                                    ...area,
                                    leaf: true
                                }
                            })
                        });
                    } else if (item.lb === 2) {
                        // 区
                        // 找到省
                        const theProvince = this.options.find(province => province.children.find(city => city.id === item.ssdqdm));
                        // 找到市放入区
                        theProvince.children.find(city => city.id === item.ssdqdm)?.children?.find(area => area.id === item.id) || theProvince.children.find(city => city.id === item.ssdqdm)?.children.push({
                            ...item,
                            leaf: true
                        });
                    }
                })
            })
        }
    }
}
</script>
javascript

使用

<template>
    <region :address.sync="address"/>
</template>
<script>
import Region from "@/components/Region/index.vue";

export default {
    components: {
        Region
    },
    data() {
        return {
            // 地址
            address: [140000, 140400, 140406]
        }
    },
    watch: {
        address(val) {
            this.$message.success('选中: ' + val.join('-'));
        }
    }
}
</script>
javascript

在上述代码中,接口大致有三个参数:level(层级)、parentCode(父级编号)、name(名称用于模糊查询) 前端组件在初始时回显选中的地区,改变时触发emit事件使父组件修改,并且支持懒加载和搜索。

源码下载

点击下载源码

评论
来发一针见血的评论吧!
表情

快来发表评论吧~

推荐文章
  • JavaScript 的事件循环机制

    1点赞1评论

  • Vue项目代码规范

    1点赞1评论

  • 聊一聊我的文本编辑器

    1点赞11评论

  • JavaScript的常用遍历方法整理

    1点赞8评论

  • Java 23种设计模式——单例模式(Singleton)

    0点赞1评论

Crafted with by Pei你看雪

小破站居然运行了 887 天访客 24128

© 2023 Pei你看雪鲁ICP备19037910号-2