Vue+Element一步步实现动态添加Input

您所在的位置:网站首页 input输入框组件判断题 Vue+Element一步步实现动态添加Input

Vue+Element一步步实现动态添加Input

2023-09-01 20:39| 来源: 网络整理| 查看: 265

目录

输入式动态添加

单选式动态添加

组合式动态添加

组合式动态添加(回传名称)

单选、多选组合式

数据回显

完整示例

总结

单选切换多选(补充)

下拉框渲染卡顿问题(补充)

双循环遍历优化

输入式动态添加

输入式:即input的值由用户输入;例如:通过自定义用户标签,给用户动态添加多个标签。

添加 查看 export default { data () { return { table: [ { id: '12121', label: '' } ] } }, methods: { // 动态添加 addInput () { this.table.push({ id: Date.now(), label: '' }) }, // 查看 search () { console.log(this.table) }, } } 单选式动态添加

例如:给一名老师动态添加多个监考科目,后台接收科目代码(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 { if (item.value === val[i]) { this.name.push(item.label) // 根据绑定值id获取到名称label } }) } // =====================进行赋值=========================== for (let i = 0; i { 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) } 完整示例

这里暂时不对代码进行优化处理。

添加 查看 回显 测试 export default { name: 'teacher', data () { return { value1: [], table: [ { id: '12121', label: '' } ], list: [ { courseId: '', id: '1' } ], list1: [ { courseId: '', id: '1', grade: '' } ], list2: [ { courseId: '', id: '1', grade: '', courseName: '' } ], 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: [], gradeList: [], // 分数列表 echoList: [ { 'id': '55cca14cad60430191c0c3840a63b50c', 'grade': { 'id': 'd3d16e7edcbb4c1fb09759725c956dd4', 'gradeName': '二年级' }, 'courseList': [ { 'id': '1455377986034917378', 'courseName': '地理' }, { 'id': '1455377934050713601', 'courseName': '数学' } ] }, { 'id': '55cca14cad60430191c0c3840a63b50c', 'grade': { 'id': 'fe3c385ab7c745a692f2c4b32c0cb2a0', 'gradeName': '八年级' }, 'courseList': [ { 'id': '1455377934050713601', 'courseName': '数学' }, { 'id': '1455377958553837569', 'courseName': '历史' } ] } ], isChange: false, arr3: [] } }, methods: { addInput () { this.table.push({ id: Date.now(), label: '' }) this.list.push({ id: Date.now(), courseId: '' }) this.list1.push({ id: Date.now(), courseId: '', grade: '' }) this.list2.push({ id: Date.now(), courseId: '', grade: '', courseName: '' }) this.list3.push({ id: Date.now(), gradeList: '', courseList: '' }) }, search () { // 根据isChange判断数据是否发生变化,如果没发生变化arr3则为后台返回的数据,说明页面未发生变化 if (this.isChange) { this.arr3 = [] for (let i = 0; i < this.courseList.length; i++) { this.arr3.push(Object.assign(this.courseList[i] || {}, this.grade[i] || {})) // 合并数组对象 } } console.log(this.arr3) // 输出传给后台的结构 }, // 处理多选的值 changeSelect (val, index) { this.isChange = true let courseList = { courseList: [] } this.name = [] this.courseList[index] = courseList // 初始化第一个值 // =====================根据变化的值赋值,有就赋值,无就删除=========================== for (let i = 0; i { if (item.value === val[i]) { this.name.push(item.label) // 根据绑定值id获取到名称label } }) } // =====================进行赋值=========================== for (let i = 0; i { // if (item.value === val) { // this.list2[index]['courseName'] = item.label // 根据绑定值id获取到名称label // } // }) // }, changeGrad (val, index) { this.isChange = true // 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) // 相当于单选年级的数据 }, // 数据回显 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) } } } .app{ margin: 50px auto; width: 500px; } .el-input{ margin-bottom: 20px; width: 200px; } .el-select{ margin-bottom: 20px; margin-right: 10px; } 总结

 1、动态添加Input,需要密切关注页面和后台数据的处理,简单的直接绑定v-for的item,复杂的需要根据具体需求,进行调整;

2、获取id的同时利用find()获取名称;

3、纯数组合与数组对象之间的转换、合并,利用循环合自定义obj={}保存对象,并循环输出;

4、数组对象的合并,利用Object.assign(),先合并对象;

5、同时获取名称和id需要在change方法里面,同时进行,根据有值就添加,无值就删除原理;

6、数据回显,要保证数据跟动态添加时的绑定值一致 。

单选切换多选(补充)

当输入框根据条件,既可以单选,又可以多选时,会出现切换模式时,无法清除数据的问题。

data () { return { isMultiple: '0', isShowSelect: true, isShow: false, course: '', grade: '', options: [ { value: '1238635', label: '一年级', isMultiple: '0' }, { value: '4568635', label: '二年级', isMultiple: '0' }, { value: '8688635', label: '三年级', isMultiple: '1' }, { value: '6728635', label: '八年级', isMultiple: '1' }, { value: '6848635', label: '九年级', isMultiple: '1' } ], options1: [ { value: '123', label: '英语' }, { value: '456', label: '数学' }, { value: '868', label: '语文' }, { value: '672', label: '化学' }, { value: '684', label: '物理' } ] } }, methods: { if (val) { // 改变年级时,判断是否可多选 this.isMultiple = this.options.find(item => item.value === val).isMultiple // 多选时,绑定的是数组,单选绑定的是字符串,出现问题的地方可能是这里 this.isMultiple === '1' ? this.course = [] : this.course = '' } }

  

可能是切换模式时,需要重新 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选择器就给我们提供了,远程搜索的功能

// 远程搜索 remoteMethod (query) { if (query !== '') { setTimeout(() => { // 调用接口,模糊查询 }, 200); } else { this.managersList = []; } },

 注意:当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



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3