真正开发过小程序的开发者会发现,小程序里面的单选框和多选框封封装的实在不够友好,一般与 UI 都会有比较大的出入,所以下面来探讨一下单选框和多选框的封装。
效果
比如我们要做一个这种样式的单选框和多选框组件,我们改怎么去处理呢?
代码
wxml
html
<!-- 判断某个元素是不是指定数组内 -->
<wxs module="checkbox">var checkStatus = function (arr, item) { return arr.indexOf(item) >= 0 }; module.exports.checkStatus = checkStatus;</wxs>
<view hidden="{{isHidden}}">
<!-- 单选组件 -->
<radio-group class="radio-group" bindchange="radioChange" wx:if="{{selectType == 'radio'}}">
<label class="{{radioIndex == item.index ? focusRadioClass : initRadioClass}}" wx:for="{{radioData}}" wx:key="{{index}}" id="{{item.index}}">
<view class="item-index">
<radio style="opacity: 0" value="{{item.index}}" checked="{{item.checked}}" />
<view class="index">{{item.index}}</view>
</view>
<view class="flex-item text-center">{{item.value}}</view>
</label>
</radio-group>
<!-- 多选组件 -->
<checkbox-group class="checkbox-group" bindchange="checkboxChange" wx:if="{{selectType == 'checkbox'}}">
<label
class="{{checkbox.checkStatus(checkboxIndexArr, item.index) ? focusCheckboxClass : initCheckboxClass}}"
wx:for="{{checkboxData}}"
wx:key="{{index}}"
id="{{item.index}}"
>
<view class="item-index">
<checkbox
style="opacity: 0"
value="{{item.index}}"
checked="{{item.checked}}"
disabled="{{checkboxIndexArr.length > maxLength - 1 && !checkbox.checkStatus(checkboxIndexArr, item.index)}}"
/>
<view class="index">{{item.index}}</view>
</view>
<view class="flex-item text-center">{{item.value}}</view>
</label>
<view>{{checkboxIndexArr.prototype}}</view>
</checkbox-group>
</view>
wxss
css
.flex-wrapper {
display: flex;
}
.flex-item {
flex: 1;
}
.text-center {
text-align: center;
}
.radio-group,
.checkbox-group {
margin: 0 auto;
width: 490rpx;
}
.radio-group label,
.checkbox-group label {
margin-bottom: 50rpx;
height: 68rpx;
line-height: 68rpx;
border: 1rpx solid #000;
border-radius: 10rpx;
font-size: 30rpx;
color: #000;
}
.radio-group label.active,
.checkbox-group label.active {
background-color: #fcc919;
}
.radio-group label .item-index,
.checkbox-group label .item-index {
position: relative;
flex: 0 0 40rpx;
margin: 0 0 0 20rpx;
width: 40rpx;
height: 68rpx;
}
.radio-group label .item-index .index,
.checkbox-group label .item-index .index {
position: absolute;
top: 0;
bottom: 0;
left: 0;
margin: auto;
width: 40rpx;
height: 40rpx;
overflow: hidden;
line-height: 40rpx;
text-align: center;
border-radius: 50%;
background-color: #fff;
}
javascript
javascript
Component({
// 组件的属性列表
properties: {
selectType: {
type: String,
value: 'checkbox',
},
radioData: {
type: Array,
value: [],
},
checkboxData: {
type: Array,
value: [],
},
isHidden: {
type: Boolean,
value: false,
},
maxLength: {
type: Number,
value: 2,
},
},
// 组件的初始数据
data: {
initRadioClass: 'radio flex-wrapper flex-direction-row',
focusRadioClass: 'radio flex-wrapper flex-direction-row active',
initCheckboxClass: 'checkbox flex-wrapper flex-direction-row',
focusCheckboxClass: 'checkbox flex-wrapper flex-direction-row active',
radioIndex: null,
checkboxIndexArr: [],
},
// 组件的方法列表
methods: {
// radio选择改变触发的函数
radioChange: function (e) {
let value = e.detail.value
this.setData({
radioIndex: value,
})
this.triggerEvent('radioChange', value)
},
// checkbox选择改变触发的函数
checkboxChange: function (e) {
let value = e.detail.value
this.setData({
checkboxIndexArr: value,
})
this.triggerEvent('checkboxChange', value)
},
},
})
分析
其中,单选框比较简单,重点在于多选框。其中比较坑的地方就是需要手动来控制 checkboxIndexArr
的内容。
小程序多选框 在选中后会返回一个所选中的 value 的数组
checkboxIndexArr
,所以我们自定义的样式需要通过判断当前框的value
是不是在checkboxIndexArr
中(切记,checkboxIndexArr 中的每个值的类型都是 String), 小程序在 wxml 中绑定方法时没办法携带参数的,所以需要需要将这个函数写在wxs
中。如果需要有默认选中,需要单独把默认选中的框的样式激活,同时手动将默认选中的框的 checked 设置为
true
,并将其value
放入checkboxIndexArr
中。如果需要做全选和全不选,需要在放置一个变量
checked
,Boolean 属性,通过控制checked
开控制是否全选,但是,还是需要手动 来添加和清空checkboxIndexArr
的内容。如果需要做反选功能,需要在数据中单独设置一个控制 是否选中的 checked 属性,通过改变数据 checked 的值来改变多选框的选中效果,与上面一样,还是要手动 来添加和清空
checkboxIndexArr
的内容。