前言:作者想实现的功能类似一个uniapp选择器,但是可以选择多个值,同时又可以单选和全选,在uniapp 的UI框架去找,发现没有类似的,最后在uniapp 的插件市场找到了这个multiple-select 里面的功能比较全实现了单选全选并同时可以选择多个值,还可以禁用某一项数据,自己做了一下更改记录一下,希望大家以后能用到。
组件封装:multiple-select.vue
<template>
<view class="select-container" v-show="show" @touchmove.stop.prevent>
<view
class="mask"
:class="activeClass ? 'mask-show' : ''"
@tap="onCancel(true)"
></view>
<view class="select-box" :class="activeClass ? 'select-box-show' : ''">
<view class="header">
<text class="cancel" @tap="onCancel">{{ cancelText }}</text>
<view class="all" @tap="onAllToggle" v-if="allShow">
<text :class="isAll ? 'all-active' : ''">全选 </text>
</view>
<text class="confirm" @tap="onConfirm">{{ confirmText }}</text>
</view>
<view class="body-warp">
<scroll-view class="body" scroll-y="true">
<slot v-if="!data.length" name="tips">
<view class="empty-tips">暂无数据~</view>
</slot>
<view
class="select-item"
:class="[
item.disabled ? 'disabled' : '',
selectedArr[index] ? 'selected' : '',
]"
v-for="(item, index) in data"
:key="item[valueName]"
@tap="onSelected(index)"
>
<view class="label">{{ item.name }}</view>
<text v-show="selectedArr[index]" class="selected-icon">✔</text>
</view>
</scroll-view>
</view>
</view>
</view>
</template>
<!-- 多选组件 -->
<script>
export default {
model: {
prop: "value",
event: ["input"],
},
data() {
return {
show: false, //是否显示
activeClass: false, //激活样式状态
selectedArr: [], //选择对照列表
selectedArrOld: [], //选择对照列表上一次的数据
};
},
onShow() {
this.show = this.value;
console.log(this.serviceList);
},
computed: {
// 返回是否全选
isAll() {
let wipeDisabledList = this.returnWipeDisabledList();
if (!wipeDisabledList.length) return false;
return !wipeDisabledList.includes(false);
},
},
props: {
// 双向绑定
value: {
type: Boolean,
default: false,
},
// 取消按钮文字
cancelText: {
type: String,
default: "取消",
},
// 确认按钮文字
confirmText: {
type: String,
default: "确认",
},
// label对应的key名称
labelName: {
type: String,
default: "label",
},
// value对应的key名称
valueName: {
type: String,
default: "value",
},
// 是否允许点击遮罩层关闭
maskCloseAble: {
type: Boolean,
default: true,
},
// 是否显示全选
allShow: {
type: Boolean,
default: true,
},
// 模式
mode: {
type: String,
default: "multiple",
},
// 默认选中值
defaultSelected: {
type: Array,
default: function () {
return [];
},
},
// 数据源
data: {
type: Array,
required: true,
default: () => {
return [];
},
},
},
created() {
console.log(this.data, "111111");
},
watch: {
async value(newVal) {
this.show = newVal;
await this.$nextTick();
this.activeClass = newVal;
if (newVal) {
this.selectedArrOld = JSON.parse(JSON.stringify(this.selectedArr));
}
},
async data(newVal) {
this.data = newVal;
await this.$nextTick();
console.log(this.data);
},
show(newVal) {
this.$emit("input", newVal);
this.$emit("change", newVal);
},
data: {
// 设置初始选择对照列表
handler(list) {
this.selectedArr = list.map((el) => false);
this.setItemActiveState();
},
deep: true,
immediate: true,
},
defaultSelected: {
handler() {
this.setItemActiveState();
},
deep: true,
immediate: true,
},
},
methods: {
// 设置默认选中通用办法
setItemActiveState() {
if (this.data.length && this.defaultSelected.length) {
this.data.forEach((item, i) => {
for (let n = 0; n < this.defaultSelected.length; n++) {
if (
!item.disabled &&
item[this.valueName] === this.defaultSelected[n]
) {
this.selectedArr.splice(i, 1, true);
break;
}
}
});
}
},
/**
* 选择事件
* @index {Number} 点击下标
*/
onSelected(index) {
if (this.data[index].disabled) return;
let index2Active = this.selectedArr[index];
this.selectedArr.splice(index, 1, !index2Active);
},
// 取消事件
onCancel(isMask) {
if (!isMask || this.maskCloseAble) {
this.show = false;
this.selectedArr = JSON.parse(JSON.stringify(this.selectedArrOld));
} else {
return;
}
this.$emit("cancel");
},
// 返回去除了disabled状态后的对照列表
returnWipeDisabledList() {
let arr = [];
this.selectedArr.forEach((el, index) => {
if (!this.data[index].disabled) arr.push(el);
});
return arr;
},
// 全选/非全选事件
onAllToggle() {
let wipeDisabledList = this.returnWipeDisabledList();
// 如果去除了disabled的对照列表有false的数据,代表未全选
if (wipeDisabledList.includes(false)) {
this.selectedArr.forEach((el, index) => {
if (!this.data[index].disabled)
this.selectedArr.splice(index, 1, true);
});
} else {
this.selectedArr.forEach((el, index) => {
if (!this.data[index].disabled)
el = this.selectedArr.splice(index, 1, false);
});
}
},
// 确定事件
onConfirm() {
console.log(11212);
this.show = false;
let selectedData = [];
this.selectedArr.forEach((el, index) => {
if (el) {
console.log(el);
selectedData.push(this.data[index]);
}
});
if (this.mode === "multiple") {
console.log(selectedData);
this.$emit("confirm", selectedData);
} else {
let backData = selectedData[0] || {};
this.$emit("confirm", backData);
}
},
},
};
</script>
<style lang="scss" scoped>
.select-container {
width: 100vw;
height: 100vh;
position: fixed;
left: 0;
top: 0;
z-index: 999;
$paddingLR: 18rpx;
.mask {
width: 100%;
height: 100%;
background-color: $uni-bg-color-mask;
opacity: 0;
transition: opacity 0.3s;
&.mask-show {
opacity: 1;
}
}
// 选择器内容区域
.select-box {
width: 100%;
position: absolute;
bottom: 0;
left: 0;
transform: translate3d(0px, 100%, 0px);
background-color: $uni-bg-color;
transition: all 0.3s;
&.select-box-show {
transform: translateZ(0);
}
.header {
display: flex;
box-sizing: border-box;
width: 100%;
justify-content: space-between;
border-bottom: 1px solid $uni-border-color;
line-height: 76rpx;
font-size: 30rpx;
padding: 0 $paddingLR;
.cancel {
color: $uni-text-color-grey;
}
.all {
color: $uni-color-success;
.all-active {
&::after {
display: inline-block;
content: "✔";
padding-left: 8rpx;
}
}
}
.confirm {
color: $uni-color-primary;
}
}
.body-warp {
width: 100%;
height: 30vh;
box-sizing: border-box;
padding: 20rpx $paddingLR;
}
.body {
width: 100%;
height: 100%;
overflow-y: auto;
.empty-tips {
margin-top: 25%;
text-align: center;
font-size: 26rpx;
color: $uni-color-error;
}
.select-item {
display: flex;
font-size: 26rpx;
line-height: 58rpx;
color: #303133;
position: relative;
transition: all 0.3s;
&.selected {
color: $uni-color-primary;
}
&.disabled {
color: $uni-text-color-disable;
}
> .label {
flex: 1;
text-align: center;
}
> .selected-icon {
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
}
}
}
}
}
</style>
组件内使用:
<template>
<view class="wrap">
<multiple-select
v-model="accServiceShow"
:data="serviceList"
:default-selected="defaultSelected"
@confirm="accServiceConfirm"
></multiple-select>
</view>
</template>
<script>
import multipleSelect from "../../components/multiple-select/multiple-select.vue";
export default {
components: {
multipleSelect,
},
data(){
return{
defaultSelected: ["3", "5"], //默认选中项
serviceList: [],//传递给子组件的数据
}
}
</script>
注意:该插件非原创作者,如有侵权请联系作者删除
版权归原作者 程序猿海王秃 所有, 如有侵权,请联系我们删除。