封装一个小程序选择器(可多选、单选、搜索)

组件

<template><view class="popup" v-show="show"><view class="bg" @tap="cancelMultiple"></view><view class="selectMultiple"><view class="multipleBody"><view class="title"><view class="close" @tap="cancelMultiple">取消</view><view class="name"><!-- cancelButton="none" 不展示取消按钮--><uni-search-bar@input="updateList"@confirm="onSearchConfirm"cancelButton="none"></uni-search-bar></view><view class="confirm" @tap="confirmMultiple">确认</view></view><view class="list"><view class="mask mask-top"></view><view class="mask mask-bottom"></view><scroll-view class="diet-list" scroll-y="true"><view v-for="(item, index) in list" :class="['item', item.selected ? 'checked' : '']" @tap="onChange(index, item)"><span style="font-size: 16px;">{{item.label}}</span><view class="icon" v-show="item.selected"><icon type="success_no_circle" size="16" color="#2D8DFF"/></view></view></scroll-view></view></view></view></view>
</template><script>
export default {name:"my-curry-multi-select",data() {return {// 选中值value: [],// 选中列表selected: [],// 列表数据list: [],originList: [],};},props: {// 是否显示show: {type: Boolean,default: false},// 标题title: {type: String,default: ''},//数据列表columns: {type: Array,default: []},// 默认选中defaultIndex: {type: Array,default: [],},isMultiSelect: {type: Boolean,default: true},},watch: {// 监听是否显示show(val) {if(val) {this.openMultiple();}}},methods: {sortListWithSelectedFirst(list) {return list.slice().sort((a, b) => {const aSelected = a.selected ? 1 : 0;const bSelected = b.selected ? 1 : 0;return bSelected - aSelected;});},updateList(str) {this.list.map(e => {this.originList.map(item => {if (e.selected && item.value === e.value) {item.selected = true}})})if (str === null || str === undefined || str === '') {this.list = JSON.parse(JSON.stringify(this.originList))} else {const filtered = this.originList.filter(e => e.label.indexOf(str) > -1 || e.selected);this.list = this.sortListWithSelectedFirst(filtered);}},// 新增:处理搜索确认事件onSearchConfirm(e) {const searchValue = e.value || e;// 先更新列表this.updateList(searchValue);// 如果有搜索内容且搜索结果不为空,自动选择第一个未选中的项目if (searchValue && this.list.length > 0) {// 找到第一个未选中的项目const firstUnselectedIndex = this.list.findIndex(item => !item.selected);if (firstUnselectedIndex !== -1) {// 自动选择第一个未选中的项目this.onChange(firstUnselectedIndex, this.list[firstUnselectedIndex]);}}},// 列点击事件onChange(index, item) {// 单选if (!this.isMultiSelect) {this.value = [];this.selected = [];this.value.push(item.value.toString());this.selected.push({label: item.label,value: item.value,});return this.$emit("confirm", {selected: this.selected, value: this.value});}// 是否已选中if(this.value.indexOf(item.value.toString()) >= 0) {this.list[index].selected = false;} else {this.list[index].selected = true;}// 筛选已勾选数据this.value = [];this.selected = [];this.list.forEach((col_item, col_index) => {if(col_item.selected) {this.value.push(col_item.value.toString());this.selected.push({label: col_item.label,value: col_item.value,});}});this.list = this.sortListWithSelectedFirst(this.list);this.$emit("change", {selected: this.selected, value: this.value});},// 弹出框开启触发事件openMultiple() {// 初始化列表数据,默认勾选数据this.value = this.defaultIndex;this.columns.forEach((item, index) => {this.$set(item, "selected", false);if(this.value.indexOf(item.value.toString()) >= 0) {item.selected = true;}});this.originList = Object.assign([], this.columns);this.list = this.sortListWithSelectedFirst(JSON.parse(JSON.stringify(this.originList)));},// 确认confirmMultiple() {this.$emit("confirm", {selected: this.selected, value: this.value});},// 关闭/取消cancelMultiple() {this.$emit("cancel");},}
}
</script><style scoped lang="scss">
.popup {width: 100%;height: 100vh;position: fixed;z-index: 99999;left: 0;top: 0;.bg {width: 100%;height: 100%;background-color: rgba(black, .5);}
}
.selectMultiple {transition: none !important;will-change: transform;width: 100%;position: absolute;left: 0;top: 0;height: 50vh;background-color: white;border-radius: 0 0 20rpx 20rpx;box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);overflow: hidden;.multipleBody {width: 100%;height: 100%;padding: 30rpx;box-sizing: border-box;display: flex;flex-direction: column;.title {flex-shrink: 0;font-size: 28rpx;display: flex;flex-direction: row;align-items: center; /* 添加这一行 */.close {width: 80rpx;text-align: left;opacity: .5;}.name {width: 530rpx;text-align: center;overflow: hidden;display: -webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1;}.confirm {width: 80rpx;text-align: right;color: #2D8DFF;}}.list {flex: 1;overflow: hidden;width: 100%;padding-top: 30rpx;position: relative;.mask {width: 100%;height: 60rpx; // 减小渐变区域position: absolute;left: 0;z-index: 2;pointer-events: none;&.mask-top {top: 30rpx;background-image: linear-gradient(to bottom, #fff, rgba(#fff, 0));}&.mask-bottom {bottom: 0;background-image: linear-gradient(to bottom, rgba(#fff, 0), #fff);}}.diet-list {height: 100%;max-height: none;}.item {display: flex;justify-content: space-between;align-items: center;padding: 20rpx 0;border-bottom: 1px solid rgba(#000, 0.05);span {flex: 1;font-size: 30rpx;text-align: center;}.icon {width: 32rpx;height: 32rpx;}&.checked {color: #2D8DFF;}&:last-child {border-bottom: none;margin-bottom: 60rpx;}&:first-child {margin-top: 60rpx;}}}}
}
</style>

使用

<template><view class="container"><view><uni-forms ref="taskForm" :model="taskForm" labelWidth="80px"><!-- 任务类型单选 --><uni-forms-item label="任务类型" name="type"><view class="item"><view :class="['select', taskForm.type ? 'selected' : '']"@tap="openTypeSelectionBox(taskForm.type)">{{ taskForm.type ? getTaskTypeName(taskForm.type) : '请选择任务类型' }}</view><!-- 如果有内容显示关闭图标 --><uni-icons v-if="taskForm.type !== ''" type="clear" size="24" color="#c0c4cc" class="close-btn"@tap="clearType"></uni-icons><!-- 如果没有内容显示下拉图标 --><uni-icons v-else type="pulldown" size="24" color="#c0c4cc" class="close-btn"@tap="openTypeSelectionBox(taskForm.type)"></uni-icons><my-curry-multi-select title="请选择" :show="taskTypeShow" :columns="taskTypeList":defaultIndex="defaultTaskTypeIndex":isMultiSelect="false"@confirm="confirmType($event)"@cancel="taskTypeShow = false"></my-curry-multi-select></view></uni-forms-item><!-- 负责人多选 --><uni-forms-item label="负责人" name="personInChargeIds"><view class="item"><view :class="['select', (Array.isArray(taskForm.personInChargeIds) && taskForm.personInChargeIds.length > 0) ? 'selected' : '']"@tap="openPersonInChargeIdsMultiSelectionBox(taskForm.personInChargeIds)">{{ (Array.isArray(taskForm.personInChargeIds) && taskForm.personInChargeIds.length > 0)? getUserNamesByIds(taskForm.personInChargeIds): '请选择负责人' }}</view><uni-icons v-if="Array.isArray(taskForm.personInChargeIds) && taskForm.personInChargeIds.length > 0"type="clear" size="24" color="#c0c4cc" class="close-btn"@tap="clearPersonInChargeIds"></uni-icons><uni-icons v-else type="pulldown" size="24" color="#c0c4cc" class="close-btn"@tap="openPersonInChargeIdsMultiSelectionBox(taskForm.personInChargeIds)"></uni-icons><my-curry-multi-select title="请选择" :show="taskTaskPersonInChargesShow":columns="userList":defaultIndex="defaultTaskPersonInChargesIndex":isMultiSelect="true"@confirm="confirmPersonInChargeIds($event)"@cancel="taskTaskPersonInChargesShow = false"></my-curry-multi-select></view></uni-forms-item></uni-forms><button type="primary" @click="submit">提交</button></view></view>
</template><script>
import myCurryMultiSelect from "@/components/curry-multi-select/my-curry-multi-select.vue";export default {components: {myCurryMultiSelect},data() {return {// 当前正选择哪个任务类型元素defaultTaskTypeIndex: [],// 任务类型列表,单选taskTypeList: [{"label": "指派任务", "value": 1},{"label": "设计任务", "value": 2},{"label": "代办", "value": 2}],// 是否展示任务类型下拉选项taskTypeShow: false,// 当前正选择哪些任务负责人元素defaultTaskPersonInChargesIndex: [],// 是否展示任务负责人下拉选项taskTaskPersonInChargesShow: false,// 用户列表,多选userList: [{ value: 1, label: '张三' },{ value: 2, label: '李四' },{ value: 3, label: '王五' },],// 表单数据taskForm: {taskTitle: '',insertUser: '',type: 2,personInChargeIds: [1,2],personInChargeId: null,taskContent: '',requiredCompletionTime: '',actualCompletionTime: '',weight: '',weightScore: '',timeoutStatus: '0',participants: [],taskPictureUrl: [],taskFileUrl: [],useSchedule: '1',standardWorkingHours: '',},// 表单验证规则rules: {type: {rules: [{required: true, errorMessage: '任务类型不能为空'}]},personInChargeIds: {rules: [{required: true,errorMessage: '负责人不能为空',validateFunction: (rule, value) => {return Array.isArray(value) && value.length > 0;}}]},},}},onLoad() {},created() {},onReady() {this.$refs.taskForm.setRules(this.rules)},methods: {// =====单选====// 打开任务类型选择框openTypeSelectionBox(val) {console.log('执行了openTypeSelectionBox,展开选择框时val值是:', val)this.defaultTaskTypeIndex = val !== '' ? [String(val)] : [];console.log('this.defaultTaskTypeIndex',this.defaultTaskTypeIndex)this.taskTypeShow = true;},// 清空类型选择框clearType() {this.defaultTaskTypeIndex = [];this.taskForm.type = '';},// 获取任务类型名称,把值转换为名称显示出来getTaskTypeName(value) {const option = this.taskTypeList.find(item => String(item.value) === String(value));return option ? option.label : '请选择任务类型';},// 确认选择任务类型confirmType(e) {// e是一个数组this.taskForm.type = e.value[0];this.taskTypeShow = false;},// =====多选====// 打开负责人多选框openPersonInChargeIdsMultiSelectionBox(val) {console.log('执行了openPersonInChargeIdsMultiSelectionBox,展开选择框时val值是:', val)this.defaultTaskPersonInChargesIndex = Array.isArray(val) ? val.map(item => String(item)) : [];console.log('this.defaultTaskPersonInChargesIndex', this.defaultTaskPersonInChargesIndex)this.taskTaskPersonInChargesShow = true;},// 清空负责人选择框clearPersonInChargeIds() {this.defaultTaskPersonInChargesIndex = [];this.taskForm.personInChargeIds = null; // 继续保持你的设定},// 获取任务负责人名称,把值转换为名称显示出来getUserNamesByIds(values) {if (!Array.isArray(values) || values.length === 0) return '请选择负责人';const labels = values.map(value => {const option = this.userList.find(item => String(item.value) === String(value));return option ? option.label : value;});return labels.join(',');},// 确认选择任务负责人confirmPersonInChargeIds(e) {// e是一个数组this.taskForm.personInChargeIds = e.value;this.taskTaskPersonInChargesShow = false;},// 提交表单submit() {console.log('提交时表单数据是:', this.taskForm)// 就是上面这个写法有一个问题,就是提交的时候,选择框的绑定的都是字符串。就是是数值,也是转为字符串的。但是前段字符串,后端用Long也能接收。所以问题不大。this.$refs.taskForm.validate().then(res => {this.$modal.msgSuccess("修改成功")})},}
}
</script><style lang="scss">
.item {width: 100%;padding: 0;position: relative;display: flex;align-items: center;height: 35px;.select {flex-grow: 1;border: 1px solid #dadbde;padding: 4px 9px;border-radius: 4px;font-size: 12px;box-sizing: border-box;color: #6a6a6a;line-height: 25px;height: 100%;overflow: hidden;&.selected {color: black;font-size: 15px;}}.close-btn {position: absolute;right: 6px;top: 50%;transform: translateY(-50%);color: red;cursor: pointer;}
}
</style>

效果

效果:

企业微信截图_17483173394654.png

企业微信截图_17483173487807.png

个人站点链接

我的博客链接:https://blog.yimengtut.online/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/news/907670.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2.1HarmonyOS NEXT开发工具链进阶:DevEco Studio深度实践

HarmonyOS NEXT开发工具链进阶&#xff1a;DevEco Studio深度实践 在HarmonyOS NEXT全栈自研的技术体系下&#xff0c;DevEco Studio作为一站式开发平台&#xff0c;通过深度整合分布式开发能力&#xff0c;为开发者提供了从代码编写到多端部署的全流程支持。本章节将围绕多设…

LLMs之Tool:Workflow Use的简介、特点、安装和使用方法、以及案例应用

LLMs之Tool&#xff1a;Workflow Use的简介、特点、安装和使用方法、以及案例应用 目录 Workflow Use的简介 1、Workflow Use的特点 2、Workflow Use的愿景和路线图 Workflow Use的安装和使用方法 1、安装 2、使用方法 查看所有命令 从 Python 中使用&#xff1a; 启动…

二分法算法技巧-思维提升

背景&#xff1a; 在写力扣题目“搜素插入位置 ”时&#xff0c;发现二分法的一个细节点&#xff0c;打算记录下来&#xff0c;先看一张图&#xff1a; 我们知道&#xff0c;排序数组&#xff0c;更高效的是二分查找法~~~而二分法就是切割中间&#xff0c;定义left是最开始的&…

Python 训练营打卡 Day 40

训练和测试的规范写法 一、黑白图片的规范写法&#xff0c;以MNIST数据集为例 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms # 用于加载MNIST数据集 from torch.utils.data import DataLoader # 用于创建…

数据结构之栈:原理与常用方法

1. 栈的定义 Stack是Vector的一个子类&#xff0c;它实现标准的后进先出堆栈。Stack只定义了创建空堆栈的默认构造方法。&#xff08;实际上是实现了List接口&#xff0c;因为Vector是List的子类&#xff09;。 Stack() // 创建一个空栈 2. 栈的基本操作 // 压栈操作 publi…

鸿蒙OSUniApp 开发支持图片和视频的多媒体展示组件#三方框架 #Uniapp

使用 UniApp 开发支持图片和视频的多媒体展示组件 前言 在现代移动应用中&#xff0c;图片和视频已成为内容展示的主流形式。一个优秀的多媒体展示组件不仅能提升用户体验&#xff0c;还能增强产品的互动性和视觉冲击力。随着鸿蒙&#xff08;HarmonyOS&#xff09;生态的不断…

STM32CubeMX,arm-none-eabi-gcc简单试用

在windows下&#xff0c;为stm32系列单片机编程&#xff0c;keil有了免费的试用版&#xff0c;有很多开发板示例&#xff0c;给学习单片机编程带来很大的方便。 STM32CubeMX提供了stm32单片机的功能设置&#xff0c;在输出方式上给出了几种方式&#xff0c;有mdk&#xff08;k…

灌水论坛系统总体设计文档

一、实验题目 灌水论坛系统 二、实验目的 旨在通过一个相对完整且功能丰富的Web应用实例&#xff0c;全面地实践和巩固Web开发所需的各项核心技术和工程方法&#xff0c;从而提升其综合应用能力和解决实际开发问题的能力。它不仅仅是完成一个软件&#xff0c;更是一个学习、…

Android 13中 配置签名文件与内置相应的Apk

目录 1.问题场景 2.实现思路 3.将测试代码做成APK并配置签名 4.将apk内置到系统当中的方法 1.问题场景 在展讯平台中Android13的源码已知的情况下&#xff0c;客户写了一个测试类用于调用系统中的一些接口来检验一些功能。为了方便调试排查问题我首先的思路是将客户写的测试…

HarmonyOS 5 应用开发导读:从入门到实践

一、HarmonyOS 5 概述 HarmonyOS 5 是华为推出的新一代分布式操作系统&#xff0c;其核心设计理念是"一次开发&#xff0c;多端部署"。与传统的移动操作系统不同&#xff0c;HarmonyOS 5 提供了更强大的跨设备协同能力&#xff0c;支持手机、平板、智能穿戴、智慧屏…

C语言创意编程:用趣味实例玩转基础语法(4)

文章目录 0. 前言1. &#x1f308; 彩虹文字生成器1.1 程序效果展示1.2 完整代码解析1.3 关键技术详解1.3.1 Windows控制台API1.3.2 颜色编码1.3.3 安全输入1.3.4 跨平台考虑 2. &#x1f3b5; 简易音乐播放器2.1 程序效果展示2.2 完整代码解析2.3 关键技术详解2.3.1 Windows B…

【专题】神经网络期末复习资料(题库)

神经网络期末复习资料&#xff08;题库&#xff09; 链接&#xff1a;https://blog.csdn.net/Pqf18064375973/article/details/148332887?sharetypeblogdetail&sharerId148332887&sharereferPC&sharesourcePqf18064375973&sharefrommp_from_link 【测试】 Th…

Python训练营打卡 Day41

简单CNN 知识回顾 数据增强卷积神经网络定义的写法batch归一化&#xff1a;调整一个批次的分布&#xff0c;常用与图像数据特征图&#xff1a;只有卷积操作输出的才叫特征图调度器&#xff1a;直接修改基础学习率 卷积操作常见流程如下&#xff1a; 1. 输入 → 卷积层 → Batch…

leetcode216.组合总和III:回溯算法中多条件约束下的状态管理

一、题目深度解析与组合约束条件 题目描述 找出所有相加之和为n的k个数的组合&#xff0c;且满足以下条件&#xff1a; 每个数只能使用一次&#xff08;范围为1到9&#xff09;所有数字均为唯一的正整数组合中的数字按升序排列 例如&#xff0c;当k3&#xff0c;n9时&#…

Java面试实战:从Spring到大数据的全栈挑战

Java面试实战&#xff1a;从Spring到大数据的全栈挑战 在某家知名互联网大厂&#xff0c;严肃的面试官正在面试一位名叫谢飞机的程序员。谢飞机以其搞笑的回答和对Java技术栈的独特见解而闻名。 第一轮&#xff1a;Spring与微服务的探索 面试官&#xff1a;“请你谈谈Spring…

基于vue框架的动物园饲养管理系统a7s60(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;饲养员,健康登记,工作进度,动物信息,进食信息,动物健康,动物医治,饲料信息,工作留言 开题报告内容 基于Vue框架的动物园饲养管理系统开题报告 一、研究背景与意义 &#xff08;一&#xff09;研究背景 随着城市化进程加快和公众对生…

docker镜像与dockerfile

一、docker镜像 1.什么是镜像 容器解决应用开发、测试和部署的问题&#xff0c;而镜像解决应用部署环境问题。镜像是一个只读的容器模板&#xff0c; 打包了应用程序和应用程序所依赖的文件系统以及启动容器的配置文件&#xff0c;是启动容器的基础。镜像所打 包的文件内容就是…

流媒体基础解析:音视频封装格式与传输协议

在视频处理与传输的完整流程中&#xff0c;音视频封装格式和传输协议扮演着至关重要的角色。它们不仅决定了视频文件的存储方式&#xff0c;还影响着视频在网络上的传输效率和播放体验。今天&#xff0c;我们将深入探讨音视频封装格式和传输协议的相关知识。 音视频封装格式 什…

普中STM32F103ZET6开发攻略(一)

各位看官老爷们&#xff0c;点击关注不迷路哟。你的点赞、收藏&#xff0c;一键三连&#xff0c;是我持续更新的动力哟&#xff01;&#xff01;&#xff01; 目录 普中STM32F103ZET6开发攻略 1. GPIO端口实验——点亮LED灯 1.1 实验目的 1.2 实验原理 1.3 实验环境和器材…

AWS API Gateway 配置WAF(中国区)

问题 需要给AWS API Gateway配置WAF。 AWS WAF设置 打开AWS WAF首页&#xff0c;开始创建和配置WAF&#xff0c;如下图&#xff1a; 设置web acl名称&#xff0c;然后开始添加aws相关资源&#xff0c;如下图&#xff1a; 选择资源类型&#xff0c;但是&#xff0c;我这里出…