单选
案例演示
案例代码
<radio-group @change="radioChange">
<label v-for="(item, index) in radioList" :key="item.value"
:class="index === current?'option_active item':'option_default item'">
<view class="radioHidden">
<radio :value="item.value" :checked="index === current" />
</view>
<view>{{item.value}}. {{item.title}}</view>
</label>
</radio-group>
data() {
return {
// 单选题
radioList: [{
value: 'A',
title: '基本法',
},
{
value: 'B',
title: '根本法'
},
{
value: 'C',
title: '一般法律法一般法律法一般法律法一般法律法一般法律法一般法律法一般法律法一般法律法一般法律法一般法律法'
},
{
value: 'D',
title: '普通法律'
}
],
current: '',
// 单选的选中项
radioValue: '',
}
},
methods: {
// 单选题
radioChange(evt) {
for (let i = 0; i < this.radioList.length; i++) {
if (this.radioList[i].value === evt.detail.value) {
this.current = i;
break;
}
}
this.radioValue = this.radioList[this.current].value
console.log(this.radioValue);
},
}
.item {
display: flex;
padding: 16rpx 27rpx;
margin-bottom: 10rpx;
background: #D45A53;
border-radius: 31rpx;
font-size: 30rpx;
color: #FFFFFF;
}
// 选中的颜色
.option_active {
background: #D52101;
}
// 默认颜色
.option_default {
background: #D45A53;
}
.radioHidden {
display: none;
}
网址
因为单选按钮不需要展示,所以需要隐藏掉
https://uniapp.dcloud.net.cn/component/radio.html
多选
案例演示
案例代码
<checkbox-group @change="checkboxChange">
<label v-for="(item, index) in checkboxList" :key="item.value"
:class="item.checked?'option_active item':'option_default item'">
<view class="checkboxHidden">
<checkbox :value="item.value" :checked="item.checked" />
</view>
<view>{{item.value}}. {{item.title}}</view>
</label>
</checkbox-group>
data() {
return {
// 多选题
checkboxList: [{
value: 'A',
title: '基本法',
},
{
value: 'B',
title: '根本法'
},
{
value: 'C',
title: '一般法律法一般法律法一般法律法一般法律法一般法律法一般法律法一般法律法一般法律法一般法律法一般法律法'
},
{
value: 'D',
title: '普通法律'
}
],
// 复选的选中项
checkValue: []
}
},
methods: {
// 多选题
checkboxChange(e) {
var items = this.checkboxList,
values = e.detail.value;
for (var i = 0, lenI = items.length; i < lenI; ++i) {
const item = items[i]
if (values.includes(item.value)) {
this.$set(item, 'checked', true)
} else {
this.$set(item, 'checked', false)
}
}
this.checkValue = values.sort();//将其排个序
console.log(this.checkValue);
}
}
.item {
display: flex;
padding: 16rpx 27rpx;
margin-bottom: 10rpx;
background: #D45A53;
border-radius: 31rpx;
font-size: 30rpx;
color: #FFFFFF;
}
// 选中的颜色
.option_active {
background: #D52101;
}
// 默认颜色
.option_default {
background: #D45A53;
}
.checkboxHidden {
display: none;
}
其他样式
代码
<checkbox-group @change="checkboxChange">
<label v-for="(item, index) in checkboxList" :key="item.value"
:class="item.checked?'option_active checkCss':'option_default checkCss'">
<view class="checkboxHidden">
<checkbox :value="item.value" :checked="item.checked" />
</view>
<view class="checkCircle"></view>
<view class="checkTxt">{{item.title}}</view>
</label>
</checkbox-group>
checkboxList: [{
value: '1',
title: '基本法',
},
{
value: '2',
title: '根本法'
},
{
value: '3',
title: '一般法律法'
},
{
value: '4',
title: '普通法律'
}
],
// 复选的选中项
checkValue: [],
// 日期复选框
checkboxChange(e) {
var items = this.checkboxList,
values = e.detail.value;
for (var i = 0, lenI = items.length; i < lenI; ++i) {
const item = items[i]
if (values.includes(item.value)) {
this.$set(item, 'checked', true)
} else {
this.$set(item, 'checked', false)
}
}
this.checkValue = values.sort();
console.log(this.checkValue);
},
//日期重置
resetBtn() {
console.log("重置");
this.checkboxList.forEach((item) => {
console.log(item);
item.checked = false
})
this.checkValue = []
},
.checkCss {
display: flex;
align-items: center;
height: 100rpx;
border-top: 1rpx solid #E6E6E6;
font-size: 28rpx;
}
// 选中的颜色
.option_active {
color: orange;
position: relative;
}
.option_active::after {
content: '';
position: absolute;
left: 30rpx;
top: 50%;
transform: translateY(-50%);
width: 30rpx;
height: 30rpx;
border-radius: 50%;
background-color: #F47428;
}
.option_active::before{
content: '';
position: absolute;
left: 35rpx;
top: 42%;
transform: translateY(-50%);
width: 18rpx;
height: 10rpx;
border-left:2rpx solid #ffffff;
border-bottom:2rpx solid #ffffff;
transform: rotate(-45deg);
z-index: 4;
}
// 默认颜色
.option_default {
color: #000000;
position: relative;
}
.option_default::after {
content: '';
position: absolute;
left: 30rpx;
top: 50%;
transform: translateY(-50%);
width: 30rpx;
height: 30rpx;
border-radius: 50%;
border: 1rpx solid #484848;
box-sizing: border-box;
}
.checkboxHidden {
display: none;
}
.checkTxt {
margin-left: 80rpx;
}
如果打印文字
网址
因为复选按钮不需要展示,所以需要隐藏掉,点击顺序不同时,会出现[‘D’,‘A’]的顺序,使用js拍个序即可
https://uniapp.dcloud.net.cn/component/checkbox.html
案例样式
uni+vue2+uview2.0
案例代码
<view class="row">
<view class="rowLeft">订单备注</view>
<view class="rowRight" @click="openRemark">
<text :class="{'remarkCss':true,'garyColor': remarkValue=='',}">{{remarkValue?remarkValue:'选填,可填写配送注意事项等'}}</text>
</view>
</view>
<!-- 备注多选 -->
<u-popup :show="remarkPup" @close="closeRemark" mode="bottom" :closeable="true">
<view class="remarkBox">
<view class="re_title">请选择订单备注(可多选)</view>
<view class="chooseBox">
<u-checkbox-group v-model="checkboxValue1" placement="column" @change="checkboxChange">
<u-checkbox :customStyle="{marginBottom: '8px',height:'60rpx'}"
v-for="(item, index) in checkboxList1" :key="index" :label="item.title"
:name="item.title" activeColor="#54BC34">
</u-checkbox>
</u-checkbox-group>
</view>
<view style="height: 100rpx;"></view>
<view class="confirmChoose" @click="confirmChoose">确定</view>
</view>
</u-popup>
data() {
return {
// 备注多选
checkboxValue1: [],
checkboxList1: [],
remarkPup: false,
remarkValue: ''
}
},
methods: {
// 备注多选
openRemark() {
this.remarkPup = true
},
checkboxChange(n) {
console.log('change', n);
},
closeRemark() {
this.remarkPup = false
},
getRemarks() {
this.$common.request('post', '/order/getMemoLists').then((res) => {
if (res.code == 1) {
this.checkboxList1 = res.data
this.checkboxList1.map((item) => {
item.disabled = false
})
console.log(this.checkboxList1);
}
})
},
confirmChoose() {
console.log(this.checkboxValue1);
this.remarkValue = this.checkboxValue1.join()
this.remarkPup = false
},
}
// 备注
.garyColor {
color: #B8B8B8;
}
.remarkBox {
min-height: 20vh;
position: relative;
.re_title {
text-align: center;
font-weight: bold;
font-size: 30rpx;
line-height: 100rpx;
}
.chooseBox {
margin: 10rpx 4%;
}
.confirmChoose {
position: absolute;
bottom: 30rpx;
left: 5%;
width: 90%;
border-radius: 50rpx;
background-color: #54BC34;
color: #ffffff;
display: flex;
justify-content: center;
align-items: center;
font-size: 28rpx;
height: 80rpx;
}
}
多选 vue3
<view class="tags">
<checkbox-group @change="chooseTags">
<label v-for="(item, index) in tagList" :key="item.value"
:class="{'tagItem':true,'tagActive':item.checked}">
<view class="checkboxHidden">
<checkbox :value="item.value" :checked="item.checked" />
</view>
<view>{{item.title}}</view>
</label>
</checkbox-group>
</view>
其余写法:
tagList.value = res.data.check_type.map(item => {
return {
...item,
checked: false
};
})
const tagList = ref([{
value: '1',
title: '自由的灵魂',
},
{
value: '2',
title: '孤僻'
},
{
value: '3',
title: '疯言疯语'
},
{
value: '4',
title: '风风火火的少年'
}
])
const selectArr = ref([])//选中的多个标签
// 标签选择
function chooseTags(e) {
const values = e.detail.value;
tagList.value.forEach(item => {
if (values.includes(item.value)) {
item.checked = true;
} else {
item.checked = false;
}
});
selectArr.value = values.sort().join(','); //将其排个序
console.log(selectArr.value);
}
.tags {
margin-top: 30rpx;
.tagItem {
border-radius: 10rpx 10rpx 10rpx 10rpx;
border: 1rpx solid #7E7E7E;
font-size: 26rpx;
color: #3D3D3D;
display: inline-block;
padding: 9rpx 20rpx;
margin-right: 20rpx;
margin-bottom: 23rpx;
}
.tagActive {
background: #FFF5FA;
border: 1rpx solid #F364B3;
color: #F364B3;
}
.checkboxHidden {
display: none;
}
}
样式
代码
<view class="whiteBox">
<view class="title">选择支付方式</view>
<view class="methodBox">
<radio-group name="" @change="changeRadio">
<view class="paytype">
<view class="left">
<image src="/static/images/moneyIcon.png" mode="aspectFit"></image>
<view class="info">
<view class="p_title">余额</view>
<view class="p_num">
<view>当前余额 0.00</view>
<view class="line"></view>
<view>赠送金 0.00</view>
</view>
</view>
</view>
<view class="right">
<radio value="yue" color="var(--nav-bg)" :checked="true" style="transform:scale(0.8)">
</radio>
</view>
</view>
<view class="paytype">
<view class="left">
<view class="info">
<view class="p_title">XXX会员卡</view>
<view class="p_row mtop23">
<view class="p_r_col">今天可用次数: 2</view>
<view class="p_r_col">剩余天数: 256天</view>
</view>
<view class="p_row mtop10">
今天剩余可使用金额: 3元
</view>
</view>
</view>
<view class="right">
<radio value="balance" color="var(--nav-bg)" style="transform:scale(0.8)"></radio>
</view>
</view>
</radio-group>
</view>
</view>
// 选择支付方式
changeRadio(e) {
console.log(e);
},
.whiteBox {
background: #FFFFFF;
box-shadow: 0rpx 5rpx 10rpx 0rpx rgba(225, 225, 225, 0.6);
border-radius: 20rpx;
margin: 0 32rpx 27rpx;
padding-bottom: 29rpx;
.title {
height: 90rpx;
font-size: 30rpx;
color: #3F3F3F;
font-weight: bold;
display: flex;
align-items: center;
padding: 0 20rpx;
margin: 0 30rpx;
position: relative;
.title_tip {
font-size: 24rpx;
color: #015C7D;
font-weight: normal;
}
}
.title::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 8rpx;
height: 34rpx;
background: #015C7D;
}
.border {
border-bottom: 1rpx solid #E9E9E9;
}
.methodBox {
margin: 0 33rpx 0 39rpx;
.paytype {
display: flex;
align-items: center;
justify-content: space-between;
padding: 25rpx 20rpx 30rpx 22rpx;
background: #F7F7F7;
border-radius: 10rpx;
margin-bottom: 22rpx;
.left {
display: flex;
align-items: center;
width: 100%;
image {
width: 47rpx;
height: 47rpx;
}
.info {
margin-left: 16rpx;
color: #3F3F3F;
width: 100%;
.p_title {
font-weight: bold;
font-size: 28rpx;
}
.p_num {
font-size: 24rpx;
margin-top: 13rpx;
display: flex;
align-items: center;
}
.line {
width: 1rpx;
height: 24rpx;
background: #707070;
margin: 0 25rpx;
}
.p_row {
font-size: 24rpx;
color: #3F3F3F;
display: flex;
justify-content: space-between;
align-items: center;
.p_r_col {
flex: 1;
}
}
.mtop23 {
margin-top: 20rpx;
}
.mtop10 {
margin-top: 12rpx;
}
}
}
.right {
flex-shrink: 0;
}
}
}
}
样式
代码
<view class="list">
<view class="item" v-for="(item,index) in list" :key="index" :class="current===index?'active':''"
@click="choosePackage(index)">
<view class="kwh">标题</view>
<view class="methodMoney">价格</view>
</view>
</view>
data() {
return {
list: [],
current: "",
};
},
methods: {
// 选择
choosePackage(index) {
this.current = index
},
}
.list {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 20px 20px; //行间距 列间距
margin: 10rpx 30rpx 0;
.active {
background: var(--nav-bg) !important;
.kwh {
color: #FFFFFF !important;
}
.methodMoney {
color: #FFFFFF !important;
}
}
.item {
background: #F3F3F3;
border-radius: 10rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 24rpx 0;
.kwh {
font-weight: bold;
font-size: 30rpx;
color: #282828;
}
.methodMoney {
font-size: 24rpx;
color: #181818;
margin-top: 17rpx;
}
}
}
多选样式 uni+vue2
说明
跳转传参:
i.to(/pages/son/son?id=${id.value}&station_name=${info.value.station_name.join(',')}&agent_station_ids=${info.value.agent_station_ids}
)
父页面传的agent_station_ids是一个数组[1,3]
,但是子页面接收的时候会发现数据被处理成了字符串1,3
,自己再处理一下即可。这个数组是选中的站点的id
。
数据格式:
station_name :‘动漫站点,电视剧站点,电影站点’
agent_station_ids:[‘1’,‘3’]
siteList:[{id:1,name:‘动漫站点’},{id:2,name:‘,电视剧站点’},{id:3,name:‘电影站点’}]
在比对时,将 item.id 转换为字符串类型以匹配 agent_station_ids.value 数组中的字符串元素
代码
<view class="list">
<checkbox-group @change="chooseTags">
<label v-for="(item, index) in siteList" :key="item.id"
:class="{'item':true,'active':item.checked}">
<view style="display: none;">
<checkbox :value="item.id.toString()" :checked="item.checked" />
</view>
{{item.name}}
</label>
</checkbox-group>
</view>
const selectArr = ref([]) //选中的多个标签
const station_name = ref('') //已绑定的站点
const agent_station_ids = ref([])//接收选中的站点
onLoad((e) => {
if (e) {
agent_station_ids.value = e.agent_station_ids.split(',')
card_id.value = e.card_id
station_name.value = e.station_name
}
getListNoPage() //获取站点
})
// 站点选择
function chooseTags(e) {
const values = e.detail.value;
siteList.value.forEach(item => {
if (values.includes(item.id.toString())) {
item.checked = true;
} else {
item.checked = false;
}
});
selectArr.value = values.join(',');
}
// 站点列表
function getListNoPage() {
api.getListNoPage({
search: search.value, //搜索
}).then(res => {
if (res.code == 1) {
siteList.value = res.data//全部站点信息
//对比信息,若包含选中的的id的,则变为选中状态。
siteList.value.forEach(item => {
if (agent_station_ids.value.includes(String(item.id))) {
item.checked = true;
}
});
}
})
}
.list {
background: #FCFCFC;
border-radius: 20rpx 20rpx 20rpx 20rpx;
.item {
font-size: 30rpx;
color: #6C6B6B;
height: 100rpx;
display: flex;
justify-content: center;
align-items: center;
border-bottom: 1rpx solid #E4E4E4;
}
.item:last-child{
border: none;
}
.active {
background-color: #E3ECFC;
color: #0256FF;
}
}
带有搜索样式的单选
<view class="row">
<view class="rowLeft"><text class="redStar">*</text>学校</view>
<view class="rowRight">
<view class="pleaseChoose" @click="openSchool">
<text
:class="{'right':true,'grey':!schoolTxt}">{{schoolTxt?schoolTxt:'请选择学校'}}</text>
<image src="/user/static/images/downIcon.png" mode="aspectFill"></image>
</view>
</view>
</view>
<!-- 学校搜索弹框 -->
<view v-if="schoolShow">
<wh-bottom-popup :show="schoolShow" @close="closeSchoolPopup" :maskClosable="false">
<view class="schoolBox">
<view class="s_title">请选择学校</view>
<view class="searchBox">
<view class="searchLeft">
<wh-icon name="search" size="40"></wh-icon>
<input type="text" placeholder="请输入搜索内容" v-model="search" />
</view>
<view class="searchBtn" @click="searchSchool">
搜索
</view>
</view>
<scroll-view scroll-y="true" class="s_list" @scrolltolower="scrollBottom">
<view :class="{'s_item':true,'boldSize':item.id == school_id}"
v-for="(item,index) in schoolList" :key="index" @click="toChooseSchool(item)">
{{item.names}}
<view class="s_yes" v-if="item.id == school_id">
<wh-icon name="check" color="#F364B3" size="34"></wh-icon>
</view>
</view>
</scroll-view>
<view class="s_btn" @click="schoolShow = false">确定</view>
</view>
</wh-bottom-popup>
</view>
const schoolTxt = ref('') //学校
const schoolShow = ref(false)
const search = ref('') //搜索内容
const schoolList = ref([]) //学校列表
const school_id = ref('') //学校id
// 关闭学校弹框
function closeSchoolPopup() {
schoolShow.value = false
}
function searchSchool() {
getSchoolLists()
}
function toChooseSchool(item) {
console.log(item);
schoolTxt.value = item.names
school_id.value = item.id
let userInfo = uni.getStorageSync('userInfo') || {}; // 如果不存在,则初始化为空对象
userInfo.schoolTxt = schoolTxt.value
userInfo.school_id = school_id.value
uni.setStorageSync('userInfo', userInfo);
}
// 打开学校弹框
function openSchool() {
if (!city_id.value) {
return i.msg("请先选择省市区")
}
if (user.state.auth_status === 'yes' || user.state.auth_status === 'audit') {
schoolShow.value = false
} else {
schoolShow.value = true
}
}
function scrollBottom() {
console.log(11);
}
// 学校弹出层
.schoolBox {
min-height: 60vh;
.s_title {
text-align: center;
font-size: 34rpx;
font-weight: bold;
color: #3D3D3D;
line-height: 100rpx;
}
.searchBox {
display: flex;
align-items: center;
justify-content: space-between;
height: 80rpx;
background: #f8f8f8;
border-radius: 50rpx;
padding: 0 20rpx;
margin: 0 30rpx;
.searchLeft {
display: flex;
align-items: center;
width: 100%;
input {
text-align: left;
font-size: 26rpx;
border-radius: 0;
margin-left: 10rpx;
width: 70%;
}
}
.searchBtn {
font-size: 28rpx;
color: #757575;
flex-shrink: 0;
}
}
.s_list {
height: 40vh;
box-sizing: border-box;
padding: 0 30rpx;
.s_item {
font-size: 30rpx;
color: #3D3D3D;
line-height: 88rpx;
border-bottom: 1rpx solid #f8f8f8;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 10rpx;
.s_yes {}
}
.boldSize {
font-weight: bold;
}
.s_item:last-child {
border: none;
}
}
.s_btn {
height: 90rpx;
margin: 20rpx 60rpx 0;
display: flex;
justify-content: center;
align-items: center;
font-size: 30rpx;
font-weight: bold;
background-color: #F364B3;
color: #ffffff;
border-radius: 60rpx;
}
}
多选样式 -圆圈uni+vue3
<checkbox-group @change="onChoose">
<label class="item" v-for="(item,index) in list" :key="index">
<view class="row">
<view class="rowItem">
<text class="txt">设备名称:</text>
<text class="nums">{{item.name?item.name:'无'}}</text>
</view>
<view class="rowItem">
<text class="txt">设备编号:</text>
<text class="nums">{{item.number?item.number:'无'}}</text>
</view>
<view class="rowItem">
<text class="txt">设备类型:</text>
<text class="nums">{{item.type_name?item.type_name:'无'}}</text>
</view>
</view>
<view class="circle">
<wh-icon name="checkround" color="#D4D4D4" size="50" v-if="!item.checked"></wh-icon>
<wh-icon name="checkbox-fill" color="#007aff" size="50" v-if="item.checked"></wh-icon>
</view>
<view class="checkboxHidden">
<checkbox :value="item.id.toString()" :checked="item.checked" activeBackgroundColor="#007aff"
iconColor="#ffffff" />
</view>
</label>
</checkbox-group>
const devices_ids = ref('') //集合
function getAgentDevicesLists() {
loadState.value = 2
api.getAgentDevicesLists({
page: page.value,
size: size.value,
}).then(res => {
if (res.code == 1) {
list.value = [...list.value, ...res.data]
if (list.value.length < page.value * size.value) {
loadState.value = 3
} else {
loadState.value = 1
}
list.value.forEach(item => {
item.checked = false
})
}
})
}
function onChoose(e) {
const values = e.detail.value;
list.value.forEach(item => {
if (values.includes(item.id.toString())) {
item.checked = true;
} else {
item.checked = false;
}
});
devices_ids.value = values.join(',');
}
function confirmAdd() {
if(!devices_ids.value){
return i.msg("请选择设备");
}
api.bandDevices({
station_id: station_id.value,
devices_ids: devices_ids.value,
}).then(res => {
if (res.code == 1) {
i.success(res.msg)
setTimeout(()=> {
i.back()
}, 1000);
}
})
}
.checkboxHidden {
display: none;
}
超简答的多选uni+vue3
tagList:[{dict_label: “干净整洁”, dict_value: “1”}, {dict_label: “占位严重”, dict_value: “2”},…]
<view class="evaluates">
<block v-for="(item, index) in tagList" :key="index">
<view class="item" :class="{'active': selectedTags.includes(index)}" @click="toggleTag(index)">
{{ item.dict_label }}
</view>
</block>
</view>
const tagList = ref([]) //字典数据
const selectedTags = ref([]) // 用于存储选中的标签索引
const selectedTagLabels = ref([]); //用于存储选中的标签内容
onLoad(() => {
getTags() //字典数据
})
// 获取站点评论字典数据
const getTags = () => {
api.getTags().then(res => {
if (res.code == 200) {
console.log(res);
tagList.value = res.data
}
})
}
// 多选: 修改toggleTag函数来更新选中标签名称数组
const toggleTag = (index) => {
// 查找当前标签是否已经被选中
const isSelected = selectedTags.value.includes(index);
if (isSelected) {
// 如果已选中,则从selectedTags和selectedTagLabels中移除
selectedTags.value = selectedTags.value.filter(item => item !== index);
selectedTagLabels.value = selectedTagLabels.value.filter(item => item !== tagList.value[index].dict_label);
} else {
// 如果未选中,则添加到selectedTags和selectedTagLabels中
selectedTags.value.push(index);
selectedTagLabels.value.push(tagList.value[index].dict_label);
}
}
// 提交
const onSubmit = () => {
console.log('多选的数组索引', selectedTags.value)
console.log('多选的数组内容', selectedTagLabels.value)
}
.evaluates {
display: flex;
align-items: center;
flex-flow: wrap;
margin-top: 30rpx;
.item {
font-size: 24rpx;
color: var(--fui-color-subtitle);
border: 1rpx solid var(--fui-color-subtitle);
background-color: #ffffff;
margin-bottom: 26rpx;
margin-right: 30rpx;
padding: 6rpx 12rpx;
border-radius: 50rpx;
}
.active {
border: 1rpx solid var(--fui-color-primary) !important;
color: var(--fui-color-primary) !important;
background-color: var(--fui-color-primary_1) !important;
}
}
单选 uniapp+vue3
<view class="list">
<view class="item" v-for="(item,index) in list" :key="item.id"
:class="{ 'active': selectedId === item.id }" @click="selectedId = item.id">
<view class="name">{{item.name}}</view>
<view class="price">{{item.price}}元</view>
</view>
</view>
const list = ref([{
name: '月会员(31天)',
price: '10.88',
id: 1,
}, {
name: '季会员 (91天)',
price: '10.88',
id: 2,
}, {
name: '年会员 (365天)',
price: '108.88',
id: 3,
}])
const selectedId = ref(list.value[0]?.id || null) //初始化时默认选中第一个
.list {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
grid-gap: 30rpx 35rpx;
.item {
font-weight: bold;
padding: 54rpx 10rpx;
text-align: center;
background: #F5F5F5;
border-radius: 20rpx 20rpx 20rpx 20rpx;
border: 2rpx solid #F5F5F5;
.name {
font-size: 24rpx;
color: #000000;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.price {
font-size: 36rpx;
color: #D6822E;
margin-top: 30rpx;
}
}
/* 选中时 */
.active {
background: #FCF5EF !important;
border: 2rpx solid #D6822E;
}
}
多选 uniapp+vue2 不使用组件等
<!-- 宫格布局 -->
<view class="grid-container">
<view v-for="(item, index) in permissionList" :key="item.id" class="grid-item"
:class="{ 'selected': selectedIds.includes(item.id) }" @click="toggleSelect(item.id)">
{{ item.name }}
</view>
</view>
<!-- 选中的ID显示 -->
<view class="selected-ids">已选ID: {{ selectedIds.join(', ') }}</view>
data() {
return {
permissionList: [{
id: 1,
name: '收款提现'
},
{
id: 2,
name: '绑定设备'
},
{
id: 3,
name: '充电套餐'
},
{
id: 4,
name: '场地管理'
},
{
id: 5,
name: '设备管理'
},
{
id: 6,
name: '充值套餐'
},
{
id: 7,
name: '充电订单'
},
{
id: 8,
name: '充值订单'
},
{
id: 9,
name: '用户管理'
},
{
id: 10,
name: '虚拟余额'
},
{
id: 11,
name: '场地收益'
},
{
id: 12,
name: '分账管理'
},
],
selectedIds: [] // 存储选中的id
}
},
methods: {
// 切换选中状态
toggleSelect(id) {
const index = this.selectedIds.indexOf(id)
if (index === -1) {
this.selectedIds.push(id)
} else {
this.selectedIds.splice(index, 1)
}
}
}
.grid-container {
display: grid; // 声明一个容器
grid-template-columns:repeat(3, 1fr);//3栏 每个宽度180rpx
grid-gap: 30rpx 30rpx; //行间距 列间距
}
.grid-item {
height: 70rpx;
border-radius: 12rpx;
background: #F7F7F7;
margin: 10rpx;
font-size: 28rpx;
color: #606266;
display: flex;
justify-content: center;
align-items: center;
transition: all 0.3s;
&.selected {
background: #EFF6FE;
color: #2E87ED;
}
}
.selected-ids {
margin-top: 40rpx;
font-size: 28rpx;
color: #666;
padding: 20rpx;
}
&的作用是:正确匹配同时有.grid-item和.selected的元素
该多选的回显
上个页面的传参
onEdit(item) {
let params = {
id: item.id,
name: item.name,
phone: item.phone,
rules: item.auth[0].rules
}
uni.navigateTo({
url: `/pages/index/addEdit?params=${encodeURIComponent(JSON.stringify(params))}`
});
},
<template>
<view class="container">
<view class="formBox">
<view class="row">
<view class="left">子账户名称</view>
<view class="right">
<input type="text" placeholder="请输入子账户名称" v-model="name" />
</view>
</view>
<view class="row">
<view class="left">账号</view>
<view class="right">
<input type="text" placeholder="请输入账号" v-model="phone" />
</view>
</view>
<view class="row">
<view class="left">密码</view>
<view class="right">
<input type="text" placeholder="请输入密码" v-model="password" />
</view>
</view>
<view class="row">
<view class="left">确认密码</view>
<view class="right">
<input type="text" placeholder="请输入确认密码" v-model="consfirmPassword" />
</view>
</view>
</view>
<view class="whiteBox">
<view class="title">请选择账户权限</view>
<!-- 宫格布局 -->
<view class="grid-container">
<view v-for="(item, index) in permissionList" :key="item.id" class="grid-item"
:class="{ 'selected': selectedIds.includes(item.id) }" @click="toggleSelect(item.id)">
{{ item.name }}
</view>
</view>
</view>
<view style="height: 150rpx;"></view>
<view class="footBox">
<view class="addBtn" @click="onSave">保存</view>
</view>
</view>
</template>
<script>
import common from '../../common/common.js'
export default {
data() {
return {
permissionList: [], //权限列表
selectedIds: [], // 存储选中的id
name: '',
phone: '',
password: '',
consfirmPassword: '',
id: ''
}
},
onLoad(options) {
if (options.params) {
try {
const params = JSON.parse(decodeURIComponent(options.params));
// 初始化表单数据
this.name = params.name || '';
this.phone = params.phone || '';
this.id = params.id || ''; // 编辑时才会有id
// 处理权限ID数组
this.selectedIds = String(params.rules || '')
.split(',')
.filter(Boolean)
.map(Number)
.filter(n => !isNaN(n));
} catch (e) {
console.error('参数解析失败:', e);
}
}
},
onShow() {
this.getAuthDate()
},
methods: {
// 保存
onSave() {
if (!this.name) {
return common.msg("请输入子账号名称")
}
if (!this.phone) {
return common.msg("请输入账号")
}
if (!this.password) {
return common.msg("请输入密码")
}
if (!this.consfirmPassword) {
return common.msg("请输入确认密码")
}
if (this.password !== this.consfirmPassword) {
return common.msg("两次密码不一致");
}
let data = {
name: this.name,
phone: this.phone,
password: this.password,
rules: this.selectedIds.join(','),
// 编辑时带ID, 添加时不带
...(this.id && {
id: this.id
}),
}
// 动态选择接口地址
const apiUrl = this.id ? '/agent/user/editAccout' : '/agent/user/addAccout';
common.request('post', apiUrl, data).then(res => {
if (res.code == 1) {
common.msg(res.msg)
setTimeout(() => {
uni.navigateBack({
delta: 1
})
}, 1200);
}
})
},
// 切换选中状态
toggleSelect(id) {
const index = this.selectedIds.indexOf(id)
if (index === -1) {
this.selectedIds.push(id)
} else {
this.selectedIds.splice(index, 1)
}
},
// 获取权限数据
getAuthDate() {
common.request('post', '/agent/user/auth').then(res => {
if (res.code == 1) {
console.log(res);
this.permissionList = res.data
}
})
}
}
}
</script>
<style lang="scss">
.container {
padding-top: 30rpx;
}
.formBox {
margin: 0 30rpx 30rpx 30rpx;
background: #FFFFFF;
border-radius: 16rpx;
padding: 0 30rpx;
.row {
padding: 30rpx 0;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #F7F7F7;
.left {
font-weight: bold;
font-size: 30rpx;
color: #3D3D3D;
}
input {
text-align: right;
font-size: 28rpx;
}
}
.row:last-child {
border-bottom: 1px solid #F7F7F7;
}
}
.whiteBox {
background: #FFFFFF;
border-radius: 16rpx 16rpx 16rpx 16rpx;
margin: 0 30rpx;
padding: 0 30rpx;
.title {
line-height: 110rpx;
font-weight: bold;
font-size: 30rpx;
color: #3D3D3D;
}
.grid-container {
display: grid; // 声明一个容器
grid-template-columns: repeat(3, 1fr); //3栏 每个宽度180rpx
grid-gap: 30rpx 30rpx; //行间距 列间距
padding-bottom: 40rpx;
}
.grid-item {
height: 70rpx;
border-radius: 12rpx;
background: #F7F7F7;
margin: 10rpx;
font-size: 28rpx;
color: #606266;
display: flex;
justify-content: center;
align-items: center;
transition: all 0.1s;
&.selected {
background: #EFF6FE;
color: #2E87ED;
}
}
}
.footBox {
position: fixed;
left: 0;
bottom: 60rpx;
width: 100%;
z-index: 10;
.addBtn {
margin: 0 30rpx;
height: 86rpx;
background: linear-gradient(180deg, #61BDFF 0%, #2E87ED 100%);
border-radius: 50rpx 50rpx 50rpx 50rpx;
font-weight: bold;
font-size: 32rpx;
color: #FFFFFF;
display: flex;
justify-content: center;
align-items: center;
}
}
</style>
uniapp+vue2多选
代码
<template>
<view class="bodyBox">
<view class="list">
<view class="item" v-for="(item,index) in list" :key="item.id" @click="toggleSelection(index)"
:class="{ 'selected-bg': item.checked }">
<view class="title">
<view class="checkCss">
<image src="/static/images/uncheck.png" mode="aspectFill" v-if="!item.checked"></image>
<image src="/static/images/check.png" mode="aspectFill" v-if="item.checked"></image>
</view>
设备名称:{{item.name}}
</view>
<view class="row">设备编号:{{item.sn}}</view>
<view class="row" v-if="item.cm_type==3">设备类型:aaaa</view>
</view>
</view>
<view style="padding: 200rpx 0;" v-if="list.length==0">
<u-empty text="暂无数据" mode="order"></u-empty>
</view>
<view style="height: 130rpx;"></view>
<view class="foot">
<view class="networkBtn" @click="handleSubmit">绑定({{selectedCount}})</view>
</view>
</view>
</template>
<script>
import common from '../../common/common.js'
export default {
data() {
return {
list: [],
page: 1,
id: 0,
};
},
computed: {
// 自动计算选中数量
selectedCount() {
return this.list.filter(item => item.checked).length
},
// 计算属性自动生成选中ID列表
selectedIds() {
return this.list.reduce((arr, item) => {
if (item.checked) arr.push(item.id)
return arr
}, [])
}
},
onLoad(e) {
if (e.id) {
this.id = e.id
}
},
onReachBottom() {
this.page++
this.networkList()
},
onShow() {
this.page = 1;
this.networkList()
},
methods: {
// 列表
networkList() {
common.request("post", "/agent/index/slave_list", {
p: this.page
}).then((res) => {
if (res.code == 1) {
// 初始化checked字段
const processData = (data) => data.map(item => ({
...item,
checked: !!item.checked // 确保boolean类型
}))
if (this.page == 1) {
this.list = processData(res.data.data)
} else {
// 保留页码回退逻辑,但增加空数据判断
if (res.data.data.length === 0) {
this.page--
uni.showToast({
title: '没有更多数据了',
icon: 'none'
})
} else {
this.list = this.list.concat(processData(res.data.data))
}
}
}
})
},
toggleSelection(index) {
this.$set(this.list, index, {
...this.list[index],
checked: !this.list[index].checked
})
},
// 提交时获取选中ID
handleSubmit() {
if (this.selectedCount === 0) {
uni.showToast({
title: '请先选择设备',
icon: 'none'
})
return
}
common.request('post', '/agent/index/networking', {
master_id: this.id,
slave_ids: this.selectedIds.join(',')
}).then(res => {
if (res.code == 1) {
common.msg(res.msg)
setTimeout(() => {
uni.navigateBack({
delta: 1
});
}, 1200);
}
})
},
}
}
</script>
<style lang="scss">
.bodyBox {
padding-top: 30rpx;
}
.list {
margin: 0 30rpx 0;
.item {
border-radius: 30rpx;
background-color: #ffffff;
padding: 0 30rpx 20rpx;
margin-bottom: 20rpx;
.title {
height: 80rpx;
font-weight: bold;
border-bottom: 1px solid #F7F7F7;
margin-bottom: 20rpx;
display: flex;
align-items: center;
.checkCss {
margin-right: 20rpx;
width: 35rpx;
height: 35rpx;
image {
width: 35rpx;
height: 35rpx;
display: block;
}
}
}
.row {
margin-bottom: 10rpx;
}
}
}
.foot {
position: fixed;
width: 100%;
bottom: 0;
padding: 20rpx 30rpx;
background-color: #F7F7F7;
z-index: 5;
.networkBtn {
display: flex;
align-items: center;
height: 90rpx;
background: linear-gradient(0deg, #4094F7 0%, #5EB9FF 100%);
border-radius: 50rpx;
justify-content: center;
color: #ffffff;
}
}
</style>
uni+vue3多选
代码
<view class="evaluates">
<block v-for="(item, index) in tagList" :key="index">
<view class="item" :class="{'active': selectedTags.includes(index)}" @click="toggleTag(index)">
{{ item.names }}
</view>
</block>
</view>
onShow(() => {
getReason() //意见反馈原因
})
function getReason() {
api.getReason({
type: 2, //1投诉2意见反馈
}).then(res => {
if (res.code == 1) {
console.log(res);
tagList.value = res.data
}
})
}
const tagList = ref([]) //原因列表
const selectedTags = ref([]) // 用于存储选中的标签索引
const reasonTags = ref([]); //用于存储选中的标签内容
const toggleTag = (index) => {
const isSelected = selectedTags.value.includes(index);
if (isSelected) {
selectedTags.value = selectedTags.value.filter(item => item !== index);
reasonTags.value = reasonTags.value.filter(item => item !== tagList.value[index].names);
} else {
selectedTags.value.push(index);
reasonTags.value.push(tagList.value[index].names);
}
}
// 提交
const onSubmit = () => {
console.log('多选的数组索引', selectedTags.value)
console.log('多选的数组内容', reasonTags.value)
}
.evaluates {
display: flex;
align-items: center;
flex-flow: wrap;
margin-top: 30rpx;
.item {
font-size: 24rpx;
color: var(--fui-color-subtitle);
border: 1rpx solid var(--fui-color-subtitle);
background-color: #ffffff;
margin-bottom: 26rpx;
margin-right: 30rpx;
padding: 6rpx 12rpx;
border-radius: 50rpx;
}
.active {
border: 1rpx solid var(--fui-color-primary) !important;
color: var(--fui-color-primary) !important;
background-color: var(--fui-color-primary_1) !important;
}
}
uniapp+vue3多选圆圈
<template>
<view class="container">
<fui-sticky>
<navBar title="绑定站点" :leftArrow="true" :fixed="true" backgroundColor="#ffffff" title-color="#000000" />
<view class="searchBox">
<view class="search">
<image class="search-img" src="/static/images/searchIcon.png" mode="aspectFill"></image>
<input class="search-inp" type="text" v-model="initialQuery.search" placeholder="请输入搜索关键词" />
</view>
<view class="search-sou" @click="onSearch">搜索</view>
</view>
</fui-sticky>
<view class="list">
<view class="item" v-for="(item,index) in filteredSites" :key="index" @click="toggleSiteSelection(item.id)">
<view class="checkCss">
<image src="/static/images/uncheck.png" mode="aspectFill" v-if="!selectedSiteIds.includes(item.id)"></image>
<image src="/static/images/check.png" mode="aspectFill" v-if="selectedSiteIds.includes(item.id)"></image>
</view>
<view class="rightInfo">
<view class="oneRow">
<view class="siteName">{{item.name}}</view>
<view class="siteStatusGreen" v-if="item.status==1">正常</view>
<view class="siteStatusRed" v-if="item.status==0">停用</view>
</view>
<view class="siteNumber">站点编号:XXXXXX</view>
</view>
</view>
</view>
<!-- <fui-loadmore :state="loadState" v-if="!(list.length==0&&loadState==3)"
activeColor="var(--fui-color-primary)"></fui-loadmore>
<fui-empty marginTop="400" v-if="loadState==3&&list.length==0" src="/static/images/empty/img_order_3x.png"
width="400" title="暂无数据" color="#999" size="28"></fui-empty> -->
<view style="height: 180rpx;"></view>
<view class="footBtn" @click="handleConfirmBinding">确认绑定</view>
</view>
</template>
<script setup>
import {
ref,
reactive,
nextTick,
computed,
watch
} from 'vue'
import {
onLoad,
onShow,
onReady,
onReachBottom
} from '@dcloudio/uni-app'
import i from '@/libs/common/index.js'
import api from '@/request/api'
import {
usePaginatedList
} from '@/hooks/usePaginatedList'
import {
userStore
} from '@/store/userStore.js'
import {
commonStore
} from '@/store/commonStore.js'
const user = userStore()
const common = commonStore()
const list = ref([{
id: '001',
name: '站点A',
status: 1
},
{
id: '002',
name: '站点B',
status: 0
},
{
id: '003',
name: '站点C',
status: 1
},
]);
// 选中状态管理
const selectedSiteIds = ref([]);
const searchQuery = ref('');
// 过滤后的站点列表
const filteredSites = computed(() => {
const keyword = searchQuery.value.toLowerCase();
return list.value.filter(site =>
site.name.toLowerCase().includes(keyword) ||
site.id.toLowerCase().includes(keyword)
);
});
// 切换站点选中状态
const toggleSiteSelection = (siteId) => {
const index = selectedSiteIds.value.indexOf(siteId);
if (index === -1) {
selectedSiteIds.value.push(siteId);
} else {
selectedSiteIds.value.splice(index, 1);
}
};
// 确认绑定
function handleConfirmBinding() {
if (selectedSiteIds.value.length === 0) {
i.msg("请至少选择一个站点")
return;
}
// 这里可以添加绑定逻辑
console.log('绑定的站点:', selectedSiteIds.value);
}
// const fetchFunction = (query) => {
// return api.getCarteamList(query)
// }
const initialQuery = reactive({
car_team_id: '',
search: '' //搜索内容
})
// const {
// list,
// fetchList,
// ReachBottom,
// onPullDown,
// loadState
// } = usePaginatedList(fetchFunction, initialQuery)
// onLoad((option) => {
// if (option) {
// initialQuery.car_team_id = option.id
// }
// })
// watch(
// () => initialQuery.search,
// (newVal, oldVal) => {
// // 仅当从有值变为空时触发刷新
// if (oldVal && !newVal) {
// fetchList(true);
// }
// }
// )
// onShow(() => {
// fetchList(true)
// })
// onReachBottom(() => {
// ReachBottom()
// })
// 确定搜索
function onSearch() {
fetchList(true)
}
</script>
<style lang="scss">
page {
background-color: #f8f8f8;
}
.searchBox {
background-color: #ffffff;
padding: 24rpx 30rpx;
display: flex;
justify-content: space-between;
align-items: center;
.search {
overflow: hidden;
width: 534rpx;
height: 72rpx;
background: #F6F7F8;
border-radius: 60rpx;
display: flex;
align-items: center;
padding: 0 28rpx;
font-size: 28rpx;
.search-img {
width: 25rpx;
height: 25rpx;
flex-shrink: 0;
}
.search-inp {
width: 100%;
margin-left: 19rpx;
}
}
.search-sou {
font-size: 32rpx;
color: #333333;
}
}
.list {
margin: 30rpx 30rpx 0;
.item {
background: #FFFFFF;
border-radius: 16rpx 16rpx 16rpx 16rpx;
padding: 40rpx 24rpx;
margin-bottom: 30rpx;
display: flex;
align-items: center;
.checkCss {
flex-shrink: 0;
image {
width: 36rpx;
height: 36rpx;
margin-right: 28rpx;
}
}
.rightInfo {
width: 100%;
.oneRow {
width: 100%;
display: flex;
justify-content: space-between;
.siteName {
font-weight: bold;
font-size: 30rpx;
color: #3D3D3D;
}
.siteStatusGreen {
width: 80rpx;
height: 42rpx;
background: #E5F5DC;
border-radius: 8rpx 8rpx 8rpx 8rpx;
font-weight: bold;
font-size: 24rpx;
color: #7FCF50;
display: flex;
justify-content: center;
align-items: center;
flex-shrink: 0;
}
.siteStatusRed {
width: 80rpx;
height: 42rpx;
background: #FFE2E2;
border-radius: 8rpx 8rpx 8rpx 8rpx;
font-weight: bold;
font-size: 24rpx;
color: #FF4D4F;
display: flex;
justify-content: center;
align-items: center;
flex-shrink: 0;
}
}
.siteNumber {
margin-top: 12rpx;
font-size: 24rpx;
color: #666666;
}
}
}
}
.footBtn {
width: 690rpx;
height: 88rpx;
background: #0256FF;
border-radius: 100rpx 100rpx 100rpx 100rpx;
font-size: 32rpx;
color: #FFFFFF;
display: flex;
justify-content: center;
align-items: center;
position: fixed;
left: 30rpx;
bottom: 90rpx;
}
</style>