圖1-外輸入框
圖2-內輸入框
圖3
? ? ?
問題描述:
? ? ? ? 這兩天在迭代功能的時候,基本上碰到的問題都是出自這個“時間日期選擇框”,昨天的bug38也是解決這個組件。如上圖1和2所示,可以把圖1中的輸入框叫外輸入框,圖2中的輸入框叫內輸入框,el-date-picker組件在官網上其實是有一個屬性叫“editable”,可以禁止用戶在文本框輸入,但是很遺憾這個只能在外輸入框生效,內輸入框還是能編輯。由于業務上對日期有一些限制,因此不能選擇任意日期,如果在內輸入框手動輸入日期,就限制不了日期范圍,因此還是考慮禁用。
以前其實碰到測試在外輸入框輸入日期的情況,然后使用editable屬性可以規避用戶輸入,其實也不是不想讓用戶輸入,只是有兩個方面考慮:(1)效率不高,很少有人去手動輸入(2)同時輸入的格式不正確,導致不能轉換成前后端約定的格式,然后查詢報錯,因此直接使用editable禁用外輸入框。其實對于所有只有外框的el-date-picker組件已經可以說是規避解決了這個問題。但是對于type="datetimerange"的這種類型比較特殊的時間日期范圍搜索框來說就不行,因為它有“內輸入框”。其實還是很建議官方單獨給datetimerange類型的搜索框加個屬性,就是把內框也禁用掉,這樣就能讓我們這些牛馬輕松點了。所以,這次的問題就是:我希望禁用掉內輸入框輸入。
方案:
? ? ? ? 還是跟上次一樣有問題先請教cursor的意見。這次的cursor沒有幫我“一步到位”的解決問題,盡管它“天花亂墜”的說了很多,而且引導了它幾次都還是沒有成功,我就知道那接下來只能靠我自己了。不過它還是為我提供了思路:那就是通過給內輸入框添加“readonly”屬性的方式實現禁用。
? ? ? ? 說到底,內輸入框本質上也是個input,只要給它添加readonly或者把它disabled就可以達到我們的要求了。在沒有相關的屬性或者API能完成任務的時候,通過在合適的時機,使用原始的js插入屬性的方式。
????????添加?@focus="timeEditable"方法,當用戶點擊外框然后顯示了日期面板的時候,使用nextTick確保此時內輸入框渲染完畢之后,再利用js定位到內輸入框的元素位置,然后給所有的input追加一個readonly屬性即可實現禁止輸入的效果。
<el-date-pickerv-else-if="item.type === 'DATEPICKER'":key="item?.dateType + (item?.valueFormat || '')"v-model="form[item.key]":type="item.dateType ?? 'daterange'":style="{ width: item.dateType ? '400px' : '300px' }"start-placeholder="開始日期"end-placeholder="結束日期"range-separator="至":clearable="!!item.clearable":editable="false":disabled-date="(time: Date) => item.dynamicDisabled ? handleDymicDisabled(time, item) : false":value-format="item.valueFormat ?? 'YYYY-MM-DD'":format="item.valueFormat ?? 'YYYY-MM-DD'"@focus="timeEditable"@calendar-change="handleCalendarChange"/>
//點擊日期范圍外面搜索框
function timeEditable(e: Event) {console.log('timeEditable', e)// 禁用時間日期范圍組件里面的日期input輸入框nextTick(() => {let els = document.querySelectorAll('.el-date-range-picker__time-picker-wrap input')console.log('els', els)for (var i = 0; i <= els.length - 1; i++) {els[i].setAttribute('readonly', 'readonly')}})}
然后發現第一個日期輸入框是可以禁止編輯了,但是第二個日期輸入框并沒有被禁止編輯,就是見了鬼了。加了打印,找到控制臺的元素,反復推敲發現了原因。當用戶在面板上選擇日期的時候,是需要點擊兩次來確定“開始日期”和“結束日期”的,當點擊選擇第一個日期之后,第二個日期輸入框視圖是會被觸發重新掛載更新了,導致之前加的readonly丟失,需要再加一遍。因此:
function handleCalendarChange(date: Date[]) {console.log('handleCalendarChange', date)// 禁用時間日期范圍組件里面的日期input輸入框nextTick(() => {let els = document.querySelectorAll('.el-date-range-picker__time-picker-wrap input')console.log('els', els)for (var i = 0; i <= els.length - 1; i++) {els[i].setAttribute('readonly', 'readonly')}})}
? ? ? ? 在@calendar-change="handleCalendarChange"方法中是觸發選擇面板的日期的事件方法,在這里再找到所有input,再全部添加一次readonly即可,測試了一下確實驗證了我的猜想。至此,終于實現了內輸入框的禁用。補充一下,內輸入框的時間選擇框不受影響,它還是可以選擇的。