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
- eY = sM + Number(monthCount) - 1 > 12 ? sY + 1 : sY
43
- eM = sM + Number(monthCount) - 1 > 12 ? sM + Number(monthCount) - 1 - 12 : sM + Number(monthCount) - 1
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
- disabled = Boolean((minDate && key < minDate) || (maxDate && key > maxDate))
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 || 0;
103
- if (top === undefined || scrollTop.value === top) {
176
+ const top = tops[_viewMonth]?.top;
177
+ if (top === undefined) {
104
178
  initing.value = false;
105
179
  return;
106
180
  }
107
- contentScrollTop.value = scrollTop.value;
108
- nextTick(() => {
109
- contentScrollTop.value = top;
110
- scrollTop.value = top;
111
- viewMonth.value = _viewMonth;
112
- initing.value = false;
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(false)
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": "data",
111
- "description": "() => void"
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]maskClick",
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",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stellar-ui-plus",
3
- "version": "1.25.6",
3
+ "version": "1.25.7",
4
4
  "description": "",
5
5
  "author": "",
6
6
  "license": "MIT",