uniapp下单选框的实现方法详解

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;
    }[];
}

selectedid可以是别的类型,但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下测试功能时正常的。

总结

到此这篇关于uniapp下单选框实现的文章就介绍到这了,更多相关uniapp下单选框实现内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • uni-app调取接口的3种方式以及封装uni.request()详解

    目录 一.uni-app中调取接口的三种方式 1.uni.request({}) 2.uni.request({}).then() 3.async/await 二.封装uni.request(); 1.创建一个对象,将该对象挂在Vue的原型下 2.进入main.js文件 3.在页面中调用 uni-app 封装接口request请求 第一步.根目录下新建 config.js 文件 第二步.根目录下新建 utils/http.js 文件 第三步. 创建model 层 根目录下新建 models/in

  • uni-popup手写菜鸟上门取件时间选择器

    目录 引言 兼容 菜鸟上门时间选择器 需求分析: 代码实现: 1.popup弹窗 2.日期+时间选择器 核心逻辑: 1.生成左侧日期列表 2.判断时间有没有过期 3.通过计算属性获取有效时间(即右侧列表展示即将过期的和未过期的时间) 4.通过计算属性获取有效日期 5.日期或时间选中函数 源码及使用 使用: 源码: TODO: 引言 近期做的项目有个需求是做一个类似菜鸟的取件时间选择器,去找了很久没找到合适的,没办法只能自己收撸,经过好几个小版本修改之后也算是定型了,这里总结一篇文档备忘,把源码贴

  • uni-app配置APP自定义顶部标题栏设置方法与注意事项

    目录 pages.json文件 页面部分或首页部分 注意: 附:uni-app如何动态设置页面的标题 1. 新建页面 2. js动态修改标题 总结 当设置 "navigationStyle":"custom" 取消原生导航栏后,由于窗体为沉浸式,占据了状态栏位置.此时可以使用一个高度为 var(--status-bar-height) 的 view 放在页面顶部,避免页面内容出现在状态栏 pages.json文件 代码块 //页面配置 "path"

  • uniapp组件uni-popup弹出层的使用

    目录 一.基本用法 二.自定义弹出层(dialog + message) 示例 三.提交信息 (input + 延迟关闭) 四.底部分享示例 官方示例:uni-popup 弹出层 - DCloud 插件市场 弹出层组件用于弹出一个覆盖到页面上的内容,使用场景如:底部弹出分享弹窗.页面插屏广告等 一.基本用法 <template> <view> <button type="primary" @click="toggle('top')"&g

  • uniapp引用echarts的详细步骤(附柱状图实例)

    相信很多小伙伴对于echarts这个东西应该不会陌生,我在网上看到很多文章,那么他到底是怎么用的呢,却是五花八门,我现在就来总结一下我的方法. 如果使用npm全局安装,太麻烦,这里推荐使用官网(ECharts 在线构建)定制下载,这样会方便我们使用. 选择柱状图,折线图,饼图:这三样是平常较常用到的: 坐标系选择直角坐标系: 组件可以全选,也可以选择自己所需要的,在这里个人建议除了工具栏不选,其他都选上:下载后的文件为echarts.min.js,建议把他放在static内. 好了,来到下一步,

  • uniapp下单选框的实现方法详解

    uniapp官方虽然提供了uni-data-checkbox,含括了单选和多选框功能.但是它功能实在不能满足需求: 单选框不支持再次点击取消 无法与父组件的数据源进行联动,无法实现如多规格选择的那种联动 源码每次点击都是对数据源进行拷贝,然后再进行json解析等操作,看着就很不靠谱,数据量大必然有性能问题. 其实我放弃uni-data-checkbox,选择自己实现也是因为商品规格展示是比较复杂的,不自己实现的话无法达到目的: 看图中,三组规格选项是要相互联动的,选择了其中一个后,就得判断其余的

  • 微信小程序下拉框组件使用方法详解

    本文实例为大家分享了微信小程序下拉框组件的使用方法,供大家参考,具体内容如下 适用场景 1.省市三级联动 2.出生日期选择 3.性别选择 4.一般性的下拉选择等 一.省市三级联动使用 注意mode = region,以及value = "一维数组" //.wxml <picker mode="region" bindchange="bindViewEvent" data-model="component" data-me

  • inux下gettimeofday函数windows替换方法(详解)

    实例如下: #include <time.h> #ifdef WIN32 # include <windows.h> #else # include <sys/time.h> #endif #ifdef WIN32 int gettimeofday(struct timeval *tp, void *tzp) { time_t clock; struct tm tm; SYSTEMTIME wtm; GetLocalTime(&wtm); tm.tm_year

  • Linux环境下Oracle安装参数设置方法详解

    前面讲了虚拟机的设置和OracleLinux的安装,接下来我们来说下Oracle安装前的准备工作. 1.系统信息查看 系统信息查看 首先服务器ip:192.168.8.120 服务器系统:Oracle Linux Server release 6.5 服务器主机名:oracle-learn 查看磁盘空间情况: [root@oracle-learn ~]# df -h Filesystem Size Used Avail Use% Mounted on /dev/sda1 32G 4.8G 26G

  • 在linux下升级软件包版本等方法详解

    Linux环境下,要想查看某个软件(package)是否安装. rpm包方式安装的,使用 rpm -qa | grep "软件或者包的名字". yum方式安装的, yum list installed | grep "软件或者包的名字". 升级软件包版本. 我们经常会遇到依赖其他版本包的情况(一般是更新的版本),这时候我们需要升级包. 1.卸载后安装新的包. 首先要根据文首提到的查看软件包是否安装的方式查看你是否安装了这个软件,若没有安装,找到路径后使用wget命令

  • 对angularjs框架下controller间的传值方法详解

    AngularJS中的controller是个函数,用来向视图的作用域($scope)添加额外的功能,我们用它来给作用域对象设置初始状态,并添加自定义行为. 当我们在创建新的控制器时,angularJS会帮我们生成并传递一个新的$scope对象给这个controller,在angularJS应用的中的任何一个部分,都有父级作用域的存在,顶级就是ng-app所在的层级,它的父级作用域就是$rootScope. 每个$scope的$root指向$rootScope, $cope.$parent指向父

  • IDEA下使用MyBatisCodeHelper插件的方法详解

    一:IDEA下使用MyBatisCodeHelper插件.(IDEA的版本 2018 2.5亲测可用) 1.1  IDEA安装MyBatisCodeHelper插件. MyBatisCodeHelper插件现在要付费了,有条件可以买激活码激活的,支持正版,这里演示安装硬盘下载的插件的方式来介绍安装. 下载链接: 链接: https://pan.baidu.com/s/1I-XlrPPVAuzsu9_XY0eEUQ 提取码: bqvn ,内含多个版本的.下载解压查看. Mybatis-Plugin

  • Vue设置select下拉框的默认选项详解(select空白bug解决)

    最近在用vue设置表单数据时发现了一个小问题:用vue动态渲染select下拉框时,select下拉框会出现空白的bug. <template> <div> <select name="art-cate" v-model="select"> <option disabled selected style="display: block;">请选择您的科目</option> <opt

  • select下拉框插件jquery.editable-select详解

    项目中有个需求,下拉框既可以下拉选择,也可以手动填写 html代码 <span>数据来源</span> <select class="source"> <option value="0">人工导入</option> <option value="1">数据服务平台</option> </select> js代码 $('#noMean').editabl

  • Android列表选择框Spinner使用方法详解

    安卓提供的列表选择框(Spinner)相当于web端用户注册时的选择下拉框,比如注册候选择省份城市等.如下图便是一个列表选择框 下拉列表的列表选择项能够通过xml文件的android:entries属性指定,或是在java代码中导入,属性android:prompt是列表项的标题. 一 列表项数据 实际运用当中,很多下拉列表项的数据实际是可知的,可以放在xml资源文件中.这时,开发者可以通过xml属性进行指定数据. 除了资源文件之外,开发者还能够使用适配器适配数据源.(适配器:如果您的电脑不能接

随机推荐