封装一个小程序选择器(可多选、单选、搜索)
组件
取消 确认 {{item.label}} 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"); }, } } .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; } } } } }
使用
{{ taskForm.type ? getTaskTypeName(taskForm.type) : '请选择任务类型' }} {{ (Array.isArray(taskForm.personInChargeIds) && taskForm.personInChargeIds.length > 0) ? getUserNamesByIds(taskForm.personInChargeIds) : '请选择负责人' }} 提交 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("修改成功") }) }, } } .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; } }
效果
效果:
个人站点链接
我的博客链接:https://blog.yimengtut.online/
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。