From b9898886dc9b53ab05dae512e0504f3ef49f483d Mon Sep 17 00:00:00 2001 From: Uyarn Date: Tue, 6 Sep 2022 14:19:54 +0800 Subject: [PATCH] fix(timepicker): boundary scroll --- src/time-picker/panel/single-panel.tsx | 60 ++++++++++++++++++-------- 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/src/time-picker/panel/single-panel.tsx b/src/time-picker/panel/single-panel.tsx index b32570d286..aecfaafa2d 100644 --- a/src/time-picker/panel/single-panel.tsx +++ b/src/time-picker/panel/single-panel.tsx @@ -21,6 +21,11 @@ dayjs.extend(customParseFormat); const timeArr = [EPickerCols.hour, EPickerCols.minute, EPickerCols.second, EPickerCols.milliSecond]; +const panelOffset = { + top: 15, + bottom: 21, +}; + export default defineComponent({ name: 'TTimePickerPanelCol', props: { @@ -95,8 +100,16 @@ export default defineComponent({ // 获取每个时间的高度 const getItemHeight = () => { const maskDom = maskRef.value?.querySelector('div'); - const timeItemTotalHeight = maskDom.offsetHeight + parseInt(getComputedStyle(maskDom).marginTop, 10); - return timeItemTotalHeight; + if (!maskDom) { + return { + offsetHeight: 0, + margin: 0, + }; + } + return { + offsetHeight: maskDom.offsetHeight, + margin: parseInt(getComputedStyle(maskDom).marginTop, 10), + }; }; const timeItemCanUsed = (col: EPickerCols, el: string | number) => { @@ -152,8 +165,9 @@ export default defineComponent({ (time as number) %= 12; // 一定是数字,直接cast const itemIdx = getColList(col).indexOf(padStart(String(time), 2, '0')); - const timeItemTotalHeight = getItemHeight(); - const distance = Math.abs(itemIdx * timeItemTotalHeight + timeItemTotalHeight / 2); + const { offsetHeight, margin } = getItemHeight(); + const timeItemTotalHeight = offsetHeight + margin; + const distance = Math.abs(Math.max(0, itemIdx) * timeItemTotalHeight); return distance; }; @@ -161,8 +175,10 @@ export default defineComponent({ let val: number | string; let formattedVal: string; const scrollTop = colsRef[idx]?.scrollTop; + const { offsetHeight, margin } = getItemHeight(); + const timeItemTotalHeight = offsetHeight + margin; + let colStep = Math.abs(Math.round(scrollTop / timeItemTotalHeight + 0.5)); - let colStep = Math.abs(Math.round(scrollTop / getItemHeight() + 0.5)); const meridiem = MERIDIEM_LIST[Math.min(colStep - 1, 1)].toLowerCase(); // 处理PM、AM与am、pm if (Number.isNaN(colStep)) colStep = 1; @@ -189,23 +205,27 @@ export default defineComponent({ else val = meridiem; const distance = getScrollDistance(col, val); - if (!dayjs(dayjsValue.value).isValid()) return; - if (distance !== scrollTop) { - if (timeArr.includes(col)) { - if (timeItemCanUsed(col, val)) formattedVal = dayjsValue.value[col]?.(val).format(format.value); + if (!dayjs(dayjsValue.value).isValid() || (value.value && !dayjs(value.value, format.value, true).isValid())) + return; + + if (timeArr.includes(col)) { + if (timeItemCanUsed(col, val)) formattedVal = dayjsValue.value[col]?.(val).format(format.value); + } else { + const currentHour = dayjsValue.value.hour(); + if (meridiem === AM && currentHour >= 12) { + formattedVal = dayjsValue.value.hour(currentHour - 12).format(format.value); + } else if (meridiem === PM && currentHour < 12) { + formattedVal = dayjsValue.value.hour(currentHour + 12).format(format.value); } else { - const currentHour = dayjsValue.value.hour(); - if (meridiem === AM && currentHour >= 12) { - formattedVal = dayjsValue.value.hour(currentHour - 12).format(format.value); - } else if (meridiem === PM && currentHour < 12) { - formattedVal = dayjsValue.value.hour(currentHour + 12).format(format.value); - } + formattedVal = dayjsValue.value.format(format.value); } - props.onChange?.(formattedVal); + } + if (formattedVal !== value.value) props.onChange?.(formattedVal); + if (distance !== scrollTop) { const scrollCtrl = colsRef[cols.value.indexOf(col)]; - if (!distance || !scrollCtrl || scrollCtrl.scrollTop === distance) return; + if (!scrollCtrl || scrollCtrl.scrollTop === distance) return; scrollCtrl.scrollTo?.({ top: distance, @@ -222,7 +242,7 @@ export default defineComponent({ ) => { const distance = getScrollDistance(col, time); const scrollCtrl = colsRef[idx]; - if (!distance || !scrollCtrl || scrollCtrl.scrollTop === distance || !timeItemCanUsed(col, time)) return; + if (!scrollCtrl || scrollCtrl.scrollTop === distance || !timeItemCanUsed(col, time)) return; scrollCtrl.scrollTo?.({ top: distance, @@ -308,6 +328,10 @@ export default defineComponent({ ref={(el) => (colsRef[idx] = el)} class={`${panelClassName.value}-body-scroll`} onScroll={debounce(() => handleScroll(col, idx), 50)} + style={{ + '--timePickerPanelOffsetTop': panelOffset.top, + '--timePickerPanelOffsetBottom': panelOffset.bottom, + }} > {getColList(col).map((el) => (