?
This document uses PHP Chinese website manual Release
<input>datetime-local
創(chuàng)建輸入字段的元素允許輕松輸入日期和時間 - 這包括年,月,日,小時和分鐘。
控件的用戶界面從瀏覽器到瀏覽器有所不同,目前的支持是不完整的,只有桌面上的Chrome / Opera和Edge以及大多數(shù)現(xiàn)代的移動瀏覽器版本具有可用的實現(xiàn)。在其他瀏覽器中,控件會優(yōu)雅地降到簡單<input type="text">
。
<input id="datetime" type="datetime-local">
對于那些不使用支持瀏覽器的用戶,Chrome / Opera datetime-local
控件看起來像下面的屏幕截圖。點擊右側(cè)的向下箭頭會彈出一個日期選擇器,讓您選擇一個日期; 你必須手動輸入時間。
邊緣日期時間-本地控件看起來是這樣的但是, 單擊該值的日期和時間部分將為您提供兩個單獨的選取器, 以便您進行選擇:
值 | 表示日期和時間的DOMString,或者為空。 |
---|---|
活動 | 改變和輸入。 |
支持的通用屬性 | 自動完成,列表,只讀和步驟。 |
IDL屬性 | 列表,值,值asAsumber。 |
方法 | select(),stepDown(),stepUp()。 |
A DOMString
表示輸入到輸入中的日期的值。您可以通過在value
屬性中包含日期來為輸入設(shè)置默認值,如下所示:
<label for="party">Enter a date and time for your party booking:</label><input id="party" type="datetime-local" name="partydate" value="2017-06-01T08:30">
有一件事要注意的是,顯示的日期格式與實際不同value
- 顯示的日期格式將根據(jù)用戶操作系統(tǒng)的設(shè)置區(qū)域選擇,而日期value
總是格式化的yyyy-MM-ddThh:mm
。例如,當(dāng)將上面的值提交給服務(wù)器時,它將看起來像partydate=2017-06-01T08:30
。
注意:請記住,如果這樣的數(shù)據(jù)是通過HTTP提交的GET
,冒號字符將需要轉(zhuǎn)義以包含在URL參數(shù)中,例如partydate=2017-06-01T08%3A30
。
您還可以使用該HTMLInputElement.value
屬性在JavaScript中獲取和設(shè)置日期值,例如:
var dateControl = document.querySelector('input[type="datetime-local"]');dateControl.value = '2017-06-01T08:30';
日期/時間輸入聽起來很方便乍一看 - 他們提供了一個簡單的用戶界面來選擇日期和時間,他們規(guī)范化的數(shù)據(jù)格式發(fā)送到服務(wù)器,無論用戶的地區(qū)。但是,<input type="datetime-local">
由于瀏覽器支持有限,因此存在問題。
我們將考慮基本的和更復(fù)雜的用途<input type="datetime-local">
,然后就減輕瀏覽器支持問題提供建議(請參閱處理瀏覽器支持)。
最簡單的使用<input type="datetime-local">
涉及基本<input>
和<label>
元素組合,如下所示:
<form> <label for="party">Enter a date and time for your party booking:</label> <input id="party" type="datetime-local" name="partydate"></form>
您可以使用min
和max
屬性來限制用戶可以選擇的日期/時間。在下面的例子中,我們設(shè)置最小日期時間2017-06-01T08:30
和最大日期時間為2017-06-30T16:30
:
<form> <label for="party">Enter a date and time for your party booking:</label> <input id="party" type="datetime-local" name="partydate" min="2017-06-01T08:30" max="2017-06-30T16:30"> </form>
其結(jié)果是:
只能選擇2017年6月的日期 - 只有日期值的“天”部分可以編輯,6月以外的日期不能滾動到日期選擇器窗口小部件中。
根據(jù)您使用的瀏覽器,您可能會發(fā)現(xiàn)超出指定值的時間可能無法在時間選擇器(如邊緣)中選擇,或者無效(請參閱驗證),但仍可用(例如Chrome)。
注意:您應(yīng)該能夠使用該step
屬性來改變每次增加日期時跳過的天數(shù)(例如,也許您只希望使周六可選)。但是,在編寫本文的任何實施過程中,這似乎并不奏效。
<input type="datetime-local">
不支持表單大小屬性,如size
。你將不得不求助于CSS的大小需求。
一件事的datetime-local
輸入型不提供用于設(shè)置日期時間的時區(qū)/區(qū)域設(shè)置的方式。這在datetime
輸入類型中是可用的,但是這種類型現(xiàn)在已經(jīng)過時了,已經(jīng)從規(guī)范中刪除了。這個被刪除的主要原因是缺少瀏覽器的實現(xiàn),以及對用戶界面/體驗的關(guān)注。只需要一個控件(或控件)來設(shè)置日期/時間,然后在一個單獨的控件中處理語言環(huán)境就比較容易。
例如,如果您正在創(chuàng)建一個用戶可能已經(jīng)登錄的系統(tǒng),并且已經(jīng)設(shè)置了其語言環(huán)境,則可以使用hidden
輸入類型提供時區(qū)。例如:
<input type="hidden" id="timezone" name="timezone" value="-08:00">
另一方面,如果您需要允許用戶輸入時區(qū)以及日期時間條目,則可以提供輸入時區(qū)的方法,如<select>
元素:
<select name="timezone_offset" id="timezone-offset" class="span5"> <option value="-12:00">(GMT -12:00) Eniwetok, Kwajalein</option> <option value="-11:00">(GMT -11:00) Midway Island, Samoa</option> <option value="-10:00">(GMT -10:00) Hawaii</option> <option value="-09:50">(GMT -9:30) Taiohae</option> <option value="-09:00">(GMT -9:00) Alaska</option> <option value="-08:00">(GMT -8:00) Pacific Time (US & Canada)</option> ... </select>
在這兩種情況下,timedate和timezone值將作為單獨的數(shù)據(jù)點提交給服務(wù)器,然后您需要將它們適當(dāng)?shù)卮鎯υ诜?wù)器端的數(shù)據(jù)庫中。
注意:上面的代碼片段取自HTML選擇元素中的所有世界時區(qū)。
默認情況下,<input type="datetime-local">
不對輸入的值應(yīng)用任何驗證。UI實現(xiàn)通常不會讓你輸入任何不是日期時間的東西 - 這是有幫助的 - 但是你仍然可以不填寫任何值并提交,或者輸入無效的日期時間(例如4月32日)。
您可以使用min
并max
限制可用的日期(請參閱anch(“設(shè)置最大值和最小值日期”)),并使用該required
屬性在日期中強制填入。因此,如果您嘗試提交超出設(shè)定范圍的日期或空的日期字段,支持的瀏覽器將顯示錯誤。
我們來看一個例子 - 在這里我們設(shè)置了最小和最大的日期時間,并且還要求這個字段:
<form> <div> <label for="party">Choose your preferred party date and time (required, June 1st 8.30am to June 30th 4.30pm):</label> <input id="party" type="datetime-local" name="partydate" min="2017-06-01T08:30" max="2017-06-30T16:30" required> <span class="validity"></span> </div> <div> <input type="submit" value="Book party!"> </div></form>
如果您嘗試使用不完整的日期提交表單(或使用設(shè)定范圍外的日期),則瀏覽器顯示錯誤。現(xiàn)在嘗試玩這個例子:
這里是不使用支持瀏覽器的人的截圖:
這是上面例子中使用的CSS。這里我們利用:valid
和:invalid
CSS屬性來根據(jù)當(dāng)前值是否有效來設(shè)置輸入的樣式。我們必須將圖標(biāo)放在<span>
輸入旁邊,而不是輸入本身,因為在Chrome中生成的內(nèi)容放置在表單控件中,無法有效地進行樣式化或顯示。
div { margin-bottom: 10px; display: flex; align-items: center;}label { display: inline-block; width: 300px;}input:invalid+span:after { content: '?'; padding-left: 5px;}input:valid+span:after { content: '?'; padding-left: 5px;}
重要提示:HTML表單驗證是不是腳本,確保輸入的數(shù)據(jù)是正確的格式的替代品。有人很容易調(diào)整HTML,使他們繞過驗證,或完全刪除它。也有人可能完全繞過你的HTML,直接提交數(shù)據(jù)到你的服務(wù)器。如果您的服務(wù)器端代碼無法驗證接收到的數(shù)據(jù),當(dāng)格式不正確的數(shù)據(jù)被提交(或數(shù)據(jù)太大,類型錯誤等等)時,可能會發(fā)生災(zāi)難。
如上所述,在編寫本文時使用日期輸入的主要問題是瀏覽器支持 - 只有Chrome / Opera和Edge支持它在桌面上,以及大多數(shù)現(xiàn)代瀏覽器在手機上。作為一個例子,datetime-local
Android版Firefox 的選擇器如下所示:
非支持的瀏覽器會降級為文本輸入, 但這會在用戶界面的一致性 (所呈現(xiàn)的控件不同) 和數(shù)據(jù)處理方面產(chǎn)生問題。
第二個問題是最嚴重的 - 就像我們之前提到的那樣,datetime-local
輸入的實際值總是被格式化yyyy-mm-ddThh:mm
。另一方面,通過文本輸入,瀏覽器默認不知道日期的格式,有很多不同的方式來寫日期和時間,例如:
ddmmyyyy
dd/mm/yyyy
mm/dd/yyyy
dd-mm-yyyy
mm-dd-yyyy
mm-dd-yyyy hh:mm
(12 hour clock)
mm-dd-yyyy hh:mm
(24 hour clock)
etc.
One way around this is to put a pattern
attribute on your datetime-local
input. Even though the datetime-local
input doesn't use it, the text input fallback will. For example, try viewing the following demo in a non-supporting browser:
<form> <div> <label for="party">Choose your preferred party date and time (required, June 1st 8.30am to June 30th 4.30pm):</label> <input id="party" type="datetime-local" name="partydate" min="2017-06-01T08:30" max="2017-06-30T16:30" pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}" required> <span class="validity"></span> </div> <div> <input type="submit" value="Book party!"> </div> <input type="hidden" id="timezone" name="timezone" value="-08:00"></form>
如果你嘗試提交它,你會看到,現(xiàn)在瀏覽器顯示錯誤信息(并突出了輸入為無效)如果您的條目不匹配的模式nnnn-nn-nnTnn:nn
,在那里n
是一個數(shù)字從0到9。當(dāng)然,這并未不要阻止人們輸入無效日期,或者錯誤地格式化日期和時間。
用戶將要了解他們需要輸入時間和日期的模式?
我們?nèi)匀挥幸粋€問題。
目前以跨瀏覽器的方式處理表單中日期的最好方法是讓用戶在單獨的控件中輸入日期,月份,年份和時間(<select>
元素正在流行 - 請參閱下面的實現(xiàn)),或者使用JavaScript庫,如jQuery日期選擇器,和jQuery timepicker插件。
在這個例子中,我們創(chuàng)建了兩組用于選擇日期時間的UI元素 - 一個本機<input type="datetime-local">
選取器,以及一組五個<select>
元素,用于在舊版瀏覽器中選擇不支持本機輸入的日期和時間。
HTML看起來像這樣:
<form> <div class="nativeDateTimePicker"> <label for="party">Choose a date and time for your party:</label> <input type="datetime-local" id="party" name="bday"> <span class="validity"></span> </div> <p class="fallbackLabel">Choose a date and time for your party:</p> <div class="fallbackDateTimePicker"> <div> <span> <label for="day">Day:</label> <select id="day" name="day"> </select> </span> <span> <label for="month">Month:</label> <select id="month" name="month"> <option selected>January</option> <option>February</option> <option>March</option> <option>April</option> <option>May</option> <option>June</option> <option>July</option> <option>August</option> <option>September</option> <option>October</option> <option>November</option> <option>December</option> </select> </span> <span> <label for="year">Year:</label> <select id="year" name="year"> </select> </span> </div> <div> <span> <label for="hour">Hour:</label> <select id="hour" name="hour"> </select> </span> <span> <label for="minute">Minute:</label> <select id="minute" name="minute"> </select> </span> </div> </div></form>
月份是硬編碼的(因為它們總是相同的),而日和年的值是根據(jù)當(dāng)前選擇的月份和年份以及當(dāng)年分別動態(tài)生成的(請參閱下面的代碼注釋,了解這些函數(shù)的詳細解釋)。我們也決定動態(tài)地生成小時和月份,因為有這么多!
該代碼可能會感興趣的另一部分是特征檢測碼-來檢測瀏覽器是否支持<input type="date">
,我們創(chuàng)建了一個新的<input>
元素,設(shè)置其type
到date
,然后立即檢查什么的類型設(shè)置為-不支持的瀏覽器將返回text
,因為這個date
類型會回到類型text
。如果<input type="date">
不支持,我們隱藏本地選擇器并顯示后備選取器UI(<select>
)。
// define variablesvar nativePicker = document.querySelector('.nativeDateTimePicker');var fallbackPicker = document.querySelector('.fallbackDateTimePicker');var fallbackLabel = document.querySelector('.fallbackLabel');var yearSelect = document.querySelector('#year');var monthSelect = document.querySelector('#month');var daySelect = document.querySelector('#day');var hourSelect = document.querySelector('#hour');var minuteSelect = document.querySelector('#minute');// hide fallback initiallyfallbackPicker.style.display = 'none';fallbackLabel.style.display = 'none';// test whether a new date input falls back to a text input or notvar test = document.createElement('input');test.type = 'date';// if it does, run the code inside the if() {} blockif(test.type === 'text') { // hide the native picker and show the fallback nativePicker.style.display = 'none'; fallbackPicker.style.display = 'block'; fallbackLabel.style.display = 'block'; // populate the days and years dynamically // (the months are always the same, therefore hardcoded) populateDays(monthSelect.value); populateYears(); populateHours(); populateMinutes();}function populateDays(month) { // delete the current set of <option> elements out of the // day <select>, ready for the next set to be injected while(daySelect.firstChild){ daySelect.removeChild(daySelect.firstChild); } // Create variable to hold new number of days to inject var dayNum; // 31 or 30 days? if(month === 'January' | month === 'March' | month === 'May' | month === 'July' | month === 'August' | month === 'October' | month === 'December') { dayNum = 31; } else if(month === 'April' | month === 'June' | month === 'September' | month === 'November') { dayNum = 30; } else { // If month is February, calculate whether it is a leap year or not var year = yearSelect.value; (year - 2016) % 4 === 0 ? dayNum = 29 : dayNum = 28; } // inject the right number of new <option> elements into the day <select> for(i = 1; i <= dayNum; i++) { var option = document.createElement('option'); option.textContent = i; daySelect.appendChild(option); } // if previous day has already been set, set daySelect's value // to that day, to avoid the day jumping back to 1 when you // change the year if(previousDay) { daySelect.value = previousDay; // If the previous day was set to a high number, say 31, and then // you chose a month with less total days in it (e.g. February), // this part of the code ensures that the highest day available // is selected, rather than showing a blank daySelect if(daySelect.value === "") { daySelect.value = previousDay - 1; } if(daySelect.value === "") { daySelect.value = previousDay - 2; } if(daySelect.value === "") { daySelect.value = previousDay - 3; } }}function populateYears() { // get this year as a number var date = new Date(); var year = date.getFullYear(); // Make this year, and the 100 years before it available in the year <select> for(var i = 0; i <= 100; i++) { var option = document.createElement('option'); option.textContent = year-i; yearSelect.appendChild(option); }}function populateHours() { // populate the hours <select> with the 24 hours of the day for(var i = 0; i <= 23; i++) { var option = document.createElement('option'); option.textContent = (i < 10) ? ("0" + i) : i; hourSelect.appendChild(option); }}function populateMinutes() { // populate the minutes <select> with the 60 hours of each minute for(var i = 0; i <= 59; i++) { var option = document.createElement('option'); option.textContent = (i < 10) ? ("0" + i) : i; minuteSelect.appendChild(option); }}// when the month or year <select> values are changed, rerun populateDays()// in case the change affected the number of available daysyearSelect.onchange = function() { populateDays(monthSelect.value);}monthSelect.onchange = function() { populateDays(monthSelect.value);}//preserve day selectionvar previousDay;// update what day has been set to previously// see end of populateDays() for usagedaySelect.onchange = function() { previousDay = daySelect.value;}
Specification | Status | Comments |
---|---|---|
HTML Living StandardThe definition of '<input type="datetime-local">' in that specification. | Living Standard | |
HTML5The definition of '<input type="datetime-local">' in that specification. | Recommendation |
Feature | Chrome | Edge | Firefox (Gecko) | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|---|
Basic support | 20 | 12 | No support1 | No support | 10.62 | No support2 |
Feature | Android | Chrome for Android | Edge | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile |
---|---|---|---|---|---|---|---|
Basic support | (Yes) | (Yes) | (Yes) | (Yes) | ? | (Yes) | (Yes) |