uniapp下单选框的实现方法详解
作者:lsjweiyi 发布时间:2024-10-17 16:42:08
uniapp官方虽然提供了uni-data-checkbox
,含括了单选和多选框功能。但是它功能实在不能满足需求:
单选框不支持再次点击取消
无法与父组件的数据源进行联动,无法实现如多规格选择的那种联动
源码每次点击都是对数据源进行拷贝,然后再进行json解析等操作,看着就很不靠谱,数据量大必然有性能问题。
其实我放弃uni-data-checkbox
,选择自己实现也是因为商品规格展示是比较复杂的,不自己实现的话无法达到目的:
看图中,三组规格选项是要相互联动的,选择了其中一个后,就得判断其余的是否可选。然后我认为也可以将已选中的取消。所以得自己实现,好根据业务定制。
代码如下:
<template>
<!-- uniapp内置的单选组件,见https://uniapp.dcloud.io/component/radio.html -->
<radio-group class="checklist-group" @change="change">
<label
class="checklist-box is--tag"
v-for="item in radioData.option"
:class="[radioData.selected === item.id ? 'is-checked' : '', item.disable ? 'is-disable' : '']">
<radio
class="hidden"
:disabled="item.disable"
:value="String(item.id)"
:checked="radioData.selected === item.id" />
<view class="checklist-content">
<text class="checklist-text">{{ item.text }}</text>
</view>
</label>
</radio-group>
</template>
<script setup lang="ts">
const props = defineProps({
// 该id设计的目的是为了应对数组,记录数组的下标,这样父类就不需要遍历查找了。当然也可以根据业务用于其他方面,不需要就不用即可。
id: {
type: [Number, String],
},
/*数据源,它的数据结构应该:{selected:,option:[{id:,disable:,text:,}...]}
其中selected 的值应取自option的id。
*/
radioData: {
type: Object,
required: true,
},
});
// 点击后回调父类的change方法
const emit = defineEmits(["change"]);
// 点击后触发
function change(e: any) {
// 参数:tag的id;props.id
emit("change", e.detail.value, props.id);
}
</script>
<style lang="scss">
$checked-color: #2979ff;
$border-color: #dcdfe6;
$disable: 0.4;
@mixin flex {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
}
.checklist-group {
@include flex;
flex-direction: row;
flex-wrap: wrap;
.checklist-box {
@include flex;
flex-direction: row;
align-items: center;
position: relative;
margin: 5px 0;
margin-right: 25px;
.hidden {
position: absolute;
opacity: 0;
}
// 文字样式
.checklist-content {
@include flex;
flex: 1;
flex-direction: row;
align-items: center;
justify-content: space-between;
.checklist-text {
font-size: 14px;
color: #666;
margin-left: 5px;
line-height: 14px;
}
}
// 单选样式
.radio__inner {
@include flex;
/* #ifndef APP-NVUE */
flex-shrink: 0;
box-sizing: border-box;
/* #endif */
justify-content: center;
align-items: center;
position: relative;
width: 16px;
height: 16px;
border: 1px solid $border-color;
border-radius: 16px;
background-color: #fff;
z-index: 1;
.radio__inner-icon {
width: 8px;
height: 8px;
border-radius: 10px;
opacity: 0;
}
}
// 标签样式
&.is--tag {
margin-right: 10px;
padding: 5px 10px;
border: 1px $border-color solid;
border-radius: 3px;
background-color: #f5f5f5;
.checklist-text {
margin: 0;
color: #666;
}
// 禁用
&.is-disable {
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
opacity: $disable;
}
&.is-checked {
background-color: $checked-color;
border-color: $checked-color;
.checklist-text {
color: #fff;
}
}
}
}
}
</style>
其实代码本身内容很少,是样式的代码多,我样式是直接照抄uni-data-checkbox
的。
传入的数据结构应该是:
interface radio{
selected: number;
option: {
id: number;
text: string;
disable: boolean;
}[];
}
selected
和id
可以是别的类型,但selected
是取值于id
这里得注意,数据源必须是响应式的,考虑这里肯定是个对象,那么就是要用reactive
去包围数据,使其具有响应性,否则页面不会更新,例如下面:
const radioData= reactive(radio);
PS1:由于vue3规范建议:子组件不修改父组件的数据源,否则会导致数据的变化难以理解。所以change方法中没有做任何修改数据的动作。比如将selected直接修改也是完全可以的,但是我这里还是交由父组件去决定如何修改。
PS2:咋一看change方法仅传递了当前选择的选项,并没有告知之前的选项是什么,如果要对比前后的时候不是没有办法?其实selected就是存储的之前的选项,在修改它之前用它作比较即可。
PS3:由于radio本身是不支持选中之后再取消的,我们这里采用将selected
赋值为一个不存在的id,这样就会取消选择了。但是会报错:
uni-shared.es.js:470 Uncaught TypeError: Cannot destructure property 'id' of 'el' as it is null.
at normalizeTarget (uni-shared.es.js:470:13)
at createNativeEvent (uni-h5.es.js:1260:13)
at $nne (uni-h5.es.js:1234:15)
at HTMLElement.invoker (vue.runtime.esm.js:9397:19)
但是不影响功能哈。
PS4:目前仅在H5下测试功能时正常的。
来源:https://blog.csdn.net/lsjweiyi/article/details/124080763


猜你喜欢
- 前言作为 Android 开发者,想必多多少少要接触启动速度优化相关的事情,当用户越来越多,产品的功能也随着迭代越来越多,App 逐渐变得臃
- 前言SQLite是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。它是一个零配置的数据库,这意味着与其
- 目录概述事件监听的结构Publisher,Event和Listener的关系事件发布者监听者总结概述ApplicationEvent以及Li
- 部分网友会发现Activity在切换到后台或布局从横屏LANDSCAPE切换到PORTRAIT,会重新切换Activity会触发一次onCr
- 一、实现原理 Mapper接口开发方法只需要程序员编写M
- 具体代码如下所示:<?xml version="1.0"?><LinearLayout android
- 一、idea打包项目第一步点击右边maven第二步点击compile,编译代码,编译成功后(双击运行)第三步点击package,打包代码二、
- Guava Cache:⾕歌开源缓存框架Guava Cache是在内存中缓存数据,相比较于数据库或redis存储,访问内存中的数据会更加高效
- 1、找准入口,使用ClassPathXmlApplicationContext的构造方法加载配置文件,用于加载classPath下的配置文件
- 前言:JSON 是轻量级的数据交换格式,很常用,尤其是在使用 Ajax 时,在后台将数据封装为 JSON 字符串更是常见。之前在做项目的时候
- JavaWeb 使用DBUtils实现增删改查1、创建C3p0Utils类创建cn.itcast.jdbc.utils包代码如下:packa
- 本文实例讲述了C#中ExecuteNonQuery()返回值注意点。对于C#数据库程序设计有一定的借鉴价值。分享给大家供大家参考之用。具体分
- #简易版1、客户发送请求经过 DisPatcherServlet 核心过滤器2、DisPatcherServlet 核心控制器在去找一个或多
- 使用工具:IDEA2022Tomcat9.0.41.下载Tomcat:官网:https://tomcat.apache.org/找到需要的版
- 目录背景统一接口返回定义API返回码枚举类定义正常响应的API统一返回体定义异常响应的API统一返回体编写包装返回结果的自定义注解定义返回结
- foreach遍历是C#常见的功能,而本文通过实例形式展现了C#使用yield关键字让自定义集合实现foreach遍历的方法。具体步骤如下:
- Android短信高效备份这篇文章,承接上一篇。使用高效的方式备份短信——xml序列化器。存储短信,要以对象的方式存储。首先创建javabe
- Mybatis防止sql注入原理SQL 注入是一种代码注入技术,用于攻击数据驱动的应用,恶意的SQL 语句 * 入到执行的实体字段中(例如,为
- 为什么要在控制台输出 SQL 呢?当然是为了开发调试的时候方便了。如果一个 数据库相关的操作出现了问题,我们可以根据输出的SQL语句快速排查
- Java并发包的locks包里的锁基本上已经介绍得差不多了,ReentrantLock重入锁是个关键,在清楚的了解了同步器AQS的运行机制后