1、问题描述
省市区多级菜单使用el-element的控件Cascader 级联选择器,一次加载全部数据,需等待1秒多,体验较不好。实现界面效果如下:
2、解决方案
查看官方文档,通过lazy参数来开启动态加载,并通过lazyload来设置加载数据源的方法。lazyload方法有两个参数,第一个参数node为当前点击的节点,第二个resolve为数据加载完成的回调(必须调用)。官方栗子如下图如示:
在以上的栗子中,设置lazy属性为true,通过lazyload方法来设置数据源,最终通过resolve方法将数据返回。
3、项目实战
3.1、cascader取值显示
前端代码:
设置cascader属性,这里需注意v-model的传值,v-model值需设为数组,形如:[120000, 120100, 120101]这样的形式,保存操作传参时,如只需存储最后一位,要特殊处理;回显时,同样需组装形如[120000, 120100, 120101]的数据,才能正确显示。
<el-cascader v-model="form.areaTran" :props="areaProps" :show-all-levels="false"></el-cascader>
areaProps属性设置如下:
areaProps: {
lazy: true,
checkStrictly: true,
lazyLoad: this.loadAreaTree,
},
loadAreaTree(node, resolve) {
// 首次加载时 node为{root:true,level:0}
// node 节点数据 获取node的level字段的值
const { level } = node;
//下一层节点
const nodes = [];
if (node.hasChildren || node.root) {
// 0 代表第一次请求
let nodeId = level == 0 ? 1 : node.value;
//这里setTimeout的目的是 显示加载动画
setTimeout(() => {
//调用后端接口 获得返回数据
let ret = listAreaByPId({parentId:nodeId});
listAreaByPId({parentId:nodeId}).then(response => {
const childNodes = response.data.map((item) => ({
value: item["areaId"],
label: item["areaName"],
leaf: level>= 2,
}));
return resolve(childNodes);
});
}, 1);
} else {
//如果没有子节点就不发起请求,直接渲染,也避免了点击叶子节点仍然有加载动画的问题
resolve(nodes);
}
}
以上代码都有说明注释,不多说明,注意一点的是leaf属性,当leaf>=2时,为叶子节点,不会继续发请求了,否则还要再请求一次,体验不太好。
后端代码:
@ApiOperation("根据PId查询地区管理列表")
@PreAuthorize("@ss.hasPermi('basicinfo:area:list')")
@GetMapping("/listByPId")
public AjaxResult listByPId(Area area)
{
List<Area> list = areaService.selectAreaList(area);
return success(list);
}
后端代码比较简单,只是根据PId查询下一级的数据。
3.2、cascader回显
后端代码:
当我们需要修改数据时,点击修改打开的弹窗中要正确回显到已经保存好的区域。这边前端代码无需修改,主要是后端代码修改,由于后端只存储某一节点的值,而前端需要的是完整的路径数组,所以后端要组装相应的数据。关键代码如下:
这里areas是全部区域数据,通过递归,返回前端所需要的数据格式。
通过组装VO返回前端:
@Data
public class TurfPitchVO extends TurfPitch {
private ArrayList areaTran;
}
3.3、保存操作
Save操作只需取最后一级传到前端即可。
// 取级联对象数组最后一级
if(this.form.areaTran.length>0){
let curAreaId=this.form.areaTran[this.form.areaTran.length - 1];
this.form.areaId=curAreaId;
}
4、扩展剖析
查看官方文档,props的属性如下,可供参考: