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