記錄--設計一個可選擇不連續的時間範圍的日期選擇器

来源:https://www.cnblogs.com/smileZAZ/archive/2023/06/16/17486186.html
-Advertisement-
Play Games

這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 npm包:sta-datepicker 效果圖 需求 普通的時間選擇器要麼只能單選,要麼只能選範圍,不可以隨意選擇若幹個時間,同時大多數現成的時間選擇器選擇結束會收起來,很不方便。現在需求如下 1、可以自己控制展開收起 2、可以選擇不連續 ...


這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助

  • npm包:sta-datepicker
  • 效果圖 

需求

普通的時間選擇器要麼只能單選,要麼只能選範圍,不可以隨意選擇若幹個時間,同時大多數現成的時間選擇器選擇結束會收起來,很不方便。現在需求如下 1、可以自己控制展開收起 2、可以選擇不連續的多個時間範圍的日期 3、可以批量選中日期,不需要一個個點擊

實現過程(分幾個步驟,具體可以看源碼)

1、生成一個日曆

  • 頂部為固定的幾個按鈕,可以綁定切換年份月份的函數

  • 中間為固定的星期,一個七個

  • 底部為具體日期,由三部分組成,即:上個月底幾天,這個月整個月,下個月初幾天

    • 算好平年閏年,輸出當前月份第一天是周幾
    • 根據當前月份的第一天的星期數,計算日曆要展示上個月月底的幾天
    • 根據當前月份最後一天的星期數,計算日曆要展示下個月月初的幾天
  • 日期部分使用div遍歷三個數組,左浮動或者彈性盒直接堆起來即可

  created() {
    this.trueDateBox()
  },
  methods: {
    trueDateBox() {
      if (this.date === "") {
        const date = new Date()
        this.year = date.getFullYear()
        this.updateLeapYear()
        this.month = date.getMonth() + 1
        this.day = null
      }
      this.dayScreen()
    },
    // 設置算好閏年平年
    updateLeapYear() {
      if (this.isLeapYear(this.year)) {
        this.monthDay[1] = 29
      } else {
        this.monthDay[1] = 28
      }
    },
    isLeapYear(year) {
      return year % 100 === 0 ? year % 400 === 0 : year % 4 === 0
    },
    // 日期顯示
    dayScreen() {
      // 渲染上個月,第一行
      const firstDate = new Date(this.year, this.month - 1, 1)
      const firstWeek = firstDate.getDay()
      let preMonthDay = null
      if (this.month === 1) {
        preMonthDay = this.monthDay[11]
      } else {
        preMonthDay = this.monthDay[this.month - 2]
      }
      console.log("preMonthDay", this.monthDay[11], this.month)

      for (let i = 0; i < preMonthDay; i++) {
        this.previousMonth[i] = i + 1
      }
      if (firstWeek === 0) {
        this.previousMonth = this.previousMonth.slice(-7)
      } else {
        this.previousMonth = this.previousMonth.slice(-firstWeek)
        console.log(33, this.previousMonth)
      }

      // 渲染下個月, 最後一行
      const endDate = new Date(
        this.year,
        this.month - 1,
        this.monthDay[this.month - 1]
      )
      const endWeek = endDate.getDay()
      let nextMonthDay = null
      if (this.month === 12) {
        nextMonthDay = this.monthDay[0]
      } else {
        nextMonthDay = this.monthDay[this.month]
      }
      for (let i = 0; i < nextMonthDay; i++) {
        this.nextMonth[i] = i + 1
      }
      if (endWeek === 6) {
        this.nextMonth = this.nextMonth.slice(0, 7)
      } else {
        this.nextMonth = this.nextMonth.slice(0, 6 - endWeek)
      }
    },
  }

2、綁定四個固定的函數

  • 點擊上一年,下一年,上個月,下個月時,需要計算跨年的情況
    // 年份的增減
    addYear() {
      this.year++
      this.updateLeapYear()
    },
    reduceYear() {
      this.year--
      this.updateLeapYear()
    },
    // 月份的增減
    addMonth() {
      this.month++
      if (this.month > 12) {
        this.month = 1
        this.addYear()
      }
    },
    reduceMonth() {
      this.month--
      if (this.month < 1) {
        this.month = 12
        this.reduceYear()
      }
    },

3、點擊具體日期時,確定狀態

  • 使用數組存起當前已選的日期,使用一個變數記錄當前半選的日期
  • 通過一個函數isActive給每個日期綁定類名,從而在視圖上顯示出來,同時可以確定狀態的切換
    • 如果點擊了已選日期的數據,需要剔除,改為空白狀態
    • 如果點擊了半選態日期,則直接選中當前日期,變為已選日期
    • 如果點擊了空白狀態日期,則可能有兩種情況,一是已存在半選態日期,等待閉合,而是不存在半選態日期,當前設置為半選
methods: {
    // 突出顯示當前日期
    isActive(index) {
      const date = new Date()
      const y = date.getFullYear()
      const m = date.getMonth() + 1
      const d = date.getDate()
      const obj = {}

      if (this.year === y && this.month === m && index === d) {
        obj.today = true
      }
      const newIndexStr = index < 10 ? `0${index}` : `${index}`
      const newMonthStr = this.month < 10 ? `0${this.month}` : `${this.month}`
      const item = `${this.year}/${newMonthStr}/${newIndexStr}`
      if (item === this.partialSelect) {
        obj.active = true
      }
      if (this.selctDate.includes(item)) {
        obj.activeRange = true
      }
      return obj
    },
    selectDay(e, type) {
      const iText = e.target.innerText
      const sDate = Number(iText) < 10 ? `0${iText}` : `${iText}`
      if (type === "previousMonth") {
        if (this.month === 1) {
          this.month = 12
          this.reduceYear()
        } else {
          this.month = this.month - 1
        }
      } else if (type === "nextMonth") {
        if (this.month === 12) {
          this.month = 1
          this.addYear()
        } else {
          this.month = this.month + 1
        }
      }

      let arr = this.selctDate.map((i) => new Date(i).getTime())
      const newMonthStr = this.month < 10 ? `0${this.month}` : `${this.month}`
      const curSelectTime = `${this.year}/${newMonthStr}/${sDate}`
      const curSelectTimeStamp = new Date(curSelectTime).getTime()
      const clsName = e.target.className // 通過類名判斷當前是什麼狀態
      if (clsName.includes("activeRange")) {
        // 點擊了範圍內的數據,需要剔除
        arr = arr.filter((i) => i !== curSelectTimeStamp)
      } else if (clsName.includes("active") && !clsName.includes("activeRange")) {
        // 點擊了一個半選狀態的日期,準備擴展範圍或者單選一個
        if (this.selctDate.length) {
          const itemTime = arr[0]
          const itemTime2 = arr[arr.length - 1]
          const selectTime = curSelectTimeStamp
          if (selectTime < itemTime) {
            console.log("點擊了範圍之前的時間")
          } else if (selectTime > itemTime2) {
            console.log("點擊了範圍之後的時間")
          } else {
            console.log("點擊了範圍內的空白,直接加上一個")
          }
          arr = [...arr, curSelectTimeStamp]
          console.log(arr)
        } else {
          // 第一次選擇日期,而且雙擊了,直接單獨確定這個
          arr = [curSelectTimeStamp]
        }
        // 此時選擇完日前了,半選的日期消費掉了,清空
        this.partialSelect = null
      } else {
        console.log("不是半選情況")

        // 即沒有點擊範圍內,又不是半選狀態,可能是已經存在一個半選,等待這個日期來閉合範圍,也可能是第一次打開點擊
        if (this.partialSelect) {
          // 需要和已存在的半選態日期閉合
          const itemTime = new Date(this.partialSelect).getTime()
          const itemTime2 = curSelectTimeStamp
          const timeArr = [itemTime, itemTime2].sort((a, b) => a - b) // 排序,因為不知道誰在前面
          for (let i = timeArr[0]; i <= timeArr[1]; i += 86400000) {
            arr.push(i)
          }
          // 此時確定好範圍了,半選的日期消費掉了,清空
          this.partialSelect = null
        } else if (this.selctDate.length) {
          // 存在一個範圍,同時點擊範圍外,此時設置半選
          this.day = sDate
          this.partialSelect = curSelectTime
        } else {
          // 不存在一個範圍,所以是第一次點擊
          this.day = sDate
          this.partialSelect = curSelectTime
        }
      }
      let filterArr = Array.from(new Set(arr))
      filterArr = filterArr.sort((a, b) => a - b)
      this.selctDate = filterArr.map((i) => this.formatTime(new Date(i)))
      this.$emit("input", this.selctDate)
      this.$emit("change", this.selctDate)
      this.day = parseInt(sDate)
    },
}

本文轉載於:

https://juejin.cn/post/7240088790423863353

如果對您有所幫助,歡迎您點個關註,我會定時更新技術文檔,大家一起討論學習,一起進步。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ![file](https://img2023.cnblogs.com/other/2685289/202306/2685289-20230616173226789-2009691483.jpg) > 截至今天,Apache DolphinScheduler 項目在 GitHub 上的 Star 數 ...
  • > mysql單表數據量太大 導致查詢緩慢問題如何解決 您好,這是Bing。根據網路搜索結果,mysql單表數據量太大導致查詢緩慢的問題有以下幾種可能的解決方案: - 使用索引。索引是一種數據結構,可以幫助資料庫高效地獲取數據。索引可以根據WHERE和JOIN中出現的列創建,以提高查詢效率。索引的種 ...
  • 摘要:華為全球智慧金融峰會2023上,華為雲資料庫服務產品部總經理蘇光牛帶來了《華為雲分散式資料庫GaussDB,做金融數字化的堅實數據底座》的主題分享。 6月7日,華為全球智慧金融峰會2023在上海順利舉行,華為雲資料庫服務產品部總經理蘇光牛帶來了《華為雲分散式資料庫GaussDB,做金融數字化的 ...
  • 查看資料庫 show databases; 創建資料庫 create database db1; 創建資料庫db1 刪除資料庫 drop database db1; 刪除資料庫db1 切換進入資料庫 use user 進入user資料庫 查看資料庫中的表 show tables; 創建表 創建表的方 ...
  • Hello,社區的小伙伴們,又到了每月版本發佈時間。🎉🎉🎉 本次社區版更新帶來了新功能 **「發佈變更」**,以及**內置脫敏規則、授權粒度細化、連接池管理、變更鏈接密鑰**等,信息量不少,一起來看! ### 發佈變更 大量數據變更的便捷操作 社區版 v2.0.0,我們增加了「數據變更」模塊, ...
  • > 上一篇文章從理論上對Kotlin協程進行了部分說明,本文將在上一篇的基礎上,從實戰出發,繼續協程之旅。 ### 從源頭說起 在Kotlin中,要想使用協程,首先需要使用協程創建器創建,但還有個前提——協程作用域(`CoroutineScope`)。在早期的Kotlin實現中,協程創建器是一等函數 ...
  • > 上一篇文章,我介紹了Kotlin協程的創建,使用,協作等內容。本篇將引入更多的使用場景,繼續帶你走進協程世界。 ### 使用協程處理非同步數據流 常用編程語言都會內置對同一類型不同對象的數據集表示,我們通常稱之為容器類。不同的容器類適用於不同的使用場景。Kotlin的`Flow`就是在非同步計算的需 ...
  • “聊技術無話不談,一起來吹吹元服務!暢聊你對元服務的想法,說不定,你就能撬動元服務的爆發增長!” 元服務(即原子化服務)是華為“輕量化”服務的新物種,可提供全新的服務和交互方式,讓應用化繁為簡,讓服務觸手可及!基於鴻蒙萬能卡片,元服務可實現應用功能在桌面“永遠打開”,實現智能推薦、服務直達! 而在元 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...