UNPKG

taro-ui-vue3

Version:

Taro UI Rewritten in Vue 3.0

348 lines (347 loc) 10.4 kB
import {h, defineComponent, computed, reactive, watch, onMounted, ref, nextTick} from "vue"; import {Swiper, SwiperItem, View} from "@tarojs/components"; import Taro from "@tarojs/taro"; import dayjs from "dayjs/esm/index"; import {delayQuerySelector} from "../../utils/common"; import generateCalendarGroup from "../common/helper"; import AtCalendarDateList from "../ui/date-list/index"; import AtCalendarDayList from "../ui/day-list/index"; const ANIMATE_DURATION = 300; const AtCalendarBody = defineComponent({ name: "AtCalendarBody", components: { AtCalendarDateList, AtCalendarDayList }, data: () => ({addGlobalClass: true}), props: { format: { type: String, default: "YYYY-MM-DD" }, validDates: { type: Array, default: () => [] }, marks: { type: Array, default: () => [] }, minDate: [String, Number, Date], maxDate: [String, Number, Date], isSwiper: { type: Boolean, default: true }, isVertical: { type: Boolean, default: false }, generateDate: { type: [Number, String], default: Date.now() }, selectedDate: { type: Object, default: () => ({end: Date.now(), start: Date.now()}) }, selectedDates: { type: Array, default: () => [] }, onDayClick: { type: Function, default: () => () => { } }, onLongClick: { type: Function, default: () => () => { } }, onSwipeMonth: { type: Function, default: () => () => { } } }, setup(props) { const startX = ref(0); const maxWidth = ref(0); const changeCount = ref(0); const swipeStartPoint = ref(0); const currentSwiperIndex = ref(1); const isTouching = ref(false); const isPreMonth = ref(false); const isWeb = ref(Taro.getEnv() === Taro.ENV_TYPE.WEB); let generateFunc = generateCalendarGroup({ validDates: props.validDates, format: props.format, minDate: props.minDate, maxDate: props.maxDate, marks: props.marks, selectedDates: props.selectedDates }); const state = reactive({ listGroup: getGroups(props.generateDate, props.selectedDate), offsetSize: 0, isAnimate: false }); const rootClass = computed(() => ({ main: true, "at-calendar-slider__main": true })); const h5MainBodyClass = computed(() => ({ body: true, main__body: true, "main__body--slider": props.isSwiper, "main__body--animate": state.isAnimate })); const h5MainBodyStyle = computed(() => { let style = {}; const transformStyle = props.isVertical ? `translateY(-100%) translate3d(0,${state.offsetSize}px,0)` : `translateX(-100%) translate3d(${state.offsetSize}px,0,0)`; if (props.isSwiper) { style.transform = transformStyle; style.WebkitTransform = transformStyle; if (props.isVertical) { style.flexDirection = "column"; } } return style; }); watch(() => [ props.validDates, props.marks, props.format, props.minDate, props.maxDate, props.selectedDates, props.generateDate, props.selectedDate ], ([ validDates, marks, format, minDate, maxDate, selectedDates, generateDate, selectedDate ]) => { const options = { validDates, marks, format, selectedDates, minDate, maxDate }; generateFunc = generateCalendarGroup(options); state.offsetSize = 0; state.listGroup = getGroups(generateDate, selectedDate); }); function getGroups(generateDate, selectedDate) { const dayjsDate = dayjs(generateDate); const arr = []; const preList = generateFunc(dayjsDate.subtract(1, "month").valueOf(), selectedDate); const nowList = generateFunc(generateDate, selectedDate, true); const nextList = generateFunc(dayjsDate.add(1, "month").valueOf(), selectedDate); const preListIndex = currentSwiperIndex.value === 0 ? 2 : currentSwiperIndex.value - 1; const nextListIndex = currentSwiperIndex.value === 2 ? 0 : currentSwiperIndex.value + 1; arr[preListIndex] = preList; arr[nextListIndex] = nextList; arr[currentSwiperIndex.value] = nowList; return arr; } function handleTouchStart(e) { if (!props.isSwiper) return; isTouching.value = true; startX.value = props.isVertical ? e.touches[0].clientY : e.touches[0].clientX; } function handleTouchMove(e) { if (!props.isSwiper) return; if (!isTouching.value) return; const clientXorY = props.isVertical ? e.touches[0].clientY : e.touches[0].clientX; state.offsetSize = clientXorY - startX.value; e.preventDefault(); e.stopPropagation(); } function animateMoveSlide(offset, callback) { state.isAnimate = true; nextTick(() => { state.offsetSize = offset; setTimeout(() => { state.isAnimate = false; nextTick(() => { callback && callback(); }); }, ANIMATE_DURATION); }); } function handleTouchEnd() { if (!props.isSwiper) return; isTouching.value = false; const isRight = state.offsetSize > 0; const breakpoint = maxWidth.value / 2; const absOffsetSize = Math.abs(state.offsetSize); if (absOffsetSize > breakpoint) { const res = isRight ? maxWidth.value : -maxWidth.value; return animateMoveSlide(res, () => { props.onSwipeMonth(isRight ? -1 : 1); }); } animateMoveSlide(0); } function handleChange(e) { const {current, source} = e.detail; if (source === "touch") { currentSwiperIndex.value = current; changeCount.value += 1; } } function handleAnimateFinish() { if (changeCount.value > 0) { props.onSwipeMonth(isPreMonth.value ? -changeCount.value : changeCount.value); changeCount.value = 0; } } function handleSwipeTouchStart(e) { const {clientX, clientY} = e.changedTouches[0]; swipeStartPoint.value = props.isVertical ? clientY : clientX; } function handleSwipeTouchEnd(e) { const {clientX, clientY} = e.changedTouches[0]; isPreMonth.value = props.isVertical ? clientY - swipeStartPoint.value > 0 : clientX - swipeStartPoint.value > 0; } function handleSwipeTouchMove(e) { e.preventDefault(); e.stopPropagation(); return; } onMounted(() => { delayQuerySelector(this, ".at-calendar-slider__main", 100).then((res) => { maxWidth.value = props.isVertical ? res[0].height : res[0].width; }); }); return () => { if (!props.isSwiper) { return h(View, { class: rootClass.value }, { default: () => [ h(AtCalendarDayList), h(View, { class: "main__body body" }, { default: () => [ h(View, { class: "body__slider body__slider--now" }, { default: () => [ h(AtCalendarDateList, { list: state.listGroup[1].list, onClick: props.onDayClick, onLongClick: props.onLongClick }) ] }) ] }) ] }); } if (isWeb.value) { return h(View, { class: rootClass.value, onTouchend: handleTouchEnd, onTouchmove: handleTouchMove, onTouchstart: handleTouchStart }, { default: () => [ h(AtCalendarDayList), h(View, { class: h5MainBodyClass.value, style: h5MainBodyStyle.value }, { default: () => [ h(View, { class: "body__slider body__slider--pre" }, { default: () => [ h(AtCalendarDateList, { key: state.listGroup[0].value, list: state.listGroup[0].list }) ] }), h(View, { class: "body__slider body__slider--now" }, { default: () => [ h(AtCalendarDateList, { key: state.listGroup[1].value, list: state.listGroup[1].list, onClick: props.onDayClick, onLongClick: props.onLongClick }) ] }), h(View, { class: "body__slider body__slider--next" }, { default: () => [ h(AtCalendarDateList, { key: state.listGroup[2].value, list: state.listGroup[2].list }) ] }) ] }) ] }); } return h(View, { class: rootClass.value }, { default: () => [ h(AtCalendarDayList), h(Swiper, { class: "main__body", circular: true, vertical: props.isVertical, skipHiddenItemLayout: true, current: currentSwiperIndex.value, catchMove: true, onChange: handleChange, onAnimationfinish: handleAnimateFinish, onTouchmove: handleSwipeTouchMove, onTouchend: handleSwipeTouchEnd, onTouchstart: handleSwipeTouchStart }, { default: () => state.listGroup.map((item, key) => h(SwiperItem, { key: key.toString(), itemId: key.toString() }, { default: () => [ h(AtCalendarDateList, { list: item.list, onClick: props.onDayClick, onLongClick: props.onLongClick }) ] })) }) ] }); }; } }); var body_default = AtCalendarBody; export { body_default as default };