taro-ui-vue3
Version:
Taro UI Rewritten in Vue 3.0
348 lines (347 loc) • 10.4 kB
JavaScript
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
};