stellar-ui-plus 1.25.6 → 1.25.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -39,8 +39,9 @@ function getMonthList(minDate?: DateType, maxDate?: DateType, defaultDate?: Date
|
|
|
39
39
|
eY = Number(end.format('YYYY'))
|
|
40
40
|
eM = Number(end.format('MM'))
|
|
41
41
|
} else {
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
const totalMonths = sM + Number(monthCount) - 1
|
|
43
|
+
eY = sY + Math.floor((totalMonths - 1) / 12)
|
|
44
|
+
eM = ((totalMonths - 1) % 12) + 1
|
|
44
45
|
}
|
|
45
46
|
const months = []
|
|
46
47
|
for (let y = sY; y <= eY; y++) {
|
|
@@ -96,8 +97,13 @@ export function getCalendarData(minDate?: DateType, maxDate?: DateType, defaultD
|
|
|
96
97
|
else _day = day++
|
|
97
98
|
const key = _day ? utils.dayjs(`${monthData.key}-${_day}`).format(formatter) : Math.random()
|
|
98
99
|
let disabled = !_day
|
|
99
|
-
if (_day)
|
|
100
|
-
|
|
100
|
+
if (_day) {
|
|
101
|
+
const keyDate = utils.dayjs(key)
|
|
102
|
+
disabled = Boolean(
|
|
103
|
+
(minDate && keyDate.isBefore(utils.dayjs(minDate), 'day')) ||
|
|
104
|
+
(maxDate && keyDate.isAfter(utils.dayjs(maxDate), 'day'))
|
|
105
|
+
)
|
|
106
|
+
}
|
|
101
107
|
|
|
102
108
|
const daySigns = _day && signs && signs[key] ? signs[key].slice(0, 3).map(item => ({
|
|
103
109
|
...item,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { watch, onMounted, computed, nextTick, onUnmounted } from 'vue';
|
|
2
|
+
import { watch, onMounted, computed, nextTick, onUnmounted, ref, getCurrentInstance } from 'vue';
|
|
3
3
|
import { useColorStore } from '../../store/color';
|
|
4
4
|
let { getColor } = useColorStore();
|
|
5
5
|
import { formatDate, type DateType, type WeekType } from './date';
|
|
@@ -75,8 +75,81 @@ const clearViewTimer = () => {
|
|
|
75
75
|
}
|
|
76
76
|
};
|
|
77
77
|
|
|
78
|
+
// 根节点引用,用于可见性监听
|
|
79
|
+
const rootRef = ref<any>(null);
|
|
80
|
+
// 是否已可见(在视口内)
|
|
81
|
+
let isVisible = false;
|
|
82
|
+
// 待执行的滚动目标,组件不可见时暂存
|
|
83
|
+
let pendingScrollTop: number | null = null;
|
|
84
|
+
// 在 setup 顶层获取实例,供小程序端观察器使用
|
|
85
|
+
const instance = getCurrentInstance();
|
|
86
|
+
|
|
87
|
+
const doScroll = (top: number, _viewMonth: string) => {
|
|
88
|
+
if (scrollTop.value === top) {
|
|
89
|
+
viewMonth.value = _viewMonth;
|
|
90
|
+
initing.value = false;
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
contentScrollTop.value = scrollTop.value;
|
|
94
|
+
nextTick(() => {
|
|
95
|
+
contentScrollTop.value = top;
|
|
96
|
+
scrollTop.value = top;
|
|
97
|
+
viewMonth.value = _viewMonth;
|
|
98
|
+
initing.value = false;
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
let observer: any = null;
|
|
103
|
+
const startObserver = () => {
|
|
104
|
+
// #ifdef H5
|
|
105
|
+
if (typeof IntersectionObserver !== 'undefined' && rootRef.value) {
|
|
106
|
+
// uni-app H5 中 <view> 的 ref 直接是 DOM 元素
|
|
107
|
+
const el = rootRef.value.$el ?? rootRef.value;
|
|
108
|
+
observer = new IntersectionObserver(entries => {
|
|
109
|
+
const visible = entries[0]?.isIntersecting;
|
|
110
|
+
if (visible && !isVisible) {
|
|
111
|
+
isVisible = true;
|
|
112
|
+
if (pendingScrollTop !== null) {
|
|
113
|
+
const top = pendingScrollTop;
|
|
114
|
+
const _viewMonth = viewDate.value.format('YYYY-MM');
|
|
115
|
+
pendingScrollTop = null;
|
|
116
|
+
nextTick(() => doScroll(top, _viewMonth));
|
|
117
|
+
}
|
|
118
|
+
} else if (!visible) {
|
|
119
|
+
isVisible = false;
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
observer.observe(el);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
// #endif
|
|
126
|
+
// 小程序端使用 uni.createIntersectionObserver
|
|
127
|
+
try {
|
|
128
|
+
observer = uni.createIntersectionObserver(instance).relativeToViewport();
|
|
129
|
+
observer.observe('.ste-calendar-root', (res: any) => {
|
|
130
|
+
const visible = res.intersectionRatio > 0;
|
|
131
|
+
if (visible && !isVisible) {
|
|
132
|
+
isVisible = true;
|
|
133
|
+
if (pendingScrollTop !== null) {
|
|
134
|
+
const top = pendingScrollTop;
|
|
135
|
+
const _viewMonth = viewDate.value.format('YYYY-MM');
|
|
136
|
+
pendingScrollTop = null;
|
|
137
|
+
nextTick(() => doScroll(top, _viewMonth));
|
|
138
|
+
}
|
|
139
|
+
} else if (!visible) {
|
|
140
|
+
isVisible = false;
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
} catch (_) {}
|
|
144
|
+
};
|
|
145
|
+
|
|
78
146
|
onUnmounted(() => {
|
|
79
147
|
clearViewTimer();
|
|
148
|
+
if (observer) {
|
|
149
|
+
observer.disconnect?.();
|
|
150
|
+
observer.unobserve?.();
|
|
151
|
+
observer = null;
|
|
152
|
+
}
|
|
80
153
|
});
|
|
81
154
|
|
|
82
155
|
const showMonth = (date?: DateType) => {
|
|
@@ -84,6 +157,7 @@ const showMonth = (date?: DateType) => {
|
|
|
84
157
|
if (newDate.format('YYYY-MM-DD') !== viewDate.value.format('YYYY-MM-DD')) {
|
|
85
158
|
viewDate.value = newDate;
|
|
86
159
|
}
|
|
160
|
+
initing.value = true;
|
|
87
161
|
clearViewTimer();
|
|
88
162
|
viewTimer = setTimeout(() => {
|
|
89
163
|
if (props.minDate && props.maxDate) {
|
|
@@ -99,18 +173,17 @@ const showMonth = (date?: DateType) => {
|
|
|
99
173
|
}
|
|
100
174
|
const _viewMonth = viewDate.value.format('YYYY-MM');
|
|
101
175
|
const tops = cmpMonthTops.value;
|
|
102
|
-
const top = tops[_viewMonth]?.top
|
|
103
|
-
if (top === undefined
|
|
176
|
+
const top = tops[_viewMonth]?.top;
|
|
177
|
+
if (top === undefined) {
|
|
104
178
|
initing.value = false;
|
|
105
179
|
return;
|
|
106
180
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
});
|
|
181
|
+
// 组件不可见时,暂存目标位置,等可见后再执行
|
|
182
|
+
if (!isVisible) {
|
|
183
|
+
pendingScrollTop = top;
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
doScroll(top, _viewMonth);
|
|
114
187
|
}, VIEW_MONTH_DELAY);
|
|
115
188
|
};
|
|
116
189
|
|
|
@@ -208,7 +281,6 @@ watch(
|
|
|
208
281
|
() => props.defaultDate,
|
|
209
282
|
v => {
|
|
210
283
|
viewDate.value = v ? utils.dayjs(v) : utils.dayjs();
|
|
211
|
-
showMonth();
|
|
212
284
|
},
|
|
213
285
|
{ immediate: true }
|
|
214
286
|
);
|
|
@@ -217,6 +289,7 @@ const confirm = () => {
|
|
|
217
289
|
emits('confirm', dataList.value);
|
|
218
290
|
};
|
|
219
291
|
onMounted(() => {
|
|
292
|
+
startObserver();
|
|
220
293
|
showMonth();
|
|
221
294
|
});
|
|
222
295
|
|
|
@@ -241,7 +314,7 @@ const onScroll = (e: any) => {
|
|
|
241
314
|
};
|
|
242
315
|
</script>
|
|
243
316
|
<template>
|
|
244
|
-
<view class="ste-calendar-root" :style="[cmpRootStyle, { opacity: initing ? 0 : 1 }]">
|
|
317
|
+
<view ref="rootRef" class="ste-calendar-root" :style="[cmpRootStyle, { opacity: initing ? 0 : 1 }]">
|
|
245
318
|
<view v-if="showTitle" class="calendar-title">{{ title }}</view>
|
|
246
319
|
<view class="week-head">
|
|
247
320
|
<view class="week-row">
|
|
@@ -3,7 +3,7 @@ import utils from '../../utils/utils'
|
|
|
3
3
|
import type { Dayjs } from '../../types'
|
|
4
4
|
|
|
5
5
|
export default function useData() {
|
|
6
|
-
const initing = ref(
|
|
6
|
+
const initing = ref(true)
|
|
7
7
|
const setIniting = (val: boolean) => initing.value = val
|
|
8
8
|
const startDate = ref<number | string | null>(null)
|
|
9
9
|
const setStartDate = (val: number | string | null) => startDate.value = val
|
|
@@ -104,33 +104,31 @@
|
|
|
104
104
|
},
|
|
105
105
|
{
|
|
106
106
|
"name": "[event]close",
|
|
107
|
-
"description": "
|
|
107
|
+
"description": "弹窗关闭前触发,可用于异步拦截关闭",
|
|
108
108
|
"params": [
|
|
109
109
|
{
|
|
110
|
-
"name": "
|
|
111
|
-
"description": "
|
|
110
|
+
"name": "suspend",
|
|
111
|
+
"description": "开启等待的回调函数"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"name": "next",
|
|
115
|
+
"description": "执行后续关闭操作的回调函数"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"name": "stop",
|
|
119
|
+
"description": "阻止后续关闭操作的回调函数"
|
|
112
120
|
}
|
|
113
121
|
]
|
|
114
122
|
},
|
|
115
123
|
{
|
|
116
|
-
"name": "[event]open",
|
|
124
|
+
"name": "[event]open-after",
|
|
117
125
|
"description": "弹窗打开动画执行完毕事件",
|
|
118
|
-
"params": [
|
|
119
|
-
{
|
|
120
|
-
"name": "data",
|
|
121
|
-
"description": "() => void"
|
|
122
|
-
}
|
|
123
|
-
]
|
|
126
|
+
"params": []
|
|
124
127
|
},
|
|
125
128
|
{
|
|
126
|
-
"name": "[event]
|
|
129
|
+
"name": "[event]clickMask",
|
|
127
130
|
"description": "点击遮罩时触发",
|
|
128
|
-
"params": [
|
|
129
|
-
{
|
|
130
|
-
"name": "data",
|
|
131
|
-
"description": "() => void"
|
|
132
|
-
}
|
|
133
|
-
]
|
|
131
|
+
"params": []
|
|
134
132
|
},
|
|
135
133
|
{
|
|
136
134
|
"name": "[slot]default",
|