牵涉到表单基本上离不开checkbox和radiobox,现在越来越多的程序前端采用vue来编写,就连小程序,小程序内部帮我们提供好了代码,但是需要限制选中个数,就要进行二次加工了。
修改官方代码示例
官方代码地址:https://developers.weixin.qq.com/miniprogram/dev/component/checkbox.html
我们着重看切换方法:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 
 | checkboxChange(e) {console.log('checkbox发生change事件,携带value值为:', e.detail.value)
 const items = this.data.items
 const values = e.detail.value
 for (let i = 0, lenI = items.length; i < lenI; ++i) {
 items[i].checked = false
 
 for (let j = 0, lenJ = values.length; j < lenJ; ++j) {
 if (items[i].value === values[j]) {
 items[i].checked = true
 break
 }
 }
 }
 
 this.setData({
 items
 })
 }
 
 | 
其实解决方法很简单,e.detail.value保存的是我们选中的数据,我们判断下他长度就可以了,比如我们限制最多选3个。
修改后的代码:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 
 | checkboxChange(e) {console.log('checkbox发生change事件,携带value值为:', e.detail.value)
 const items = this.data.items
 const values = e.detail.value
 // 如果长度大于3,直接删除第一个选中的
 if(values.length>3){
 values.shift()
 }
 for (let i = 0, lenI = items.length; i < lenI; ++i) {
 items[i].checked = false
 
 for (let j = 0, lenJ = values.length; j < lenJ; ++j) {
 if (items[i].value === values[j]) {
 items[i].checked = true
 break
 }
 }
 }
 
 this.setData({
 items
 })
 }
 
 | 
看似没什么问题,甚至测试几次也没发现有异常,但是你如果从下往上选择就发现很大的问题了。
比如选项依次为:中国,美国,俄罗斯,加拿大,韩国,日本。如果你选择的是加拿大、韩国和日本,再尝试点击中国、美国、俄罗斯中的任意一个,发现无效,并没有删除第一个,而添加进来新点击的选项。
此时观察下输出e.detail.value,我们点击中、美、俄,发现e.detail.value里存的就是中美俄,我们依次点击俄美中,e.detail.value中存的还是中美俄,也就是说人根本不按我们点击的顺序来依次保存选项,所以会出现选中三个再选上面的没反应了,因为上面的加在第一个了然后直接又被删除掉了。不管他们基于什么这样写的,我们就按照自己的逻辑写一个。
自定义方案
我们看下wxml可以看出他们的点击事件挂载到了checkbox-group组件上,并不是绑定到checkbox-item上,我们按照自己的逻辑就绑定到每个选项上。
直接上代码,wxml部分(我这里使用的uni-app,跟原生小程序相差不大):
| 12
 3
 4
 5
 6
 7
 
 | <checkbox-group class="block" name="purpose_abroad">
 <view class="cu-form-group" @click="checkboxChange(index)" v-for="(item, index) in purpose_abroad" :key='index'>
 <view class="title">{{item.value}}</view>
 <checkbox :class="item.checked?'checked':''" :checked="item.checked" :value="item.value"></checkbox>
 </view>
 </checkbox-group>
 
 | 
我的逻辑是点击该项,会把该项在选项列表中对应的索引带到函数中,我们在函数中根据该索引提取其值和样式控制。
js部分,包含数据项
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 
 | export default {data() {
 return {
 purpose_abroad: [{
 value: '子女教育',
 checked: false
 }, {
 value: '环境与健康',
 checked: false
 }, {
 value: '税务筹划',
 checked: false
 }, {
 value: '出行自由',
 checked: false
 }, {
 value: '海外资产配置',
 checked: false
 }, {
 value: '财富传承',
 checked: false
 }, {
 value: '海外创业',
 checked: false
 }, {
 value: '其他',
 checked: false
 }],
 purpose_abroad_result: [],
 }
 },
 methods: {
 // 出国目的
 checkboxChange(index) {
 // 判断是否已选中3项了
 if (this.purpose_abroad_result.length > 2) {
 // 删除结果中第一个选中的项
 var deleted_item = this.purpose_abroad_result.shift()
 // 循环选项列表,一一比对,找出第一项在想选列表中的索引,修改其选中状态
 for (var i = 0; i < this.purpose_abroad.length; i++) {
 // 判断该项是否是要删除的项
 if (this.purpose_abroad[i].value == deleted_item) {
 this.purpose_abroad[i].checked = false
 break
 }
 }
 }
 // 判断当前选项是否已被选
 if (this.purpose_abroad[index].checked) {
 // 如果当前项已被选中,则取消选中
 this.purpose_abroad[index].checked = false
 // 并将该选中值从结果中删除
 // 找出该项在结果中的索引
 this.purpose_abroad_result.splice(this.purpose_abroad_result.indexOf(this.purpose_abroad[index].value), 1)
 
 } else {
 // 选中该项
 this.purpose_abroad[index].checked = true
 // 将该项添加至结果中
 this.purpose_abroad_result.push(this.purpose_abroad[index].value)
 }
 
 },
 
 }
 }
 
 | 
展示效果:
![img]()