< 返回新闻公告列表

Vue中级联选择器实现数据回显有哪些事项要注意的

发布时间:2023-1-6 15:04:33    来源: 纵横云

很多朋友都对“Vue中级联选择器实现数据回显有哪些事项要注意的”的内容比较感兴趣,对此小编整理了相关的知识分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获,那么感兴趣的朋友就继续往下看吧!

业务场景

由于项目需求,需要对相关类目进行多选,类目数据量又特别大,业务逻辑是使用懒加载方式加载各级类目数据,编辑时回显用户选择的类目。

问题描述

使用Cascader级联选择器过程中主要存在的应用问题如下:

1、由于在未渲染节点数据的情况下编辑时无法找到对应的类目数据导致无法回显,如何自动全部加载已选择类目的相关节点数据;

2、提前加载数据后,点击相应父级节点出现数据重复等;

3、使用多个数据源相同的级联选择器,产生只能成功响应一个加载子级节点数据;

4、Vue中级联选择器相应数据完成加载,依然无法回显。

解决思路

Cascader级联选择器在需要回显的节点数据都存在的情况下,方可完成回显,首先想到的是把选中节点相关的数据全部获取到即可,遍历已选择的节点数据,遍历加载相对应的数据。(如果多个级联选择器使用同一个数据源,使用深拷贝将数据分开,避免产生影响)

由于是级联的数据懒加载,需要每一级相应的节点数据加载完进行下一步,故使用ES6中的Promise,将子级节点数据加载封装成一个Promise,待Promise执行完成,对列表数据遍历获取完成后返回即可。

getChildrenList (fid, level = 0) {

return new Promise((resolve, reject) => {

API.getCategory({ fid: fid, level: level }).then(

res => {

if (res) {

if (res.code === 0 && res.result) {

resolve(res.result)

}

}

}

)

})

},

let twolist = this.getChildrenList(codeArr[0], 1)

let thirdlist = this.getChildrenList(codeArr[1], 2)

Promise.all([twolist, thirdlist]).then((data) => {

...

})

Vue2的双向数据绑定使用ES2015中的Object.defineProperty(),该方法无法检测到Array中的深层数据变化,需要使用$set来触发列表数据的更新。

一个三级级联选择器,首先获取全部一级类目,二级类目和三级类目采用懒加载,获取数据的步骤如下:

1、获取全部一级类目;

2、由于使用异步数据加载,使用Promise进行数据请求;

3、根据已选择的类目获取相关联的二级类目和三级类目;

4、数据请求完成,使用$set触发列表数据更新,在$nextTick中完成数据你回显。

相关代码

export default {

data () {

return {

categoryList: [],

category: [],

secondCategoryList: [],

secondCategory: [],

props: {

lazy: true,

// checkStrictly: true, // 父子级节点关联

async lazyLoad (node, reso) {

const { level, data } = node

if (data && data.children && data.children.length !== 0) {

return reso(node)

}

if (data && data.leaf) {

return reso([])

}

const lv3Code = data ? data.code : null

setTimeout(() => {

lv3Code && API.getCategory({ fid: lv3Code, level: level }).then(

res => {

if (res) {

if (res.code === 0 && res.result) {

const nodes = res.result.map(item => ({ leaf: level === 2, ...item, children: [] }))

data.children = nodes

reso(nodes)

} else {

reso([])

}

}

}

)

}, 500)

}

}

}

},

mounted () {

this.getCategory()

this.initData()

},

methods: {

initData () {

let _that = this

异步获取编辑数据。。。

.then(result => {

// 此处仅处理result中firstCategory和secondCategory均不为空的情况

let firstTemp = _that.getCategoryListFormat(result.firstCategory, _that.categoryList)

let secondTemp = _that.getCategoryListFormat(result.secondCategory, _that.secondCategoryList)

let promiseArr = [firstTemp, secondTemp].filter(_ => _)

Promise.all(promiseArr).then((formatRes) => {

// 触发列表数据响应

this.$set(_that.categoryList, formatRes[0].tragetCategoryList)

this.$set(_that.secondCategoryList, formatRes[1].tragetCategoryList)

_that.$nextTick(() => {

// 数据加载完成后,在下一次循环中回显

_that.category = formatRes[0].category

_that.secondCategory = formatRes[1].category

})

})

})

},

getCategoryListFormat (categorySelectList, tragetCategoryList) {

return new Promise((resolve, reject) => {

const category = []

let flag = 0

let counter = categorySelectList.length

categorySelectList.forEach(v => { // 遍历已选择节点数据

const oneNode = v

const twoNode = v.children

const threeNode = v.children.children

const codeArr = [oneNode.code, twoNode.code, threeNode.code]

category.push(codeArr)

twoNode.children = twoNode.children ? twoNode.children : []

let twolist = this.getChildrenList(codeArr[0], 1)

let thirdlist = this.getChildrenList(codeArr[1], 2)

Promise.all([twolist, thirdlist]).then((data) => {

let twochildren = data[0]

let threechildren = data[1]

threechildren = threechildren.map(item => ({ leaf: true, ...item })) // 三级节点设置成叶子节点

twoNode.children = threechildren

tragetCategoryList.forEach(w => { // 遍历列表添加相应节点数据

if (w.code === oneNode.code) {

if (!w.children) {

w.children = twochildren

}

w.children.forEach(item => {

if (item.code === twoNode.code) {

item.children = twoNode.children

}

})

}

})

flag++

if (flag === counter) {

resolve({ tragetCategoryList, category })

}

})

})

})

},

getChildrenList (fid, level = 0) {

return new Promise((resolve, reject) => {

API.getCategory({ fid: fid, level: level }).then(

res => {

if (res) {

if (res.code === 0 && res.result) {

resolve(res.result)

}

}

}

)

})

},

getCategory(fid = 0, level = 0) {

API.getCategory({ fid: fid, level: level })

.then(

res => {

if (res) {

if (res.code == 0 && res.result) {

this.categoryList = this.deepClone(res.result);

}

}

}

)

},

deepClone (source) { // 深拷贝

if (!source && typeof source !== 'object') {

throw new Error('error arguments', 'shallowClone')

}

const targetObj = source.constructor === Array ? [] : {}

Object.keys(source).forEach(keys => {

if (source[keys] && typeof source[keys] === 'object') {

targetObj[keys] = source[keys].constructor === Array ? [] : {}

targetObj[keys] = deepClone(source[keys])

} else {

targetObj[keys] = source[keys]

}

})

return targetObj

}

}

}

补充知识:Ant Design 级联选择的一种写法

简单记录类似省、市、区或品牌、车系、车型等多级结构,级联选择添加并展示的一种写法:

import React from 'react';

import {Button, Form, message, Row, Tag,Select,Col} from 'antd';

import request from "../../../../utils/request";

const FormItem = Form.Item;

const Option = Select.Option;

class CarSeriesCascader extends React.Component {

constructor(props) {

super(props);

this.state = {

defaultBrandList:[],

selectedCarModelList: props.carModelList ? props.carModelList : [],

brandCode:null,

carModelList:[],

carId:null,

modelCode:null,

modelName:null

}

}

componentDidMount() {

let promise = 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) => {

let limitList = selectedCarModelList.map((carModel,index) => {

let limitItem = {};

limitItem.modelName = carModel.modelName;

limitItem.modelCode = carModel.modelCode;

limitItem.carId = carModel.carId;

return limitItem;

});

return limitList;

}

addCarModel = () => {

let addCarModel = {};

let selectedCarModelList = this.state.selectedCarModelList;

// 选中车型号

if (this.state.carId !== null) {

// 检查车型是否已选中

for (let index = this.state.selectedCarModelList.length - 1; index >= 0; index--) {

let carModel = 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) {

let limitList = this.getLimitList(selectedCarModelList);

this.props.onChange(limitList);

}

}

deleteTag = (limitCode) => {

debugger

let selectedCarModelList = 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) {

let promise = 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;

//品牌名称列表

let allBrandListOption = this.state.defaultBrandList != null ? this.state.defaultBrandList.map((item, index) => {

return ;

}) : null;

//车型名称列表

let allModelListOption = this.state.carModelList != null ? this.state.carModelList.map((item, index) => {

return ;

}) : null;

const {

closable=true,

} = this.props;

const existCarModel = [];

const limitList = this.getLimitList(this.state.selectedCarModelList);

for (let index = limitList.length - 1; index >= 0; index--) {

let limitItem = limitList[index];

existCarModel.push(

key={limitItem.modelCode}

closable={closable}

onClose={(e) => {

e.preventDefault();

this.deleteTag(limitItem.modelCode);

}}

>{limitItem.modelName});

}

return (

{getFieldDecorator('brandName', {

rules: [{

message: '请选择品牌'

}],

})(

placeholder="品牌"

dropdownMatchSelectWidth={false}

onChange={this.brandChange}

style={{ marginRight: 10, width: 100 }}>

{allBrandListOption}

)}

{getFieldDecorator('modelName', {

rules: [{

message: '请选择车型'

}],

})(

placeholder="车型"

dropdownMatchSelectWidth={false}

onChange={this.modelChange}

style={{ marginRight: 10, width: 260 }}>

{allModelListOption}

)}


{existCarModel}

)

}

}

export default Form.create()(CarSeriesCascader);

vx:19906048603
vx:19906048603 vx:19906048603
返回顶部
返回顶部 返回顶部