「Vue 项目中实现智能时间选择:带业务规则的级联选择器」

#创作灵感

公司业务需要,某个时间节点前可以选择到月,某个时间节点后只能选择季度

vue2  Vant2

javascript

import { Cascader, Field, Form, Popup, Button } from 'vant';
import 'vant/lib/index.css';export default {name: 'CascaderPage',components: {VanCascader: Cascader,VanField: Field,VanForm: Form,VanPopup: Popup,VanButton: Button},props: {title: {type: String,default: '选择时间'},// 起始年份,默认从当前年往前5年startYear: {type: Number,default: new Date().getFullYear() - 5},// 结束年份,默认从当前年往后5年endYear: {type: Number,default: new Date().getFullYear() + 5}},data() {return {showPopup: false,cascaderValue: '',fieldValue: '',selectedResult: '',fieldNames: {text: 'label',value: 'value',children: 'children'}};},computed: {// 生成级联选择的选项options() {const yearOptions = [];// 生成年份选项for (let year = this.startYear; year <= this.endYear; year++) {const quarterOptions = [];// 生成季度选项for (let quarter = 1; quarter <= 4; quarter++) {const quarterObj = {label: `${year}年第${quarter}季度`,value: `${year}-Q${quarter}`// 移除默认children属性,避免空选项};// 判断是否需要生成月份选项// 规则:2025年9月及之前需要月份,之后不需要if (year < 2025) {// 2025年之前,所有季度都需要月份quarterObj.children = this.getMonthsByQuarter(quarter);} else if (year === 2025) {// 2025年,只有前3季度需要月份if (quarter <= 3) {quarterObj.children = this.getMonthsByQuarter(quarter);}}// 2025年之后的年份,不生成月份选项quarterOptions.push(quarterObj);}yearOptions.push({label: `${year}年`,value: year.toString(),children: quarterOptions});}return yearOptions;}},methods: {// 根据季度获取对应的月份getMonthsByQuarter(quarter) {const months = [];let startMonth, endMonth;switch (quarter) {case 1:startMonth = 1;endMonth = 3;break;case 2:startMonth = 4;endMonth = 6;break;case 3:startMonth = 7;endMonth = 9;break;case 4:startMonth = 10;endMonth = 12;break;default:return [];}for (let month = startMonth; month <= endMonth; month++) {months.push({label: `${month}月`,value: month.toString()});}return months;},// 处理选择变化 - 只在选择完最后一级选项时关闭handleChange(value) {const { selectedOptions, tabIndex } = value;console.log('选择变化:', value, selectedOptions, tabIndex);// 如果没有选择值,不处理if (!selectedOptions || selectedOptions.length === 0) return;// 获取当前选中的年份const selectedYear = parseInt(selectedOptions[0].value);// 构建正确格式的selectedValues数组const selectedValues = [];selectedValues.push(selectedOptions[0].value); // 年份if (selectedOptions.length >= 2) {// 对于季度,提取数字部分const quarterStr = selectedOptions[1].value;if (quarterStr.includes('-Q')) {selectedValues.push(quarterStr.split('-Q')[1]); // 只提取季度数字} else {selectedValues.push(quarterStr);}}if (selectedOptions.length === 3) {selectedValues.push(selectedOptions[2].value); // 月份}// 检查是否已经选择到最后一级if (selectedOptions.length === 2) {// 情况1: 如果是2025年之后或2025年第4季度,选择完季度就关闭const quarterValue = selectedOptions[1].value;const quarter = parseInt(quarterValue.includes('-Q') ? quarterValue.split('-Q')[1] : quarterValue);if (selectedYear > 2025 || (selectedYear === 2025 && quarter === 4)) {this.onConfirm(selectedValues, selectedOptions);}// 其他情况:选择完季度后继续选择月份,不关闭} else if (selectedOptions.length === 3) {// 情况2: 选择完月份后关闭this.onConfirm(selectedValues, selectedOptions);}},// 确认选择onConfirm(selectedValues, selectedOptions) {if (!selectedValues || selectedValues.length === 0) return;// 格式化选中的结果const formattedResult = this.formatSelectedResult(selectedValues);this.fieldValue = formattedResult;this.selectedResult = `您选择了:${formattedResult}`;this.showPopup = false;},// 格式化选中的结果formatSelectedResult(selectedValues) {if (!selectedValues || selectedValues.length === 0) return '';// 处理selectedValues可能是字符串的情况let values = Array.isArray(selectedValues) ? selectedValues : [selectedValues];// 如果只有一个值,尝试从值中解析出年份if (values.length === 1) {const value = values[0];// 检查是否是季度格式if (typeof value === 'string' && value.includes('-Q')) {const parts = value.split('-Q');const year = parts[0];const quarter = parts[1];return `${year}年第${quarter}季度`;}// 只显示年份return `${value}年`;}let result = '';// 年份result += `${values[0]}年`;// 季度if (values.length >= 2) {let quarter;if (typeof values[1] === 'string' && values[1].includes('-Q')) {// 处理字符串格式的季度值quarter = values[1].split('-Q')[1];} else {// 直接使用季度值quarter = values[1];}result += `第${quarter}季度`;}// 月份 - 确保月份显示为两位数格式if (values.length === 3) {const month = parseInt(values[2]);// 格式化月份为两位数const formattedMonth = month < 10 ? `0${month}` : `${month}`;result += `${formattedMonth}月`;}return result;},// 表单提交onSubmit(values) {if (!this.fieldValue) {this.$toast('请选择时间');return;}this.$toast(`提交成功:${this.fieldValue}`);}},mounted() {// 生命周期钩子:设置默认选中最后一项try {if (this.options.length > 0) {const lastYear = this.options[this.options.length - 1];if (lastYear.children && lastYear.children.length > 0) {const lastQuarter = lastYear.children[lastYear.children.length - 1];const selected = [lastYear.value,lastQuarter.value];// 如果有月份选项,也选中最后一个if (lastQuarter.children && lastQuarter.children.length > 0) {selected.push(lastQuarter.children[lastQuarter.children.length - 1].value);}this.cascaderValue = selected.join('/');this.fieldValue = this.formatSelectedResult(selected);this.selectedResult = `您选择了:${this.fieldValue}`;}}} catch (error) {console.error('设置默认选中项失败:', error);}}
};

HTML

  <div class="cascader-container"><h2>Vant 时间级联选择器示例</h2><van-form @submit="onSubmit"><div class="field-container"><van-fieldv-model="fieldValue"readonlylabel="时间选择"placeholder="请选择时间":value="fieldValue"/><van-button type="primary" @click="showPopup = true"style="margin-left: 10px; min-width: 100px;">选择时间</van-button></div></van-form><!-- Popup弹窗 --><van-popupv-model="showPopup"roundposition="bottom":style="{ height: '80%' }"><div class="popup-header"><h3>{{ title }}</h3><van-button type="text" @click="showPopup = false"style="position: absolute; right: 16px; top: 16px;">取消</van-button></div><van-cascaderv-model="cascaderValue":options="options":field-names="fieldNames"@change="handleChange"@close="showPopup = false"placeholder=""/></van-popup><div class="result-section" v-if="selectedResult"><h3>选择结果</h3><p>{{ selectedResult }}</p></div></div>

css

.cascader-container {padding: 20px;max-width: 600px;margin: 0 auto;
}.field-container {display: flex;align-items: center;
}.popup-header {padding: 16px;border-bottom: 1px solid #eee;position: relative;text-align: center;
}.popup-header h3 {margin: 0;color: #333;font-size: 16px;
}.cascader-container h2 {text-align: center;margin-bottom: 20px;color: #333;
}.result-section {margin-top: 30px;padding: 15px;background-color: #f5f5f5;border-radius: 8px;
}.result-section h3 {margin-bottom: 10px;color: #666;
}.result-section p {color: #333;font-size: 16px;
}

vue3 vant4

HTML TS 

<template><div class="date-cascader-container"><!-- 添加激活按钮触发显示 --><van-button @click="show = true">选择时间</van-button><van-popup v-model:show="show" round position="bottom"><van-cascaderv-model:selected-values="selectedValues":options="options":title="title"@change="handleChange"@close="show = false":field-names="fieldNames"placeholder=""/></van-popup><div v-if="selectedValues.length" class="selected-result">已选择: {{ formatSelectedResult() }}</div></div>
</template><script setup>
import { ref, computed, watch, onMounted } from 'vue';// 先定义show变量
const show = ref(false);
// 选中的值
const selectedValues = ref([]);// 配置级联选择的字段名
const fieldNames = {text: 'label',value: 'value',children: 'children'
};// 组件参数
const props = defineProps({title: {type: String,default: '选择时间'},// 起始年份,默认从当前年往前5年startYear: {type: Number,default: new Date().getFullYear() - 5},// 结束年份,默认从当前年往后5年endYear: {type: Number,default: new Date().getFullYear() + 5}
});// 生成级联选择的选项
const options = computed(() => {const yearOptions = [];// 生成年份选项for (let year = props.startYear; year <= props.endYear; year++) {const quarterOptions = [];// 生成季度选项for (let quarter = 1; quarter <= 4; quarter++) {const quarterObj = {label: `${year}年第${quarter}季度`,value: `${year}-Q${quarter}`// 移除默认children属性,避免空选项};// 判断是否需要生成月份选项// 规则:2025年9月及之前需要月份,之后不需要if (year < 2025) {// 2025年之前,所有季度都需要月份quarterObj.children = getMonthsByQuarter(quarter);} else if (year === 2025) {// 2025年,只有前3季度需要月份if (quarter <= 3) {quarterObj.children = getMonthsByQuarter(quarter);}}// 2025年之后的年份,不生成月份选项quarterOptions.push(quarterObj);}yearOptions.push({label: `${year}年`,value: year.toString(),children: quarterOptions});}return yearOptions;
});// 根据季度获取对应的月份
function getMonthsByQuarter(quarter) {const months = [];let startMonth, endMonth;switch (quarter) {case 1:startMonth = 1;endMonth = 3;break;case 2:startMonth = 4;endMonth = 6;break;case 3:startMonth = 7;endMonth = 9;break;case 4:startMonth = 10;endMonth = 12;break;default:return [];}for (let month = startMonth; month <= endMonth; month++) {months.push({label: `${month}月`,value: month.toString()});}return months;
}// 处理选择变化 - 只在选择完最后一级选项时关闭
const handleChange = ({ selectedValues, selectedOptions }) => {console.log('选择变化:', selectedValues, selectedOptions);// 如果没有选择值,不处理if (!selectedOptions || selectedOptions.length === 0) return;// 获取当前选中的年份const selectedYear = parseInt(selectedOptions[0].value);// 检查是否已经选择到最后一级if (selectedOptions.length === 2) {// 情况1: 如果是2025年之后或2025年第4季度,选择完季度就关闭const quarter = parseInt(selectedOptions[1].value.split('-Q')[1]);if (selectedYear > 2025 || (selectedYear === 2025 && quarter === 4)) {show.value = false;}// 其他情况:选择完季度后继续选择月份,不关闭} else if (selectedOptions.length === 3) {// 情况2: 选择完月份后关闭show.value = false;}
};// 格式化选中的结果
const formatSelectedResult = () => {if (selectedValues.value.length === 0) return '';let result = '';// 年份result += `${selectedValues.value[0]}年`;// 季度if (selectedValues.value.length >= 2) {const quarter = selectedValues.value[1].split('-Q')[1];result += `第${quarter}季度`;}// 月份if (selectedValues.value.length === 3) {result += `${selectedValues.value[2]}月`;}return result;
};// 暴露选中的值
const emits = defineEmits(['update:modelValue']);
watch(selectedValues, (newVal) => {emits('update:modelValue', newVal);
});// 生命周期钩子:设置默认选中最后一项
onMounted(() => {try {if (options.value.length > 0) {const lastYear = options.value[options.value.length - 1];if (lastYear.children && lastYear.children.length > 0) {const lastQuarter = lastYear.children[lastYear.children.length - 1];const selected = [lastYear.value,lastQuarter.value];// 如果有月份选项,也选中最后一个if (lastQuarter.children && lastQuarter.children.length > 0) {selected.push(lastQuarter.children[lastQuarter.children.length - 1].value);}selectedValues.value = selected;}}} catch (error) {console.error('设置默认选中项失败:', error);}
});
</script><style scoped>
.date-cascader-container {margin: 20px;min-height: 200px; /* 确保容器有足够高度 */
}
</style>

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

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

相关文章

day1———Qt———应用程序界面设置

1&#xff0c;定义一个Mystring类代替string的功能#include <iostream> #include <string.h>using namespace std; class Mystring {friend ostream &operator<<(ostream &cout,const Mystring &s);friend istream &operator>>(istrea…

apache实现LAMP+apache(URL重定向)

1.apache实现LAMPLAMP是指一组通常一起使用来运行动态网站的自由软件名称首字母的缩写a.L是指Linux操作系统b,.A是指Apache&#xff0c;用来提供Web服务c.M指MySQL&#xff0c;用来提供数据库服务d.P指PHP&#xff0c;是动态网站的一种开发语言1.1php运行方式说明php是脚本语言…

SAConv可切换空洞卷积

SAConv可切换空洞卷积 带来的改进机制时可切换的空洞卷积 是一种创新型卷积网络 专门为增强物体检测和分割任务&#xff0c;中特征提取去设计 SAC核心时相同的输入儿子应用到不同空洞率去进行卷积&#xff0c;设计特别开关函数融合这些不同卷积的成果 该方法可让网络更灵活的适…

基于Matlab的雾霾天气和夜间车牌识别系统

在复杂天气和低光照环境下&#xff0c;车牌识别系统的准确率和稳定性显著下降&#xff0c;严重影响交通管理与智能监控的可靠性。本文针对雾霾天气和夜间环境下车牌图像特征模糊、对比度低、噪声干扰严重的问题&#xff0c;提出了一种融合图像增强与模板匹配的车牌识别方法。系…

华为云/本地化部署K8S-查看容器日志

华为云日志查看 目前工作的大部分情况下&#xff0c;通过华为云LTS云日志服务就可以满足日常需求。 不过上线时过来支援的开发老哥更习惯于从容器里查看日志&#xff0c;也一并记录下以备不时之需。 1.登录服务节点服务器 点击左侧三个横线&#xff0c;选择 应用服务-云容器引擎…

【MySQL 死锁:从 “业务卡顿“ 到 “根因定位“ 的实战指南】

MySQL 死锁&#xff1a;从 “业务卡顿” 到 “根因定位” 的实战指南 后端开发必看&#xff1a;MySQL死锁排查与预防全攻略线上系统突然报出Deadlock found when trying to get lock; try restarting transaction&#xff0c;用户操作卡顿甚至超时&#xff0c;排查时却对着一堆…

从虚拟化基石到云原生架构的降维打击:用dd/mkfs玩转namespace隔离,解锁Docker/K8S资源密码,看透物理机到云服务器的进化之路

本篇摘要 本文围绕虚拟化与容器化技术展开&#xff0c;涵盖架构演进、Docker/K8S优势与挑战、namespace隔离实操&#xff08;如主机名/PID隔离&#xff09;、磁盘操作&#xff08;dd/mkfs/df/mount&#xff09;等&#xff0c;对比虚拟机与容器差异&#xff0c;阐明技术原理与架…

自动化测试的概念

文章目录自动化测试能够取代人工测试吗&#xff1f;回归测试自动化分类自动化测试金字塔为啥单元测试的性价比这么高呢&#xff1f;那为啥UI自动化测试的性价比没有组件测试的高呢&#xff1f;web自动化测试举例引入自动化测试的准备工作自动化测试的简单示例自动化测试能够取代…

OSPF故障排查实战:如何通过一条命令精准定位网络掩码不匹配问题

掌握display ospf error命令的解读技巧&#xff0c;快速解决OSPF邻接关系建立失败难题。一、问题背景与场景引入 在网络运维工作中&#xff0c;OSPF&#xff08;开放最短路径优先&#xff09;协议作为主流的内部网关协议&#xff0c;其稳定运行至关重要。然而&#xff0c;在实际…

Redis----如何引入分布式锁

一、概述首先引入分布式锁指的是应用程序引入&#xff0c;不是Redis本身引入&#xff0c;Redis作为中间件可以作为分布式锁的一个典型实现方案&#xff0c;同时也有一些其他的实现方案。分布式锁指的是一个/组程序&#xff0c;使用Redis实现的话就是通过添加一个特殊的Key-Valu…

prometheus-2.42.0.linux-amd64.tar.gz 安装配置展示

一、prometheus 1.1解压文件 # tar -xzvf prometheus-2.42.0.linux-amd64.tar.gz -C ~/apps/ prometheus-2.42.0.linux-amd64/ prometheus-2.42.0.linux-amd64/NOTICE prometheus-2.42.0.linux-amd64/consoles/ prometheus-2.42.0.linux-amd64/consoles/index.html.example p…

Linux 标准输入 标准输出 标准错误

目录一. 简介二. 常见用法2.1 输出重定向2.2 错误重定向2.3 同时重定向标准输出 错误2.4 输入重定向2.5 特殊设备三. 这样设计的好处3.1 区分正常信息和错误信息3.2 方便调用方脚本处理3.3 与管道结合时更清晰四. 案例4.1 if判断4.2 ls查询一. 简介 ⏹在 Linux/Unix 中&#…

零基础新手小白快速了解掌握服务集群与自动化运维(二)Linux Journalctl命令、Journalctl日志持久化存储

Linux提供了一个强大的日志系统&#xff0c;它可以跟踪和记录系统的各种活动。在这个系统中&#xff0c;journalctl是一个非常重要的工具&#xff0c;用于查询和操作由systemd进程管理的日志。 本文将深入探讨journalctl命令&#xff0c;介绍其基本使用、高级选项及示例等内容…

【学习】【js】栈数据结构

栈 栈是一种遵从后进先出&#xff08;LIFO&#xff09;原则的有序集合。新添加或待删除的元素都保存在栈的同一端&#xff0c;称作栈顶&#xff0c;另一端就叫栈底。在栈里&#xff0c;新元素都靠近栈顶&#xff0c;旧元素都接近栈底。 基于数组的栈 时间复杂度O(n),占用较多的…

【Linux】基本指令 · 下

alias 指令起别名为什么 ls -l 指令等价于 ll 指令呢&#xff1f;指令就是可执行程序&#xff0c;和我们自己写的代码编译好的程序&#xff0c;没有本质区别&#xff01; 指令在系统的某一个位置存在&#xff01; 执行指令前&#xff0c;现在系统中查找对应的指令指令在根目录下…

计算机视觉(opencv)实战二十二——指纹图像中提取特征点,计算两两指纹之间的相似度

指纹识别原理与代码实现详解指纹识别是一种常见的生物特征识别技术&#xff0c;广泛应用于门禁系统、手机解锁、考勤打卡、身份认证等场景。其核心思想是&#xff1a;从指纹图像中提取特征点&#xff0c;计算两幅指纹之间的相似度&#xff0c;并根据相似度判断是否为同一人。本…

Linux基础之部署mysql数据库

文章目录一、环境准备二、源码解压与依赖三、CMake 编译配置四、配置 MySQL权限管理修改配置文件 /etc/my.cnf五、环境变量设置六、数据库初始化七、服务管理八、账号密码管理一、环境准备 yum -y install gcc gcc-c ncurses ncurses-devel bison cmakegcc / gcc-c&#xff1a…

代码审计-PHP专题原生开发文件上传删除包含文件操作监控Zend源码解密1day分析

快速分析脆弱&#xff1a;1、看文件路径2、看代码里面的变量&#xff08;可控&#xff09;3、看变量前后的过滤文件安全挖掘点&#xff1a;1、脚本文件名2、应用功能点3、操作关键字文件上传&#xff0c;文件下载(读取)&#xff0c;文件包含&#xff0c;文件删除等emlog-文件上…

零基础搭建 Hexo 博客:从本地到 GitHub Pages 全流程指南

零基础搭建 Hexo 博客&#xff1a;从本地到 GitHub Pages 全流程指南 Hexo 是一个快速、简洁且高效的博客框架&#xff0c;支持使用 Markdown 来编写文章&#xff0c;并能快速生成静态网页&#xff0c;非常适合想要搭建个人博客的同学。本文将带你从零开始&#xff0c;本地搭建…

Git 简介

Git 是目前全球最流行的分布式版本控制系统&#xff08;Distributed Version Control System, DVCS&#xff09;&#xff0c;核心作用是追踪文件修改历史、支持多人协同开发&#xff0c;并能高效管理代码&#xff08;或任何文本类文件&#xff09;的版本迭代。它由 Linux 内核创…