前言
在做前端开发过程中,我们经常会遇到这样的需求:要求动态增减输入框、下拉选择等输入元素(如下图)。
如果是Vue新手的话可能会疑惑:“我一个 input
输入框或者 select
下拉选择只能绑定一个 v-model
,如果动态增减,我们都不知道总共有多少个或者多少组输入元素,我们应该如何处理动态的 v-model
呢?”
解决思路
使用数组作为状态数据,然后把单个 / 或者单组输入元素封装为 Vue 子组件。面对这种动态增减输入元素的处理方式一般我们是化繁为简。单个 / 单组输入元素封装为单个 Vue 组件后,在组件里面我们就可以愉快地给每个元素定义一个 v-model
来处理了,我们还可以给组件外暴露属性 props
和事件 events
供外部调用。动态增减的处理也相对简单,就维护一个数组,数组里面每条数据对应一个上面定义的 Vue 组件;这样,对数组进行增删改,直接更新到组件视图。
组件实现代码
这里以一个简单的 elementUI 输入框为例
<template>
<div class="panel__item clearfix">
<div class="left panel__label">
{{ label }}
</div>
<div
:class="{'last': isLastItem}"
class="right panel__input"
>
<el-input
v-model="value"
size="small"
placeholder="请填写"
@change="change"
/>
<el-button
v-if="isLastItem"
type="primary"
size="small"
@click="deleteItem"
>一</el-button>
<div
v-if="isLastItem"
class="add-item"
@click="addItem"
>
<el-button
type="primary"
size="small"
>十</el-button><span class="add-item__desc">添加输入框</span>
</div>
</div>
</div>
</template>
export default {
props: {
defaultValue: {
type: Object,
default: () => {
return {
label: '',
value: '',
isLastItem: false
}
}
}
},
data () {
return {
value: '',
label: '',
isLastItem: ''
}
},
created () {
this.value = this.defaultValue.value
this.label = this.defaultValue.label
this.isLastItem = this.defaultValue.isLastItem
},
methods: {
change (value) {
this.$emit('change', value)
},
deleteItem () {
this.$emit('deleteItem', this.label, this.value)
},
addItem () {
this.$emit('addItem')
}
}
}
外部调用方式
外部调用方式要注意传参的方式的处理,代码如下:
<my-input
v-for="(item, index) in items"
:key="index"
:default-value="{ label : item.label, value : item.value }"
@change="(label, val) => inputChange(label, val, index)"
@addItem="addItem"
@deleteItem="() => deleteItem(index)"
/>
methods: {
inputChange (val, index) {
// 相应改变items数组对应index元素的数据
},
addItem () {
// 相应改变items数组,push一个元素
},
deleteItem (index) {
// 相应删除items数组对应index元素的数据
}
}
扩展
上面只是一个最简单的动态增减元素 / 组件的处理方式,如果要动态增加的组件里面需要再嵌套动态增减元素 / 组件呢?如法炮制!
还是一样的处理方式,定义好最小粒度的一个或者一组元素使用 v-model
绑定好的一个 Vue 组件,然后往上就是处理多维数组的操作(对数组元素进行增删改查而已)。