用 element ui 实现季度选择器

news2025/1/15 6:26:55

由于在数据项目中经常以各种时间条件查询数据,所以时间选择器(DatePicker)组件是很常用的组件。但是在我使用的 Element UI 中,缺少了季度选择器的功能。

简易实现

一开始我根据时间范围使用 select 去遍历,如 2024-Q1、2023-Q4、2023-Q3 如此类推。

image

element 并无季度选择器

其实也算是快速解决了 element ui 无法选择季度的问题。但总感觉特别的 low,后来有时间了就去隔壁 ant design 看了看。

image

发现在新版的 ant design 都支持季度和季度范围选择器了……

查了查新的 element plus 也只是只支持了 'year' | 'years' |'month' | 'date' | 'dates' | 'datetime' | 'week' | 'datetimerange' | 'daterange' | 'monthrange' 这些个类型。

工具不给力,又不想用其他库的情况下只能手搓了。

手搓季度选择器

季度面板

参考 ant design 做了一个类似的面板。

image

<template>
  <div class="quarter-panel">
    <div class="quarter-panel-header">
      <i
        class="quarter-panel-header-icon el-icon-arrow-left"
        @click="currentYear--"
      />
      <div class="quarter-panel-header-title">{{ currentYear }} 年</div>
      <i
        class="quarter-panel-header-icon el-icon-arrow-right"
        @click="currentYear++"
      />
    </div>
    <div class="quarter-panel-content">
      <div
        v-for="option in quarterOptions"
        class="quarter-panel-item-btn"
        :class="getComputedClass(option.value)"
        :key="option.value"
        @click="emitClick(option.value)"
      >
        {{ option.label }}
      </div>
    </div>
  </div>
</template>

<script>
import dayjs from 'dayjs'
import customParseFormat from 'dayjs/plugin/customParseFormat'

dayjs.extend(customParseFormat)

export default {
  name: 'QuarterPanel',
  props: {
    value: String,
    dice: Number,
    min: String,
    max: String,
    todayDisabled: Boolean,
    featureDisabled: Boolean,
  },
  data() {
    return {
      currentYear: 2023,
    }
  },
  computed: {
    day() {
      if (this.value) {
        return dayjs(this.value, 'YYYY-MM-DD')
      }
      return dayjs()
    },
    computedDate() {
      return this.day.startOf('quarter').format('YYYY-MM-DD')
    },
    quarterOptions() {
      return [
        { label: 'Q1', value: `${this.currentYear}-01-01` },
        { label: 'Q2', value: `${this.currentYear}-04-01` },
        { label: 'Q3', value: `${this.currentYear}-07-01` },
        { label: 'Q4', value: `${this.currentYear}-10-01` },
      ]
    },
  },
  mounted() {
    this.currentYear = dayjs().year()
  },
  methods: {
    getDisabled(value) {
      let isFeature = false

      if (this.todayDisabled) {
        isFeature = dayjs()
          .subtract(1, 'day')
          .startOf('quarter')
          .isBefore(dayjs(value))
      } else if (this.featureDisabled) {
        isFeature = dayjs().startOf('quarter').isBefore(dayjs(value))
      }

      const isMin = this.min
        ? dayjs(this.min, 'YYYY-MM-DD')
            .startOf('quarter')
            .isAfter(dayjs(value, 'YYYY-MM-DD'))
        : false

      const isMax = this.max
        ? dayjs(this.max, 'YYYY-MM-DD')
            .startOf('quarter')
            .isBefore(dayjs(value, 'YYYY-MM-DD'))
        : false

      return isFeature || isMin || isMax
    },
    getComputedClass(value) {
      if (this.computedDate === value) {
        return 'quarter-panel-item-btn-active'
      }
      if (this.getDisabled(value)) {
        return 'quarter-panel-item-btn-disabled'
      }
      return ''
    },
    emitClick(value) {
      if (this.getDisabled(value)) {
        return
      }
      this.$emit('input', value)
    },
  },
  watch: {
    dice() {
      this.currentYear = this.day.year()
    },
  },
}
</script>

<style lang="scss" scoped>
$--gw-primary-color: #f6674f;

.quarter-panel {
  width: 200px;
  color: #303133;

  .quarter-panel-header {
    height: 30px;
    padding: 12px;
    display: flex;
    align-items: center;

    .quarter-panel-header-icon {
      font-size: 12;
      margin: 5px;
      cursor: pointer;

      &:hover {
        color: $--gw-primary-color;
      }
    }

    .quarter-panel-header-title {
      flex: 1;
      text-align: center;
      font-size: 16;
    }
  }

  .quarter-panel-content {
    display: flex;
    align-items: center;

    .quarter-panel-item-btn {
      flex: 1;
      font-size: 14;
      height: 30px;
      line-height: 30px;
      text-align: center;
      cursor: pointer;
      border: solid 1px transparent;
      border-radius: 5px;

      &:hover {
        color: $--gw-primary-color;
        border: solid 1px $--gw-primary-color;
      }
    }

    .quarter-panel-item-btn-active {
      background: $--gw-primary-color;
      color: #ffffff;

      &:hover {
        color: #ffffff;
      }
    }

    .quarter-panel-item-btn-disabled {
      color: #909399;
      background: #f2f6fc;
      cursor: not-allowed;

      &:hover {
        color: #909399;
        background: #f2f6fc;
      }
    }
  }
}
</style>

季度选择器

将面板放到 el-popover 中实现类似 DatePicker 的效果。并且提供了像清空数据、最大值、最小值等常用功能。

image

<template>
  <div class="quarter-picker" :class="{ 'quarter-picker-disabled': disabled }">
    <div class="quarter-picker-date-button">
      <i class="iconfont icon-date-select-icon quarter-picker-time-icon" />
      <el-popover
        placement="bottom-start"
        width="200"
        trigger="click"
        ref="datePopover"
        :disabled="disabled"
        @show="initPopover"
      >
        <div
          class="quarter-picker-date-button-item quarter-picker-date-button-item-long"
          slot="reference"
        >
          <span v-if="form.date" class="button-item-span">
            {{ dateQuarterStr }}
          </span>
          <span v-else class="button-item-span">选择时间</span>
          <div class="bottom-line" />
        </div>
        <quarterPanel
          v-model="form.date"
          :dice="dice"
          :min="min"
          :max="max"
          :featureDisabled="featureDisabled"
          :todayDisabled="todayDisabled"
          @input="emitDateChange()"
        />
      </el-popover>
      <i
        v-show="form.date && clearable"
        class="el-icon-close quarter-picker-clear-icon"
        @click.stop="clearCurrentDate"
      />
    </div>
  </div>
</template>

<script>
import dayjs from 'dayjs'
import customParseFormat from 'dayjs/plugin/customParseFormat'
import quarterOfYear from 'dayjs/plugin/quarterOfYear'

import quarterPanel from './quarterPanel.vue'

dayjs.extend(customParseFormat)
dayjs.extend(quarterOfYear)

/**
 * date 日期
 */
export default {
  name: 'QuarterPicker',
  components: {
    quarterPanel,
  },
  props: {
    date: String,
    min: String,
    max: String,
    featureDisabled: Boolean,
    todayDisabled: Boolean,
    disabled: Boolean,
    clearable: Boolean,
  },
  data() {
    return {
      form: {
        date: '',
      },
      dice: 0,
    }
  },
  mounted() {
    this.syncData()
  },
  computed: {
    dateQuarterStr() {
      if (!this.form.date) return '选择季'

      const dj = dayjs(this.form.date).startOf('quarter')
      return `${dj.year()}-Q${dj.quarter()}`
    },
  },
  methods: {
    initPopover() {
      this.dice++
    },
    syncData() {
      this.form.date = this.date
    },
    clearCurrentDate() {
      if (this.disabled) return
      this.form.date = ''

      this.emitDateChange()
    },
    emitDateChange() {
      this.$emit('change', this.form)

      this.closePopovers()
    },
    closePopovers() {
      this.$refs.datePopover.doClose()
    },
  },
  watch: {
    date() {
      if (this.form.date !== this.date) {
        this.syncData()
      }
    },
  },
}
</script>

<style scoped lang="scss">
$--gw-primary-color: #f6674f;

.quarter-picker {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: flex-end;

  .quarter-picker-date-button {
    display: flex;
    position: relative;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    user-select: none;
    margin-left: 5px;
    width: 250px;
    padding-left: 10px;
    height: 28px;
    background: #ffffff;
    border: 1px solid #dcdfe6;
    font-size: 14px;
    font-family: Microsoft YaHei;
    font-weight: 400;
    color: #282c32;
    border-radius: 4px;

    .quarter-picker-time-icon {
      position: absolute;
      left: 12px;
    }

    .quarter-picker-date-button-item {
      position: relative;
      height: 28px;
      line-height: 28px;
      text-align: center;
      width: 70px;
      cursor: pointer;

      .bottom-line {
        position: absolute;
        bottom: 0;
        left: 0;
        right: 0;
        height: 2px;
        border-radius: 1px;
        background: transparent;
      }

      &:hover {
        .bottom-line {
          background: $--gw-primary-color;
        }
      }
    }

    .quarter-picker-date-button-item-long {
      width: 200px;

      .button-item-span {
        display: inline-block;
        width: 90px;
        text-align: center;
      }

      .button-item-span-active {
        color: $--gw-primary-color;
      }
    }

    .quarter-picker-clear-icon {
      position: absolute;
      right: 12px;
      font-size: 14;
      cursor: pointer;

      &:hover {
        color: $--gw-primary-color;
      }
    }
  }
}

.quarter-picker-disabled {
  .quarter-picker-date-button {
    color: #c0c4cc;
    background-color: #f2f6fc;

    .quarter-picker-date-button-item {
      cursor: not-allowed;
    }
  }

  .quarter-picker-date-button-item {
    &:hover {
      .bottom-line {
        background: transparent !important;
      }
    }
  }

  .quarter-picker-clear-icon {
    cursor: not-allowed !important;

    &:hover {
      color: #c0c4cc !important;
    }
  }
}
</style>

组件的使用

最后就是组件的使用了:

  <QuarterPicker
    type="quarter"
    :date="quarter.date"
    :min="minDate"
    :max="maxDate"
    :featureDisabled="options.featureDisabled"
    :todayDisabled="options.todayDisabled"
    :disabled="options.disabled"
    :clearable="options.clearable"
    @change="handleQuarterPickerChange"
  />
handleQuarterPickerChange({ date }) {
  this.quarter.date = date

  this.$message({
    message: '触发查询请求',
    type: 'success',
  })
},

最后

另外,季度范围选择器也可以用类似的思路来实现。以上就是个人解决季度选择器的方式。希望能对有类似需求的同学一些帮助。

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

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

相关文章

Node.js 基础学习

文章目录 1. Node.js1.1 是什么&#xff1f;1.2 作用 2. 命令行工具2.1 命令的结构2.2 常用命令 3. Node.js 注意点3.1 Node.js 中不能使用DOM 和BOM 的API3.2 Node.js 中顶级对象叫做global 4. Buffer4.1 Buffer 特点4.2 Buffer 创建方式4.3 Buffer 操作与注意点 5. 计算机基础…

Rust入门-引用借用

一、引用借用&#xff0c;是什么、为什么、怎么用 所有权上篇我们已经讨论过了&#xff0c;所以这篇我们讨论Rust的引用借用 1、引用借用 是什么&#xff1f; Rust 通过借用(Borrowing) 这个概念来达成上述的目的&#xff0c;获取变量的引用&#xff0c;称之为借用(borrowin…

CERLAB无人机自主框架: 1-环境搭建

前言&#xff1a;更多更新文章详见我的个人博客主页【MGodmonkeyの世界】 描述&#xff1a;欢迎来到CERLAB无人机自主框架&#xff0c;这是一个用于自主无人飞行器 (UAV) 的多功能模块化框架。该框架包括不同的组件 (模拟器&#xff0c;感知&#xff0c;映射&#xff0c;规划和…

【数据结构-串-数组-广义表】

目录 1 串-理解1.1 串的抽象定义&#xff1a;-理解1.2 串的存储结构-不断掌握1.2.1 顺序存储结构&#xff1a;1.2.2 链式存储结构&#xff1a; 1.3 串的模式匹配算法&#xff1a;-掌握1.3.1 BF暴力求解算法-代码 -掌握1.3.2 KMP求解算法-代码--掌握 2 数组-不断掌握2.1 顺序存储…

vue-cli2 与vue-cli3,vue2与vue3 初始化项目,本地vue项目,详细解析区别(2024-04-19)

目录 1、区别&#xff08;vue-cli2 与 vue-cli3 &#xff09; 2、例子1&#xff08;vue2项目&#xff09; 2.1 版本与命令行 2.2 项目本地截图 2.3 项目文件解析 &#xff08;1&#xff09;package.json 文件 &#xff08;2&#xff09;webpack.dev.conf.js文件 &#…

PTA图论的搜索题

目录 7-1 列出连通集 题目 输入格式: 输出格式: 输入样例: 输出样例: AC代码 7-2 六度空间 题目 输入格式: 输出格式: 输入样例: 输出样例: 思路 AC代码 7-3 地下迷宫探索 题目 输入格式: 输出格式: 输入样例1: 输出样例1: 输入样例2: 输出样例2: 思路 …

股票战法课程之主力的痕迹

文章目录 1. 主力的操作痕迹2. 主力的建仓2.1 建仓的三种方式2.2 建仓的五个特点2.3 建仓的迹象2.4 建仓的成交量特征 1. 主力的操作痕迹 序号痕迹原因1不跟随大盘节奏筹码都在主力手中2突发利空消息&#xff0c;股价不跌反涨主力被套&#xff0c;不希望散户抛盘3很小的成交量…

【初识Qt】如何使用QtCreator创建项目

文章目录 1 :peach:Qt Creator 概览:peach:2 :peach:使⽤ Qt Creator 新建项目:peach:2.1 :apple:新建项目:apple:2.2 :apple:使用标签实现 Hello World 程序:apple:2.2.1 :lemon:纯代码方式实现:lemon:2.2.2 :lemon:可视化操作实现:lemon: 2.3 :apple:使用按钮实现 Hello Worl…

vue element-ui 表格横向滚动条在合计项下方

目前效果 需求效果 1.隐藏bodyWrapper滚动条&#xff0c;显示footerWrapper滚动条 css代码如下&#xff1a; div ::v-deep .el-table--scrollable-x .el-table__body-wrapper{overflow-x: hidden!important;z-index: 2!important;} div ::v-deep .el-table__footer-wrapper …

WWW ‘24 | EarnMore: 如何利用强化学习来处理可定制股票池中的投资组合管理问题

WWW 24 | EarnMore: 如何利用强化学习来处理可定制股票池中的投资组合管理问题 原创 QuantML QuantML 2024-04-16 09:04 上海 Content 本文主要探讨了如何利用强化学习&#xff08;Reinforcement Learning, RL&#xff09;来处理可定制股票池&#xff08;Customizable Stock …

关于RA8900CE时钟芯片的使用注意事项

在快节奏的现代社会&#xff0c;时间变得越来越宝贵。对于时钟的电子设计&#xff0c;高精度且低功耗逐渐成为主流。我们就有一个汽车显示屏的时钟显示项目&#xff0c;要求时钟一天的误差控制在1s以内。要想达到此要求&#xff0c;则必须满足晶振的频率偏差PPM<1/60/60/24*…

【Hadoop大数据技术】——Sqoop数据迁移(学习笔记)

&#x1f4d6; 前言&#xff1a;在实际开发中&#xff0c;有时候需要将HDFS或Hive上的数据导出到传统关系型数据库中&#xff08;如MySQL、Oracle等&#xff09;&#xff0c;或者将传统关系型数据库中的数据导入到HDFS或Hive上&#xff0c;如果通过人工手动进行数据迁移的话&am…

微博聚类文本分析和可视化

本文使用python抓取微博数据并对微博文本分析和可视化&#xff0c;LDA&#xff08;树图&#xff09;、关系图、词云、时间趋势&#xff08;折线图&#xff09;、热度地图、词典情感分析&#xff08;饼图和3D柱状图&#xff09;、词向量神经网络情感分析、tfidf聚类、词向量聚类…

go语言并发实战——日志收集系统(四) 利用tail包实现对日志文件的实时监控

Linux中的tail命令 tail 命令是一个在 Unix/Linux 操作系统上用来显示文件末尾内容的命令。它可以显示文件的最后几行内容&#xff0c;默认情况下显示文件的最后 10 行。tail 命令 非常有用&#xff0c;特别是在我们查看日志文件或者监视文件变化时。 基本用法如下&#xff1a…

搭建sql-lab出现的php不兼容

下载不了的时候&#xff0c;直接打开该网址下载5.xphp版本&#xff0c;解压到C:\php_studyv8\phpstudy\phpstudy_pro\Extensions\php&#xff08;可能路径都不一样&#xff0c;找到Extensions\php放到该目录下&#xff09;

Excel模板导入、导出工具类

1.引入maven依赖&#xff0c;利用hutool的excel读取 Hutool-poi对excel读取、写入 <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.16</version></dependency> <depen…

期权小知识科普

期权的交易时间 上交所期权合约的交易时间为每个交易日9:15至9:25、9:30至11:30、13&#xff1a;00至15:00。 其中&#xff0c;9:15至9:25为开盘集合竞价时间&#xff0c;14:57-15:00为收盘集合竞价时间&#xff0c;其余时段为连续竞价时间&#xff0c;交易所规则另有规定的除…

后台管理系统加水印(react)

效果 代码图片 代码 window.waterMark function (config) {var defaultConfig {content: 我是水印,fontSize: 16px,opacity: 0.3,rotate: -15,color: #ADADAD,modalId: J_waterMarkModalByXHMAndDHL,};config Object.assign({}, defaultConfig, config);var existMarkModal…

Hadoop3:大数据的基本介绍

一、什么是大数据 1、大数据的4v特点 Volume&#xff08;大量&#xff09; Velocity&#xff08;高速&#xff09; Variety&#xff08;多样&#xff09; Value&#xff08;低价值密度&#xff09; 2、大数据部门间的工作岗位 第三部分&#xff0c;其实就是JavaWeb 二、…

李沐53_语言模型——自学笔记

语言模型 1.预测文本序列出现的概率 2.应用在做预训练模型 3.生成文本&#xff0c;给定前面几个词&#xff0c;不断生成后续文本 4.判断多个序列中哪个更常见 真实数据集的统计 《时光机器》数据集构建词表&#xff0c; 并打印前10个最常用的&#xff08;频率最高的&…