当前位置: 首页 > news >正文

年份与季度筛选组件封装

先总结一下整体架构:

📚 组件结构总览

在这里插入图片描述

quarterlyScreening 组件
│
├── 模板部分 (template)
│   ├── 起始时间选择(年份 + 季度)
│   ├── 结束时间选择(年份 + 季度)
│   ├── 错误提示框
│   └── 操作按钮(重置 + 确定)
│
├── 脚本部分 (script)
│   ├── QUARTER_MAP 常量(季度映射)
│   ├── props(父组件传入的配置)
│   ├── data(组件内部状态)
│   ├── computed(计算属性 - 6个核心优化)
│   │   ├── yearOptions - 年份选项
│   │   ├── quarterOptions - 季度选项
│   │   ├── isAllFieldsFilled - 是否填写完整
│   │   ├── startTimestamp - 起始时间戳 ⭐
│   │   ├── endTimestamp - 结束时间戳 ⭐
│   │   └── isValidTimeRange - 时间范围是否有效 ⭐
│   ├── watch(监听器 - 自动验证)
│   └── methods(方法)
│       ├── handleFromYearChange - 起始年份变化
│       ├── handleToYearChange - 结束年份变化
│       ├── validate - 统一验证 ⭐
│       ├── handleReset - 重置
│       └── handleSubmit - 提交
│
└── 样式部分 (style)└── 引入外部 SCSS 文件

🎯 核心优化点(6个)

1️⃣ 季度映射(第 129-134 行)

// 将 Q1~Q4 映射为数字,方便比较
const QUARTER_MAP = { Q1: 1, Q2: 2, Q3: 3, Q4: 4 };

2️⃣ 统一表单数据(第 187-192 行)

// 使用合理的数据类型(null 表示未选择)
form: {fromYear: null,           // 数字startingQuarter: null,    // 字符串terminationYear: null,endQuarter: null
}

3️⃣ 计算属性(第 201-260 行)

自动计算、自动缓存、代码清晰

4️⃣ 时间戳概念(第 230-250 行)

// 年 * 4 + 季度数字 = 可比较的时间戳
// 2020Q2 = 8082, 2021Q1 = 8085
startTimestamp() {return this.form.fromYear * 4 + QUARTER_MAP[this.form.startingQuarter];
}

5️⃣ 自动监听验证(第 264-274 行)

// 表单任何字段改变时,自动验证
watch: {form: { handler() { this.validate(); }, deep: true }
}

6️⃣ 统一验证方法(第 300-317 行)

// 所有验证逻辑集中在一个方法中
validate() {// 清空错误 → 检查是否填完 → 验证时间范围
}

💡 关键技术点

技术说明位置
v-model双向绑定第 10, 28, 47, 65 行
v-for列表渲染第 15, 32, 52, 69 行
v-if条件渲染第 79 行
:class动态类名第 83 行
computed计算属性第 201-260 行
watch监听器第 264-274 行
$emit事件触发第 334, 363 行

📖 使用示例

<!-- 父组件中使用 -->
<quarterlyScreening:fromWhatYear="2019":cycleYearValue="10"colorChange="red"@determineFilterDate="handleDateChange"
/>

现在你应该能完全理解这个组件的每一行代码了!

组件模块

<template><!-- 季度筛选组件的根容器 --><div class="quarterlyScreening"><!-- 上部时间选择区域 --><div class="qs-top"><!-- 起始年份选择器 --><a-select placeholder="年"  <!-- 占位符文字 -->style="width: 80px"  <!-- 设置宽度为 80px -->v-model="form.fromYear"  <!-- 双向绑定到 form.fromYear,选择后自动更新数据 -->@change="handleFromYearChange"  <!-- 监听改变事件,用于联动调整结束年份 -->><!-- 循环渲染年份选项,yearOptions 是计算属性,返回年份数组 --><a-select-option v-for="year in yearOptions"  <!-- 遍历年份数组 -->:key="year"  <!-- 设置唯一 key,提升渲染性能 -->:value="year"  <!-- 选项的值,选中后赋值给 v-model 绑定的变量 -->>{{ year }}  <!-- 显示的年份文字 --></a-select-option></a-select><!-- 起始季度选择器 --><a-select class="offset-l15"  <!-- 左边距 15px 的样式类 -->placeholder="季度"  <!-- 占位符文字 -->style="width: 80px"  <!-- 设置宽度 -->v-model="form.startingQuarter"  <!-- 双向绑定到起始季度 -->><!-- 循环渲染季度选项 Q1~Q4 --><a-select-option v-for="quarter in quarterOptions"  <!-- 遍历季度数组 ['Q1', 'Q2', 'Q3', 'Q4'] -->:key="quarter"  <!-- 唯一 key -->:value="quarter"  <!-- 选项值,如 'Q1' -->>{{ quarter }}  <!-- 显示文字,如 Q1 --></a-select-option></a-select><!-- 中间的分隔文字 --><samp class="offset-l15 offset-r15"></samp>  <!-- 左右各 15px 边距 --><!-- 结束年份选择器 --><a-select placeholder="年"  <!-- 占位符 -->style="width: 80px"  <!-- 宽度 -->v-model="form.terminationYear"  <!-- 双向绑定到结束年份 -->@change="handleToYearChange"  <!-- 监听改变事件,用于验证时间范围 -->><!-- 循环渲染年份选项(与起始年份选项相同) --><a-select-option v-for="year in yearOptions"  <!-- 遍历年份数组 -->:key="year"  <!-- 唯一 key -->:value="year"  <!-- 选项值 -->>{{ year }}  <!-- 显示年份 --></a-select-option></a-select><!-- 结束季度选择器 --><a-select class="offset-l15"  <!-- 左边距 -->placeholder="季度"  <!-- 占位符 -->style="width: 80px"  <!-- 宽度 -->v-model="form.endQuarter"  <!-- 双向绑定到结束季度 -->><!-- 循环渲染季度选项 --><a-select-option v-for="quarter in quarterOptions"  <!-- 遍历季度数组 -->:key="quarter"  <!-- 唯一 key -->:value="quarter"  <!-- 选项值 -->>{{ quarter }}  <!-- 显示季度 --></a-select-option></a-select><!-- 错误提示框区域 --><!-- 只有当 errorMessage 有值时才显示(v-if--><div class="amount-label-area" v-if="errorMessage"><div class="offset-t10"  <!-- 上边距 10px --><!-- 动态 class:如果 colorChange 有值则显示红色样式,否则显示黄色样式 -->:class="colorChange ? 'redPromptBar' : 'reusable-prompt'"><!-- 感叹号图标 --><a-icon type="exclamation-circle" class="exclamation-circle"/><!-- 显示错误信息文字 --><span class="rp-TextArea">{{ errorMessage }}</span></div></div></div><!-- 下部按钮区域 --><div class="qs-bottom"><!-- 重置按钮 --><my-buttoncolor="#0070C9"  <!-- 文字颜色为蓝色 -->:width="64"  <!-- 宽度 64px -->:height="32"  <!-- 高度 32px -->class="offset-r15"  <!-- 右边距 15px -->@handleClick="handleReset"  <!-- 点击时调用重置方法 -->>重置  <!-- 按钮文字 --></my-button><!-- 确定按钮 --><my-button  color="#fff"  <!-- 文字颜色为白色 -->backgroundColor="#D71921"  <!-- 背景色为红色 -->borderColor="#D71921"  <!-- 边框色为红色 -->:width="64"  <!-- 宽度 -->:loading="submitLoading"  <!-- 是否显示加载状态 -->:height="32"  <!-- 高度 -->@handleClick="handleSubmit"  <!-- 点击时调用提交方法 -->>确定  <!-- 按钮文字 --></my-button></div></div>
</template><script>
// 导入自定义按钮组件
import MyButton from "@/components/Button.vue";// 【核心优化点1】季度映射对象:将 Q1-Q4 转换为数字便于比较
// 原代码使用 substr(1,1) 截取字符串来比较,不够优雅
// 优化后:直接通过映射获取数字,如 QUARTER_MAP['Q1'] = 1
const QUARTER_MAP = {Q1: 1,  // 第一季度对应数字 1Q2: 2,  // 第二季度对应数字 2Q3: 3,  // 第三季度对应数字 3Q4: 4   // 第四季度对应数字 4
};export default {name: 'quarterlyScreening',  // 组件名称// 注册子组件components: {MyButton  // 自定义按钮组件},// 接收父组件传入的参数props: {// 起始年份(从哪一年开始显示)fromWhatYear: {type: Number,      // 类型:数字default: 2019      // 默认值:2019 年},// 年份范围(显示多少年的选项)// 例如:fromWhatYear=2019,cycleYearValue=10,则显示 2019-2028cycleYearValue: {type: Number,      // 类型:数字default: 10        // 默认值:显示 10 年},// 提示框为空时的文字itemEmptyPrompt: {type: String,      // 类型:字符串default: '年份与季度不能为空'  // 默认提示文字},// 时间范围错误时的提示文字timeErrorPrompt: {type: String,      // 类型:字符串default: '选择的年份或季度不能早于起始年份或季度'  // 默认提示},// 颜色样式控制:传 'red' 显示红色提示,否则显示黄色colorChange: {type: String,      // 类型:字符串default: null      // 默认值:null(显示黄色)}},// 组件的响应式数据data() {return {// 提交按钮的加载状态submitLoading: false,// 【核心优化点2】统一的表单数据对象,使用合理的数据类型// 原代码使用数组存储单个值(如 fromYear: []),不合理// 优化后:使用 null 表示未选择状态,选择后变为对应的值form: {fromYear: null,           // 起始年份(数字或 null)startingQuarter: null,    // 起始季度(字符串或 null,如 'Q1')terminationYear: null,    // 结束年份(数字或 null)endQuarter: null          // 结束季度(字符串或 null)},// 错误提示信息(空字符串表示没有错误)errorMessage: ''};},// 【核心优化点3】计算属性 - 根据其他数据动态计算得出的值// 好处:自动缓存、自动更新、代码更清晰computed: {// 年份选项数组// 根据 fromWhatYear 和 cycleYearValue 动态生成// 例如:fromWhatYear=2019, cycleYearValue=10// 返回:[2019, 2020, 2021, ..., 2028]yearOptions() {return Array.from({ length: this.cycleYearValue },  // 创建指定长度的数组(_, i) => this.fromWhatYear + i   // 每个元素为起始年份+索引);},// 季度选项数组(固定返回 Q1-Q4)quarterOptions() {return ['Q1', 'Q2', 'Q3', 'Q4'];},// 判断是否所有字段都已填写// 使用 !! 转换为布尔值// 只有当所有字段都有值时才返回 trueisAllFieldsFilled() {return !!(this.form.fromYear &&          // 起始年份已选择this.form.startingQuarter &&   // 起始季度已选择this.form.terminationYear &&   // 结束年份已选择this.form.endQuarter           // 结束季度已选择);},// 【核心优化点4】时间戳概念 - 将"年+季度"转换为可比较的数字// 计算公式:年份 * 4 + 季度数字// 例如:2020年Q2 = 2020 * 4 + 2 = 8082//       2021年Q1 = 2021 * 4 + 1 = 8085// 这样就能直接比较大小:8085 > 8082,说明 2021Q1 晚于 2020Q2startTimestamp() {// 如果起始年份或季度未选择,返回 0if (!this.form.fromYear || !this.form.startingQuarter) return 0;// 计算时间戳:年 * 4 + 季度数字return this.form.fromYear * 4 + QUARTER_MAP[this.form.startingQuarter];},// 结束时间的时间戳(计算方式同上)endTimestamp() {// 如果结束年份或季度未选择,返回 0if (!this.form.terminationYear || !this.form.endQuarter) return 0;// 计算时间戳return this.form.terminationYear * 4 + QUARTER_MAP[this.form.endQuarter];},// 验证时间范围是否有效// 规则:结束时间必须 >= 起始时间isValidTimeRange() {// 如果还没填写完整,先不验证(返回 true 表示通过)if (!this.isAllFieldsFilled) return true;// 比较时间戳:结束时间戳 >= 起始时间戳return this.endTimestamp >= this.startTimestamp;}},// 【核心优化点5】监听器 - 自动监听数据变化并执行操作watch: {// 监听整个表单对象的变化form: {handler() {// 每当表单任何字段改变时,自动执行验证// 好处:实时反馈,用户体验更好this.validate();},deep: true  // 深度监听,监听对象内部属性的变化}},// 组件的方法methods: {// 起始年份改变时的处理函数// 智能联动:如果起始年份 > 结束年份,自动调整结束年份handleFromYearChange() {// 如果已选择结束年份,且起始年份 > 结束年份if (this.form.terminationYear && this.form.fromYear > this.form.terminationYear) {// 自动将结束年份调整为与起始年份相同// 例如:原来选的 2019-2021,起始改为 2023,自动变为 2023-2023this.form.terminationYear = this.form.fromYear;}// 执行验证this.validate();},// 结束年份改变时的处理函数handleToYearChange() {// 只需执行验证即可(由 watch 自动触发)this.validate();},// 【核心优化点6】统一的验证方法// 原代码在每个 change 事件中都写验证逻辑,重复度高// 优化后:统一在这里验证,代码清晰易维护validate() {// 第一步:清空之前的错误信息this.errorMessage = '';// 第二步:如果没有填写完整,不显示错误// 原因:用户还在填写过程中,不应该提示错误if (!this.isAllFieldsFilled) return true;// 第三步:验证时间范围是否有效if (!this.isValidTimeRange) {// 如果无效,设置错误信息this.errorMessage = this.timeErrorPrompt;return false;  // 返回 false 表示验证失败}// 验证通过return true;},// 重置按钮点击处理handleReset() {// 第一步:清空表单所有数据this.form = {fromYear: null,           // 重置为 nullstartingQuarter: null,terminationYear: null,endQuarter: null};// 第二步:清空错误信息this.errorMessage = '';// 第三步:触发父组件事件,传递空对象// 父组件收到空对象后可以清空筛选条件this.$emit('determineFilterDate', {});},// 确定按钮点击处理handleSubmit() {// 第一步:验证是否填写完整if (!this.isAllFieldsFilled) {// 如果未填写完整,显示错误信息this.errorMessage = this.itemEmptyPrompt;return;  // 终止执行}// 第二步:验证时间范围if (!this.validate()) {// 如果验证失败,validate() 方法已经设置了 errorMessagereturn;  // 终止执行}// 第三步:准备要提交的数据// 注意:年份转换为字符串,因为父组件可能需要字符串格式const data = {fromYear: String(this.form.fromYear),              // 数字转字符串startingQuarter: this.form.startingQuarter,        // 保持字符串格式terminationYear: String(this.form.terminationYear),// 数字转字符串endQuarter: this.form.endQuarter                   // 保持字符串格式};// 第四步:触发父组件事件,传递筛选数据// 父组件通过 @determineFilterDate 监听这个事件this.$emit('determineFilterDate', data);}}
};
</script><style scoped lang='scss'>
@import "./index.scss";
</style>
http://www.dtcms.com/a/525770.html

相关文章:

  • KingbaseES数据库:异构多活构建极致容灾
  • 做网站一个人能做吗网页设计六安模板
  • 河南郑州做网站的公司wordpress图片切换插件
  • 方法重写111
  • Spring依赖管理核心技巧与应用
  • java面试:有了解过消息队列mq吗,详细讲解一下
  • 建设校园网站公司怎么介绍自己的优势
  • 第十四届蓝桥杯大赛软件赛国赛Java大学C组(部分)
  • 2025年--Lc211- 557. 反转字符串中的单词 III--Java版
  • 网站建设售后服务承诺网站做多久才有流量
  • 网站外包制作工程建设报道
  • 【u-boot】u-boot启动文件start.S剖析(ARM64)
  • 【JUnit实战3_11】第六章:关于测试的质量(下)
  • 最新选题-基于Spark的二氧化碳排放量数据分析系统设计
  • 438.找到字符串中所有字母异位词
  • 鞍山手机网站设计广东省室内设计公司排名
  • 适合seo优化的网站制作网站鼠标特效
  • 【无标题】叽叽喳喳
  • 多线程六脉神剑第四剑:读写锁 (ReaderWriterLockSlim)
  • 网站设关键字wordpress搭建问答系统
  • 泉州高端网站建设微信h5免费制作网站模板下载
  • 第13章-人员管理
  • Maya Python入门:属性连接connectAttr()、创建节点createNode()
  • Java学习之旅第三季-17:Lambda表达式
  • 企业电子商务网站建设和一般建设网站收费标准
  • 【深度学习】深度学习核心:优化与正则化超详细笔记
  • 南昌做网站哪个好如何做好网站推广工作
  • 网站网速慢网站正在建设中_敬请期待
  • 影刀:自动化测试网页应用
  • 做彩票网站要什么接口只放一个图片做网站