浅谈Vue使用Cascader级联选择器数据回显中的坑
业务场景
由于项目需求,需要对相关类目进行多选,类目数据量又特别大,业务逻辑是使用懒加载方式加载各级类目数据,编辑时回显用户选择的类目。
问题描述
使用Cascader级联选择器过程中主要存在的应用问题如下:
1、由于在未渲染节点数据的情况下编辑时无法找到对应的类目数据导致无法回显,如何自动全部加载已选择类目的相关节点数据;
2、提前加载数据后,点击相应父级节点出现数据重复等;
3、使用多个数据源相同的级联选择器,产生只能成功响应一个加载子级节点数据;
4、Vue中级联选择器相应数据完成加载,依然无法回显。
解决思路
Cascader级联选择器在需要回显的节点数据都存在的情况下,方可完成回显,首先想到的是把选中节点相关的数据全部获取到即可,遍历已选择的节点数据,遍历加载相对应的数据。(如果多个级联选择器使用同一个数据源,使用深拷贝将数据分开,避免产生影响)
由于是级联的数据懒加载,需要每一级相应的节点数据加载完进行下一步,故使用ES6中的Promise,将子级节点数据加载封装成一个Promise,待Promise执行完成,对列表数据遍历获取完成后返回即可。
getChildrenList(fid,level=0){
returnnewPromise((resolve,reject)=>{
API.getCategory({fid:fid,level:level}).then(
res=>{
if(res){
if(res.code===0&&res.result){
resolve(res.result)
}
}
}
)
})
},
lettwolist=this.getChildrenList(codeArr[0],1)
letthirdlist=this.getChildrenList(codeArr[1],2)
Promise.all([twolist,thirdlist]).then((data)=>{
...
})
Vue2的双向数据绑定使用ES2015中的Object.defineProperty(),该方法无法检测到Array中的深层数据变化,需要使用$set来触发列表数据的更新。
一个三级级联选择器,首先获取全部一级类目,二级类目和三级类目采用懒加载,获取数据的步骤如下:
1、获取全部一级类目;
2、由于使用异步数据加载,使用Promise进行数据请求;
3、根据已选择的类目获取相关联的二级类目和三级类目;
4、数据请求完成,使用$set触发列表数据更新,在$nextTick中完成数据你回显。
相关代码
补充知识:AntDesign级联选择的一种写法
简单记录类似省、市、区或品牌、车系、车型等多级结构,级联选择添加并展示的一种写法:
importReactfrom'react';
import{Button,Form,message,Row,Tag,Select,Col}from'antd';
importrequestfrom"../../../../utils/request";
constFormItem=Form.Item;
constOption=Select.Option;
classCarSeriesCascaderextendsReact.Component{
constructor(props){
super(props);
this.state={
defaultBrandList:[],
selectedCarModelList:props.carModelList?props.carModelList:[],
brandCode:null,
carModelList:[],
carId:null,
modelCode:null,
modelName:null
}
}
componentDidMount(){
letpromise=request(`/car/getBrandList`);
promise.then(result=>{
if(result!=null){
this.setState({
defaultBrandList:result
});
}else{
message.error("获取品牌数据失败");
}
}).catch(err=>{
message.error("获取品牌数据失败");
});
//this.setState({
//selectedCarModelList:(this.props.carModelList?this.props.carModelList:[])
//});
this.handleChange(this.state.selectedCarModelList);
}
getLimitList=(selectedCarModelList)=>{
letlimitList=selectedCarModelList.map((carModel,index)=>{
letlimitItem={};
limitItem.modelName=carModel.modelName;
limitItem.modelCode=carModel.modelCode;
limitItem.carId=carModel.carId;
returnlimitItem;
});
returnlimitList;
}
addCarModel=()=>{
letaddCarModel={};
letselectedCarModelList=this.state.selectedCarModelList;
//选中车型号
if(this.state.carId!==null){
//检查车型是否已选中
for(letindex=this.state.selectedCarModelList.length-1;index>=0;index--){
letcarModel=this.state.selectedCarModelList[index];
if(carModel.carId==this.state.carId){
message.error("车型已在已选车型中");
return;
}
}
addCarModel.carId=this.state.carId;
addCarModel.modelCode=this.state.modelCode;
addCarModel.modelName=this.state.modelName;
selectedCarModelList.push(addCarModel);
}else{
return;
}
this.handleChange(selectedCarModelList);
this.setState({
selectedCarModelList
});
}
handleChange=(selectedCarModelList)=>{
if(this.props.onChange){
letlimitList=this.getLimitList(selectedCarModelList);
this.props.onChange(limitList);
}
}
deleteTag=(limitCode)=>{
debugger
letselectedCarModelList=this.state.selectedCarModelList;
selectedCarModelList=selectedCarModelList.filter(carModel=>!(carModel.modelCode===limitCode));
this.handleChange(selectedCarModelList);
this.setState({selectedCarModelList});
}
//品牌变化
brandChange=(brandName)=>{
this.state.defaultBrandList.map((item,index)=>{
if(item.brandName==brandName){
letpromise=request(`/car/getModelList?brandCode=`+item.brandCode);
promise.then(result=>{
if(result!=null){
this.setState({
brandCode:item.brandCode,
carModelList:result
});
}else{
message.error("获取车型数据失败");
}
}).catch(err=>{
message.error("获取车型数据失败:");
});
}
});
}
//车型变化
modelChange=(modelName)=>{
this.props.form.setFieldsValue({modelName:null});
let_this=this;
this.state.carModelList.map((item,index)=>{
if(item.modelName==modelName){
console.log(item);
this.setState({
modelCode:item.modelCode,
carId:item.carId,
modelName:item.modelName
});
}
});
}
render(){
const{getFieldDecorator}=this.props.form;
//品牌名称列表
letallBrandListOption=this.state.defaultBrandList!=null?this.state.defaultBrandList.map((item,index)=>{
return{item.brandName};
}):null;
//车型名称列表
letallModelListOption=this.state.carModelList!=null?this.state.carModelList.map((item,index)=>{
return{item.modelName};
}):null;
const{
closable=true,
}=this.props;
constexistCarModel=[];
constlimitList=this.getLimitList(this.state.selectedCarModelList);
for(letindex=limitList.length-1;index>=0;index--){
letlimitItem=limitList[index];
existCarModel.push({
e.preventDefault();
this.deleteTag(limitItem.modelCode);
}}
>{limitItem.modelName} );
}
return(
{getFieldDecorator('brandName',{
rules:[{
message:'请选择品牌'
}],
})(
)}
{getFieldDecorator('modelName',{
rules:[{
message:'请选择车型'
}],
})(
)}
添加车型
{existCarModel}
)
}
}
exportdefaultForm.create()(CarSeriesCascader);
以上这篇浅谈Vue使用Cascader级联选择器数据回显中的坑就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。