在 Vue 中設定 input date 輸入的日期範圍

更新於 發佈於 閱讀時間約 10 分鐘

問題描述

  在設計輸入日期的表單時,有時我們會需要限定時間範圍。

  像是常見的網銀帳戶記錄,很多就有類似從今天開始前的一年內為查詢範圍的限制,有時候就算在說明文字中已說明資料範圍僅有一年內的資料,還是有可能會有用戶去選到超過一年內的日期。

  這種時候直接禁止選取超過一年內的日期,可以避免使用者不小心進行錯誤的操作。


實作案例

  要設定 <input type=”date”> 的範圍其實用原生的 JS 就能做到,只需要增加 max 或 min 的屬性即可:

<html>
<head>
<title>Date Range Example</title>
</head>
<body>
<input type="date" id="dateInput">

<script>
// 獲取今日日期
const today = new Date();
// 設定最大值為今日
const maxDate = today.toISOString().split("T")[0];
// 設定最小值為一年前
today.setFullYear(today.getFullYear() - 1);
const minDate = today.toISOString().split("T")[0];

// 設置 input 的最小值和最大值
document.getElementById('dateInput').max = maxDate;
document.getElementById('dateInput').min = minDate;
</script>
</body>
</html>


  而在 Vue 中就可以這樣寫:

<template>
<input type="date" :max="maxDate" :min="minDate">
</template>

<script setup>
import { ref, onMounted } from 'vue';

const today = new Date;
const maxDate = ref('');
const minDate = ref('');

function setDateRange() {
maxDate.value = today.toISOString().split("T")[0];
today.setFullYear(today.getFullYear() - 1);
minDate.value = today.toISOString().split("T")[0];
}

onMounted(() => {
setDateRange();
})


</script>


語法解䆁

input date 屬性:max 與 min

  max 與 min 都是 <input type=”date”> 本身就擁有的屬性,從 MDN 中的說明可以看到,設定的時候需符合 yyyy-mm-dd 這樣的日期格式。因此如果有一個已知的固定時間,也是可以直接把 max 或 min 的值寫死。


new Date():動態取得今日日期

  因為在這個案例中,要取得的日期範圍是「從今日開始到一年前」這個動態的區間,因此可以用new Date() 這個方法來取得現在日期和時間的 Date 物件。

  console.log() 之後看到的內容會是:Tue Oct 22 2024 00:00:00 GMT+0800 (台北標準時間) 這樣的格式,而我們需要讓它轉成 2024-10-22 才能被我們的 max 給接受,因此需要進行下一步:


.toISOString():把日期格式轉成 YYYY-MM-DDTHH:mm:ss.sssZ

  toISOString() 是 Date 物件的一個內建方法,他會返回一個 ISO 8601(國際標準化組織的日期和時間的表示方法) 格式的字符串,但要注意一個問題是它返回的值會是 UTC 時區的值,也就是以台灣 UTC+8 來說,它的 HH 會比我們使用當下要少 8 小時,假設我們使用的時間在早上八點以前,那麼得到的 max 日期就不會是當天,而是前一天。

  如果想避免這個情況發生,也可以用函式手動將 Date 物件進行格式化,格式化的函式放到最後再來說明。


.split(“T”)[0]:提取 YYYY-MM-DD

  前面已經透過 .toISOString() 把 Date 物件轉成 YYYY-MM-DDTHH:mm:ss.sssZ 格式了,但我們需要的部份其實只有 YYYY-MM-DD 這部份而已,因此用字串內建的方法 split(),以T這個字為切割點,把整個字串切成了陣列:[ ‘YYYY-MM-DD‘, ‘HH:mm:ss.sssZ‘ ],而其中第 0 項的 ‘YYYY-MM-DD’ 就是我們需要的部份。

  其實用另一個字串的內建方法 slice() 也能達到一樣的效果,因為 YYYY-MM-DDTHH:mm:ss.sssZ 的格式是固定的,我們需要的 YYYY-MM-DD 區塊必定是字串的前十個字,因此用 .slice(0,10) 也可以獲得我們需要的部份,寫法會像這樣:

function setDateRange() {
maxDate.value = today.toISOString().slice(0,10);
today.setFullYear(today.getFullYear() - 1);
minDate.value = today.toISOString().slice(0,10);
}


如何手動格式化 Date 物件

  為了避免時差導致日期錯誤,我們可以設計一個函式來將 Date 物件手動格式化成 YYYY-MM-DD 的格式,具體寫法如下:

const today = new Date()

function formatDate(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}

formatDate(today);


  這個函式的思路很簡單,就是分別把日期物件的年、月、日提取出來之後,再重新組合成我們要的格式。其中值得注意的部份有兩點:

  1. 用 getMonth() 得到的值是 monthIndex,因此要再 +1 才會是正確的月份。
  2. 用 getFullYear()、getMonth()、getDate() 取得的值都是數字,如果月或日是個位數的話需要補零,為了補零就需要先把數字轉成字串。轉成字串之後再用 padStart() 來確保字符串至少有兩個字符,若不足兩個字符的時候就在前面補零。


  套用到案例中的話,就會是這樣:

<template>
<input type="date" :max="maxDate" :min="minDate">
</template>

<script setup>
import { ref, onMounted } from 'vue';

const today = new Date;
const maxDate = ref('');
const minDate = ref('');

function setDateRange() {
maxDate.value = formatDate(today);
today.setFullYear(today.getFullYear() - 1);
minDate.value = formatDate(today);
}

function formatDate(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}

onMounted(() => {
setDateRange();
})


</script>


參考資料

MDN - <input type=”date”>

MDN - Date

JavaScript 之旅 (5):String method - padStart & padEnd

AI 工具 - Microsoft Copilot



留言
avatar-img
留言分享你的想法!
avatar-img
佧佧的術式領域
4會員
15內容數
我是佧佧,歡迎來到我的術式領域。 讓我們一起磨練技術、學習程式, 在前端的領域中不斷成長吧!
佧佧的術式領域的其他內容
2024/10/27
  在寫程式的時候,我們常會需要針對不同情況來執行不同的工作。這個時候就會用到條件判斷式 ( if statement )
2024/10/27
  在寫程式的時候,我們常會需要針對不同情況來執行不同的工作。這個時候就會用到條件判斷式 ( if statement )
2024/10/26
  在 RWD 設計當中,很常見到某些區塊在大螢幕上要顯示多欄、在小螢幕上要顯示單欄。用 Bootstrap 的排版(格線系統)可以設定不同裝置要呈現的大小及欄位。但若不依靠 Bootstrap 來做,而是自己撰寫 CSS 的話,或許可以試著用設定最大或最小寬度來完成自適應。
2024/10/26
  在 RWD 設計當中,很常見到某些區塊在大螢幕上要顯示多欄、在小螢幕上要顯示單欄。用 Bootstrap 的排版(格線系統)可以設定不同裝置要呈現的大小及欄位。但若不依靠 Bootstrap 來做,而是自己撰寫 CSS 的話,或許可以試著用設定最大或最小寬度來完成自適應。
2024/10/24
  先前在開發的專案中,需要一個上傳圖片後可以看即時看到預覽的功能。再加上這個功能在許多地方都會用到,因此試著製作了一個可以獨立運行的組件。
2024/10/24
  先前在開發的專案中,需要一個上傳圖片後可以看即時看到預覽的功能。再加上這個功能在許多地方都會用到,因此試著製作了一個可以獨立運行的組件。
看更多
你可能也想看
Thumbnail
家中修繕或裝潢想要找各種小零件時,直接上網採買可以省去不少煩惱~看看Sylvia這回為了工地買了些什麼吧~
Thumbnail
家中修繕或裝潢想要找各種小零件時,直接上網採買可以省去不少煩惱~看看Sylvia這回為了工地買了些什麼吧~
Thumbnail
👜簡單生活,從整理包包開始!我的三款愛用包+隨身小物清單開箱,一起來看看我每天都帶些什麼吧🌿✨
Thumbnail
👜簡單生活,從整理包包開始!我的三款愛用包+隨身小物清單開箱,一起來看看我每天都帶些什麼吧🌿✨
Thumbnail
創作者營運專員/經理(Operations Specialist/Manager)將負責對平台成長及收入至關重要的 Partnership 夥伴創作者開發及營運。你將發揮對知識與內容變現、影響力變現的精準判斷力,找到你心中的潛力新星或有聲量的中大型創作者加入 vocus。
Thumbnail
創作者營運專員/經理(Operations Specialist/Manager)將負責對平台成長及收入至關重要的 Partnership 夥伴創作者開發及營運。你將發揮對知識與內容變現、影響力變現的精準判斷力,找到你心中的潛力新星或有聲量的中大型創作者加入 vocus。
Thumbnail
Vue 的 scoped 樣式無法完全隔離全局樣式,需要採取其他策略如 BEM 命名規則或 CSS Modules 來避免衝突。未來可能也會遇到 JavaScript 衝突,因此需遵循嚴格的命名和範圍控制。
Thumbnail
Vue 的 scoped 樣式無法完全隔離全局樣式,需要採取其他策略如 BEM 命名規則或 CSS Modules 來避免衝突。未來可能也會遇到 JavaScript 衝突,因此需遵循嚴格的命名和範圍控制。
Thumbnail
資料處理中日期格式是一定會遇到的一個課題,而在台灣日期又有民國年與西元年,很不幸的在EXCEL上,日期有它自己的標準設定模式,YYYY/MM/DD,如果不是依照這種格式進行輸入,那個日期就是僅供觀看不能進行任何計算。 延伸閱讀:EXCEL日期正確的輸入方式,與常見錯誤之日期格式輸入 而不盡少數的
Thumbnail
資料處理中日期格式是一定會遇到的一個課題,而在台灣日期又有民國年與西元年,很不幸的在EXCEL上,日期有它自己的標準設定模式,YYYY/MM/DD,如果不是依照這種格式進行輸入,那個日期就是僅供觀看不能進行任何計算。 延伸閱讀:EXCEL日期正確的輸入方式,與常見錯誤之日期格式輸入 而不盡少數的
Thumbnail
情境 M小姐有一份報表,報表上使用了「交叉分析篩選器」,可以方便分享給其他人進行查詢,但是又害怕別人變動了資料內容,於是她想到,可以把工作表進行「保護」,但.....沒想到工作表一保護,要讓大家使用的「交叉分析篩選器」卻無法使用了,這該怎麼辦呢?
Thumbnail
情境 M小姐有一份報表,報表上使用了「交叉分析篩選器」,可以方便分享給其他人進行查詢,但是又害怕別人變動了資料內容,於是她想到,可以把工作表進行「保護」,但.....沒想到工作表一保護,要讓大家使用的「交叉分析篩選器」卻無法使用了,這該怎麼辦呢?
Thumbnail
自學筆記 - Vue3 watch 的應用
Thumbnail
自學筆記 - Vue3 watch 的應用
Thumbnail
UNIX 在設計時,用 32 位元為基礎設計,Timestamp (time_t 結構) 順理成章也是 32 位元 (signed int32),從 1970 年開始算,導致它能記錄的時間在 2038 年會溢位變負數。
Thumbnail
UNIX 在設計時,用 32 位元為基礎設計,Timestamp (time_t 結構) 順理成章也是 32 位元 (signed int32),從 1970 年開始算,導致它能記錄的時間在 2038 年會溢位變負數。
Thumbnail
翻開買了就再也沒碰過的excel書籍,這本書應該是2017年前後買的書籍。事實上我不太喜歡研究excel,我的工作需要的函數其實也沒有這麼多。今天打開後,發現,廢話也是不少。但我覺得這就是工具書必須要存在的廢話地方,長篇大論描述一個簡單的事情。但今天發現了幾個以前沒有注意到的小細節。像是:
Thumbnail
翻開買了就再也沒碰過的excel書籍,這本書應該是2017年前後買的書籍。事實上我不太喜歡研究excel,我的工作需要的函數其實也沒有這麼多。今天打開後,發現,廢話也是不少。但我覺得這就是工具書必須要存在的廢話地方,長篇大論描述一個簡單的事情。但今天發現了幾個以前沒有注意到的小細節。像是:
Thumbnail
什麼,IMPORTRANGE 的進階應用還有第二招!來看看 IMPORTRANGE 可以怎麼跟 QUERY 結合,進一步篩選即時匯入的資料。
Thumbnail
什麼,IMPORTRANGE 的進階應用還有第二招!來看看 IMPORTRANGE 可以怎麼跟 QUERY 結合,進一步篩選即時匯入的資料。
Thumbnail
不知不覺寫到第七篇了!QUERY 真的有好多好多東西可以說 (ノ>ω<)ノ QUERY 其實還能處理有日期、時間的資料,而且語法也相當容易,和我們之前就看過的聚集函式很像。你如果會了之前的聚集函式,相信這次處理日期和時間也會對你來說很簡單!
Thumbnail
不知不覺寫到第七篇了!QUERY 真的有好多好多東西可以說 (ノ>ω<)ノ QUERY 其實還能處理有日期、時間的資料,而且語法也相當容易,和我們之前就看過的聚集函式很像。你如果會了之前的聚集函式,相信這次處理日期和時間也會對你來說很簡單!
Thumbnail
說好的萬年曆,只有200年          接下來想挑戰萬年曆,於是上網找找有關閏年的資料,不找還好找出很多不知道的事。一開始,想說阿不就 4 年閏一次,好像...什麼 100 的倍數又不是,然後 400 的倍數又是閏年,接著發現 1582 年前根本不是這麼一回事, 1582 年又消失了很多天,好
Thumbnail
說好的萬年曆,只有200年          接下來想挑戰萬年曆,於是上網找找有關閏年的資料,不找還好找出很多不知道的事。一開始,想說阿不就 4 年閏一次,好像...什麼 100 的倍數又不是,然後 400 的倍數又是閏年,接著發現 1582 年前根本不是這麼一回事, 1582 年又消失了很多天,好
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News