目录
输入式动态添加
单选式动态添加
组合式动态添加
组合式动态添加(回传名称)
单选、多选组合式
数据回显
完整示例
总结
单选切换多选(补充)
下拉框渲染卡顿问题(补充)
双循环遍历优化
输入式:即input的值由用户输入;例如:通过自定义用户标签,给用户动态添加多个标签。
添加
查看
例如:给一名老师动态添加多个监考科目,后台接收科目代码(courseId)。
list: [
{ courseId: '', id: '1' }
],
options: [
{ value: '123', label: '英语' },
{ value: '456', label: '数学' },
{ value: '868', label: '语文' },
{ value: '672', label: '化学' },
{ value: '684', label: '物理' }
],
// 动态添加
addInput () {
this.list.push({ id: Date.now(), courseId: '' })
},
例如:给学生各个科目打上分数。
list1: [
{ courseId: '', id: '1', grade: '' }
],
options: [
{ value: '123', label: '英语' },
{ value: '456', label: '数学' },
{ value: '868', label: '语文' },
{ value: '672', label: '化学' },
{ value: '684', label: '物理' }
],
addInput () {
this.list1.push({ id: Date.now(), courseId: '', grade: '' })
},
// this.list1
// [
// {
// "courseId":"123",
// "id":"1",
// "grade":"96"
// },
// {
// "id":1636423648221,
// "courseId":"456",
// "grade":"100"
// }
// ]
例如:给学生各个科目打上分数,后端需要同时接收科目名称和科目id。
// 后台接收的数据
courseList:[
{courseId: '', grade: '', courseName: '' }
{courseId: '', grade: '', courseName: '' }
]
这时候,只需要给el-select添加change事件,在获取id的同时获取到名称即可。
changeOneCourse(val, index) {
this.options.find((item) => {
if (item.value === val) {
this.list2[index]['courseName'] = item.label // 根据绑定值id获取到名称label
}
})
}
// this.list2: [
// {
// "courseId":"123",
// "id":"1",
// "grade":"96",
// "courseName":"英语"
// }
// ]
例如:给各个年级添加不同科目,后端需要同时接收【科目名称,科目id】,【年级id,年级名称】。
gradeList:[
{ courseList: [
{ courseId: '', courseName: '' },
{ courseId: '', courseName: '' }
],
gradeData: { grade: '', gradeName: ' ' }
}
]
添加
查看
list3: [
{ gradeList: '', id: '1', courseList: '' }
],
options: [
{ value: '123', label: '英语' },
{ value: '456', label: '数学' },
{ value: '868', label: '语文' },
{ value: '672', label: '化学' },
{ value: '684', label: '物理' }
],
options1: [
{ value: '1238635', label: '一年级' },
{ value: '4568635', label: '二年级' },
{ value: '8688635', label: '三年级' },
{ value: '6728635', label: '八年级' },
{ value: '6848635', label: '九年级' }
],
courseList: [], // 存放多选
grade: [], // 存放单选
name: [],
methods: {
addInput () {
this.list3.push({ id: Date.now(), gradeList: '', courseList: '' })
},
search () {
let arr3 = []
for (let i = 0; i < this.courseList.length; i++) {
arr3.push(Object.assign(this.courseList[i] || {}, this.grade[i] || {})) // 合并数组对象
}
console.log(arr3) // 输出传给后台的结构
},
// 处理多选的值
changeSelect (val, index) {
let courseList = { courseList: [] }
this.name = []
this.courseList[index] = courseList // 初始化第一个值
// =====================根据变化的值赋值,有就赋值,无就删除===========================
for (let i = 0; i <= val.length - 1; i++) {
this.options.find((item) => {
if (item.value === val[i]) {
this.name.push(item.label) // 根据绑定值id获取到名称label
}
})
}
// =====================进行赋值===========================
for (let i = 0; i <= val.length - 1; i++) {
let obj = {}
obj['courseId'] = val[i]
obj['courseName'] = this.name[i]
this.courseList[index]['courseList'].push(obj)
}
console.log(this.courseList) // 相当于多选课程的数据
},
changeGrad (val, index) {
this.options1.find((item) => {
if (item.value === val) {
this.list2[index]['gradeName'] = item.label // 根据绑定值id获取到名称label
}
})
let grade = { grade: { gradeName: '', gradeId: '' } }
//
let gradeName = ''
this.grade[index] = grade // 初始化第一个值
this.options1.find((item) => {
if (item.value === val) {
gradeName = item.label // 根据绑定值id获取到名称label
}
})
// =====================进行赋值===========================
this.grade[index]['grade']['gradeName'] = gradeName
this.grade[index]['grade']['gradeId'] = val
console.log(this.grade) // 相当于单选年级的数据
}
}
动态添加数据之后,数据也正常提交给了后台,往往数据可能还需要编辑或修改,那就会涉及到数据的回显问题。
// 定义一个test方法,和echoData查看回显的数据是否正确
// 数据回显
echoData () {
this.isChange = false
this.arr3 = this.echoList // arr3提到data中全局保存
let courseList = [] // 保存多选的值
let obj = {}
// 回显时初始化单选值(年级)
this.grade = this.echoList.map(item => {
return { grade: { ...item.grade } }
})
// 回显时初始化多选值(课程)
for (let key in this.echoList) {
let obj = {}
obj['courseList'] = this.echoList[key]['courseList']
this.courseList.push(obj)
}
// 1.拆分后台数据,构造年级回显
this.options1 = this.echoList.map(item => {
item.courseList.forEach(val => {
courseList.push(val)
})
return {
value: item.grade['id'],
label: item.grade['gradeName']
}
})
// 数组对象去重
courseList = courseList.reduce((a, b) => {
obj[b.id] ? '' : obj[b.id] = true && a.push(b)
return a
}, [])
// 2.拆分后台数据,构造科目回显
this.options = courseList.map(item => {
return {
value: item.id,
label: item.courseName
}
})
// 3.拆分后台数据,构造动态绑定的数据回显
this.list3 = this.echoList.map(item => {
let course = []
item.courseList.forEach(val => {
course.push(val.id)
})
return {
gradeList: item.grade['id'],
courseList: course
}
})
console.log(this.arr3)
},
// 用于检查回显数据的赋值是否正确
test () {
this.courseList = []
this.grade = []
// 回显时初始化单选值(年级)
this.grade = this.echoList.map(item => {
return { grade: { ...item.grade } }
})
// 回显时初始化多选值(课程)
for (let key in this.echoList) {
let obj = {}
obj['courseList'] = this.echoList[key]['courseList']
this.courseList.push(obj)
}
console.log(this.grade)
console.log(this.courseList)
}
这里暂时不对代码进行优化处理。
添加
查看
回显
测试
1、动态添加Input,需要密切关注页面和后台数据的处理,简单的直接绑定v-for的item,复杂的需要根据具体需求,进行调整;
2、获取id的同时利用find()获取名称;
3、纯数组合与数组对象之间的转换、合并,利用循环合自定义obj={}保存对象,并循环输出;
4、数组对象的合并,利用Object.assign(),先合并对象;
5、同时获取名称和id需要在change方法里面,同时进行,根据有值就添加,无值就删除原理;
6、数据回显,要保证数据跟动态添加时的绑定值一致 。
当输入框根据条件,既可以单选,又可以多选时,会出现切换模式时,无法清除数据的问题。
可能是切换模式时,需要重新 v-model,但容器又没有重新渲染导致,因此可以在切换的时候,让容器重新渲染,重新 v-model ,首先给选择课程添加 v-if,,然后观察 isMultiple 的变化,变化时,让课程容器重新渲染即可。
watch: {
isMultiple (val) {
if (val) {
this.isShowSelect = false
setTimeout(() => {
this.isShowSelect = true
})
}
}
},
下拉框渲染卡顿问题(补充)
当渲染的数据量很大时,一次性渲染,会造成页面卡顿,甚至内存溢出现象,一次性渲染超过2000条数据的下拉框,就会出现卡顿现象(小编自测的结果,不一定准确)。解决的方法是:分页,同时支持搜索,那就可以使用 Element 的 Cascader 级联选择器。
既然多数据,那必然需要支持多选。
分页下的多选,在点击下一页的时候,会把上一页选择的数据清空,怎么办呢?
那就把在上页中选择的数据,保存起来,在下一页中,加入渲染中去即可。
// @change 中保存选择的数据
changeOptionValue (val) {
this.saveOptionsValue = val; // 保存选择的数据
},
// 在点击下一页时,把上一页选择的数据 push 到渲染中去
managersCurrentChange (val) {
const hash = {};
// 每次点击时,把重复数据过滤掉,不然点击一次,就会 push 一次重复数据
this.pushOptionsList = this.saveOptionsValue.reduce(function (prev, cur) {
!hash[cur.value] ? hash[cur.value] = prev.push({ label: cur.label, value: { value: cur.value, label: cur.label } }) : '';
return prev;
}, []);
this.optionsValue = this.saveOptionsValue;
this.managersPageNo = val;
this.renderData(); // 接口调用,渲染数据
},
renderData(){
.......
// 把上一页选择的数据,加到数组最前面
this.pushOptionsList.length !== 0 && this.List.unshift(...this.pushOptionsList);
}
最后,在数据渲染时,要给一个渲染中的提示,最好是全局的,同时禁止用户其他的操作。毕竟数据量多,渲染需要一定的时间,这段时间不能被其他操作影响。
openFullScreen2() {
const loading = this.$loading({
lock: true,
text: 'Loading',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
setTimeout(() => {
loading.close();
}, 2000);
}
当然分页是不太符合页面操作逻辑的,数据多的时候,应该满足模糊搜索,而不是一页页去查,再进行搜索。 查这一步,明显多余,那一步到位的做法是什么呢?element的Select选择器就给我们提供了,远程搜索的功能
注意:当el-select开启多选的时候,size最好是medium以上,不然,有时候会发生页面抖动现象
双循环遍历优化
在拆分后台数据,构造年级回显时,用到了下面所示代码
可以看到使用map()和forEach循环遍历数据,这里双循环的时间复杂度为O(n²),当数据量大的时候,太消耗性能了,因此需要优化一下,
// 1.拆分后台数据,构造年级回显
this.options1 = this.echoList.map(item => {
item.courseList.forEach(val => {
courseList.push(val)
})
return {
value: item.grade['id'],
label: item.grade['gradeName']
}
})
// 优化代码,拆分双层遍历,降低时间复杂度,O(n)
this.echoList.map(item => {return item.courseList}).forEach(val =>{
courseList.push(...val)
})
this.options1 = echoList.map(item =>{
return {
value: item.grade['id'],
label: item.grade['gradeName']
}
})
【Vue-Vant】Checkbox复选框--案例分析多选和全选是复选框中的基本组成部分,复选框用于在选中和非选中状态之间进行切换。在很日常场景中都是很常见的,这里是个小案例,记录平时复选框的运用https://blog.csdn.net/weixin_45785873/article/details/112984637