hy-app 0.6.2 → 0.6.4

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.
@@ -5,15 +5,20 @@
5
5
  <scroll-view
6
6
  class="hy-table__header--scroll"
7
7
  scroll-x
8
- :scroll-left="scrollLeft"
8
+ :scroll-left="topScrollLeft"
9
9
  :scroll-y="false"
10
+ lower-threshold="0"
10
11
  @scroll="onHeaderScroll"
12
+ @scrolltolower="isReachBottom = true"
11
13
  >
12
14
  <view class="hy-table__header--wrapper" :style="{ width: addUnit(totalWidth) }">
13
15
  <!-- 左侧固定列头 -->
14
16
  <view
15
17
  v-if="leftFixedColumns.length > 0"
16
- :class="['hy-table__header--wrapper__left', scrollLeft && 'is-shadow']"
18
+ :class="[
19
+ 'hy-table__header--wrapper__left',
20
+ isShadow('left') && 'is-shadow'
21
+ ]"
17
22
  :style="{ width: addUnit(leftFixedWidth), zIndex: 3 }"
18
23
  >
19
24
  <view
@@ -103,7 +108,10 @@
103
108
  <!-- 右侧固定列头 -->
104
109
  <view
105
110
  v-if="rightFixedColumns.length > 0"
106
- class="hy-table__header--wrapper__right"
111
+ :class="[
112
+ 'hy-table__header--wrapper__right',
113
+ isShadow('right') && 'is-shadow'
114
+ ]"
107
115
  :style="{ width: addUnit(rightFixedWidth), zIndex: 3 }"
108
116
  >
109
117
  <view
@@ -161,9 +169,9 @@
161
169
  <!-- 左侧固定列 -->
162
170
  <scroll-view
163
171
  v-if="processedData.length"
164
- :class="['hy-table__body--left', scrollLeft && 'is-shadow']"
172
+ :class="['hy-table__body--left', isShadow('left') && 'is-shadow']"
165
173
  scroll-y
166
- :scroll-top="scrollTop"
174
+ :scroll-top="leftScrollTop"
167
175
  :style="{ width: addUnit(leftFixedWidth), height: addUnit(bodyHeight) }"
168
176
  @scroll="onLeftScroll"
169
177
  >
@@ -205,7 +213,7 @@
205
213
  v-if="processedData.length"
206
214
  class="hy-table__body--center"
207
215
  scroll-y
208
- :scroll-top="scrollTop"
216
+ :scroll-top="centerScrollTop"
209
217
  @scroll="onScroll"
210
218
  :style="{
211
219
  width: `calc(100% - ${leftFixedWidth + rightFixedWidth}px)`,
@@ -216,9 +224,12 @@
216
224
  >
217
225
  <scroll-view
218
226
  scroll-x
219
- :scroll-left="scrollLeft"
227
+ :scroll-y="false"
228
+ :scroll-left="centerScrollLeft"
220
229
  class="hy-table__body--content"
230
+ lower-threshold="5"
221
231
  @scroll="onCrosswiseScroll"
232
+ @scrolltolower="isReachBottom = true"
222
233
  >
223
234
  <view
224
235
  v-for="(row, rowIndex) in processedData"
@@ -256,9 +267,9 @@
256
267
  <!-- 右侧固定列 -->
257
268
  <scroll-view
258
269
  v-if="processedData.length"
259
- class="hy-table__body--right"
270
+ :class="['hy-table__body--right', isShadow('right') && 'is-shadow']"
260
271
  scroll-y
261
- :scroll-top="scrollTop"
272
+ :scroll-top="rightScrollTop"
262
273
  :style="{
263
274
  width: addUnit(rightFixedWidth),
264
275
  height: addUnit(bodyHeight),
@@ -314,8 +325,8 @@ export default {
314
325
  </script>
315
326
 
316
327
  <script setup lang="ts">
317
- import { ref, computed, watch, onMounted, nextTick } from 'vue'
318
- import { addUnit, IconConfig, sleep, getPx } from '../../libs'
328
+ import { ref, computed, watch, onMounted } from 'vue'
329
+ import { addUnit, IconConfig, getPx } from '../../libs'
319
330
  import type { ITableColumn, ITableEmits } from './typing'
320
331
  import tableProps from './props'
321
332
  // 组件
@@ -333,15 +344,19 @@ const props = defineProps(tableProps)
333
344
  const emit = defineEmits<ITableEmits>()
334
345
 
335
346
  // 响应式数据
336
- const scrollLeft = ref(0)
337
- const scrollTop = ref(0)
338
347
  const rowHeights = ref<number[]>([])
339
348
  const sortField = ref<string>('')
340
349
  const sortOrder = ref<'asc' | 'desc'>('asc')
341
350
  const SLEEP_TIME = 60
342
-
343
351
  // 防止滚动循环触发和抖动的标志位
344
- const isUpdatingScroll = ref(false)
352
+ const activeScroller = ref('')
353
+ const isSyncing = ref(false)
354
+ const leftScrollTop = ref(0)
355
+ const centerScrollTop = ref(0)
356
+ const rightScrollTop = ref(0)
357
+ const centerScrollLeft = ref(0)
358
+ const topScrollLeft = ref(0)
359
+ const isReachBottom = ref(false)
345
360
 
346
361
  // 计算属性
347
362
  const leftFixedColumns = computed(() => props.columns.filter((col) => col.fixed === 'left'))
@@ -361,14 +376,24 @@ const rightFixedWidth = computed(() =>
361
376
  const scrollWidth = computed(() => scrollColumns.value.reduce((sum, col) => sum + col.width, 0))
362
377
 
363
378
  const totalWidth = computed(() => leftFixedWidth.value + scrollWidth.value + rightFixedWidth.value)
364
-
379
+ // 表格高度
365
380
  const containerHeight = computed(() => props.height)
366
-
381
+ // 表格高度
367
382
  const bodyHeight = computed(() => {
368
383
  // 减去表头高度
369
384
  return props.showHeader ? getPx(props.height) - 50 : props.height
370
385
  })
371
386
 
387
+ const isShadow = computed(() => {
388
+ return (type: 'left' | 'right') => {
389
+ if (type === 'left') {
390
+ return topScrollLeft.value !== 0 || centerScrollLeft.value !== 0
391
+ } else {
392
+ return !isReachBottom.value
393
+ }
394
+ }
395
+ })
396
+
372
397
  const processedData = computed(() => {
373
398
  let data = [...props.data]
374
399
 
@@ -389,6 +414,8 @@ const processedData = computed(() => {
389
414
  return data
390
415
  })
391
416
 
417
+ onMounted(() => {})
418
+
392
419
  // 方法
393
420
  const getHeaderCellStyle = (col: ITableColumn) => {
394
421
  return {
@@ -445,83 +472,51 @@ const getCellValue = (row: any, col: ITableColumn) => {
445
472
  /**
446
473
  * 头部横向滚动
447
474
  * */
448
- const onHeaderScroll = async (e: any) => {
449
- if (isUpdatingScroll.value) return
450
-
451
- const newScrollLeft = e.detail.scrollLeft
452
- if (Math.abs(newScrollLeft - scrollLeft.value) > 1) {
453
- isUpdatingScroll.value = true
454
- scrollLeft.value = newScrollLeft
455
- // 在下一个事件循环重置标志位
456
- await sleep(SLEEP_TIME)
457
- isUpdatingScroll.value = false
458
- }
475
+ const onHeaderScroll = (e: any) => {
476
+ if (activeScroller.value && activeScroller.value !== 'top') return
477
+ syncScroll('top', {
478
+ scrollLeft: e.detail.scrollLeft
479
+ })
459
480
  }
460
481
 
461
482
  /**
462
483
  * 中间内容竖直滚动
463
484
  * */
464
- const onScroll = async (e: any) => {
465
- if (isUpdatingScroll.value) return
466
-
467
- const newScrollTop = e.detail.scrollTop
468
- isUpdatingScroll.value = true
469
- if (Math.abs(newScrollTop - scrollTop.value) > 1) {
470
- scrollTop.value = newScrollTop
471
- }
472
-
473
- // 在下一个事件循环重置标志位
474
- await sleep(SLEEP_TIME)
475
- isUpdatingScroll.value = false
485
+ const onScroll = (e: any) => {
486
+ if (activeScroller.value && activeScroller.value !== 'center') return
487
+ syncScroll('center', {
488
+ scrollTop: e.detail.scrollTop
489
+ })
476
490
  }
477
491
 
478
492
  /**
479
493
  * 中间内容横向滚动
480
494
  * */
481
- const onCrosswiseScroll = async (e: any) => {
482
- if (isUpdatingScroll.value) return
483
-
484
- const newScrollLeft = e.detail.scrollLeft
485
- isUpdatingScroll.value = true
486
- // 使用阈值来减少频繁更新,避免抖动
487
- if (Math.abs(newScrollLeft - scrollLeft.value) > 1) {
488
- scrollLeft.value = newScrollLeft
489
- }
490
- // 在下一个事件循环重置标志位
491
- await sleep(SLEEP_TIME)
492
- isUpdatingScroll.value = false
495
+ const onCrosswiseScroll = (e: any) => {
496
+ if (activeScroller.value && activeScroller.value !== 'bottom') return
497
+ syncScroll('bottom', {
498
+ scrollLeft: e.detail.scrollLeft
499
+ })
493
500
  }
494
501
 
495
502
  /**
496
- * 左侧列表滚动
503
+ * 左侧列表竖向滚动
497
504
  * */
498
- const onLeftScroll = async (e: any) => {
499
- if (isUpdatingScroll.value) return
500
-
501
- const newScrollTop = e.detail.scrollTop
502
- if (Math.abs(newScrollTop - scrollTop.value) > 1) {
503
- isUpdatingScroll.value = true
504
- scrollTop.value = newScrollTop
505
- // 在下一个事件循环重置标志位
506
- await sleep(SLEEP_TIME)
507
- isUpdatingScroll.value = false
508
- }
505
+ const onLeftScroll = (e: any) => {
506
+ if (activeScroller.value && activeScroller.value !== 'left') return
507
+ syncScroll('left', {
508
+ scrollTop: e.detail.scrollTop
509
+ })
509
510
  }
510
511
 
511
512
  /**
512
- * 右侧列表滚动
513
+ * 右侧列表竖向滚动
513
514
  * */
514
- const onRightScroll = async (e: any) => {
515
- if (isUpdatingScroll.value) return
516
-
517
- const newScrollTop = e.detail.scrollTop
518
- if (Math.abs(newScrollTop - scrollTop.value) > 1) {
519
- isUpdatingScroll.value = true
520
- scrollTop.value = newScrollTop
521
- // 在下一个事件循环重置标志位
522
- await sleep(SLEEP_TIME)
523
- isUpdatingScroll.value = false
524
- }
515
+ const onRightScroll = (e: any) => {
516
+ if (activeScroller.value && activeScroller.value != 'right') return
517
+ syncScroll('right', {
518
+ scrollTop: e.detail.scrollTop
519
+ })
525
520
  }
526
521
 
527
522
  /**
@@ -569,6 +564,45 @@ watch(
569
564
  },
570
565
  { deep: true }
571
566
  )
567
+
568
+ /**
569
+ * 通用滚动同步函数
570
+ * @param source 哪组滚动数据
571
+ * @param payload 滚动实例
572
+ * */
573
+ const syncScroll = (source: string, payload: { scrollTop?: number; scrollLeft?: number }) => {
574
+ if (isSyncing.value) return
575
+
576
+ isSyncing.value = true
577
+ activeScroller.value = source
578
+
579
+ if (payload.scrollTop !== undefined) {
580
+ if (activeScroller.value !== 'left') leftScrollTop.value = payload.scrollTop
581
+ if (activeScroller.value !== 'center') centerScrollTop.value = payload.scrollTop
582
+ if (activeScroller.value !== 'right') rightScrollTop.value = payload.scrollTop
583
+ }
584
+
585
+ if (payload.scrollLeft !== undefined) {
586
+ isReachBottom.value = false
587
+ // centerScrollLeft.value = payload.scrollLeft
588
+ if (activeScroller.value !== 'top') topScrollLeft.value = payload.scrollLeft
589
+ if (activeScroller.value !== 'bottom') centerScrollLeft.value = payload.scrollLeft
590
+ }
591
+
592
+ // 下一帧解锁
593
+ nextFrame(() => {
594
+ isSyncing.value = false
595
+ activeScroller.value = ''
596
+ })
597
+ }
598
+
599
+ const nextFrame = (cb: () => void) => {
600
+ if (typeof requestAnimationFrame !== 'undefined') {
601
+ requestAnimationFrame(cb)
602
+ } else {
603
+ setTimeout(cb, SLEEP_TIME)
604
+ }
605
+ }
572
606
  </script>
573
607
 
574
608
  <style scoped lang="scss">
@@ -67,13 +67,17 @@ $stripe-bg: $hy-background--table-header;
67
67
  border-right: $hy-border-line;
68
68
 
69
69
  @include is(shadow) {
70
- box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
70
+ box-shadow: 4px 0 10px rgba(0, 0, 0, 0.1);
71
71
  }
72
72
  }
73
73
 
74
74
  @include e(right) {
75
75
  right: 0;
76
76
  border-left: $hy-border-line;
77
+
78
+ @include is(shadow) {
79
+ box-shadow: -4px 0 10px rgba(0, 0, 0, 0.1);
80
+ }
77
81
  }
78
82
  }
79
83
  }
@@ -165,13 +169,21 @@ $stripe-bg: $hy-background--table-header;
165
169
  left: 0;
166
170
 
167
171
  @include is(shadow) {
168
- box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
172
+ box-shadow: 4px 0 10px rgba(0, 0, 0, 0.1);
169
173
  }
170
174
  }
171
175
 
172
176
  @include m(right) {
173
177
  right: 0;
174
178
  border-left: $hy-border-line;
179
+
180
+ @include is(shadow) {
181
+ box-shadow: -4px 0 10px rgba(0, 0, 0, 0.1);
182
+ }
175
183
  }
176
184
  }
177
- }
185
+ }
186
+
187
+ //.is-shadow {
188
+ // box-shadow: -4px 0 10px rgba(0, 0, 0, 0.1);
189
+ //}
@@ -70,6 +70,9 @@
70
70
  }
71
71
 
72
72
  .swiper-item {
73
+ width: 100%;
73
74
  height: 100%;
75
+ @include flex(column);
76
+ box-sizing: border-box;
74
77
  }
75
78
  }
@@ -18,11 +18,10 @@
18
18
  :round="icon?.round"
19
19
  :customStyle="Object.assign({ marginRight: '3px' }, icon?.customStyle)"
20
20
  ></hy-icon>
21
- <text :class="textClass" :style="textStyle">
22
- <slot>
23
- {{ text }}
24
- </slot>
25
- </text>
21
+ <view :class="textClass" :style="textStyle">
22
+ <slot v-if="$slots.default"></slot>
23
+ <template v-else>{{ text }}</template>
24
+ </view>
26
25
  <!-- 关闭按钮 -->
27
26
  <view
28
27
  :class="['hy-tag__close', `hy-tag__close--${size}`]"
@@ -1,5 +1,10 @@
1
1
  <template>
2
- <HyOverlay :show="isShow" :zIndex="tmpConfig.overlay ? 10070 : -1" :custom-style="overlayStyle">
2
+ <hy-overlay
3
+ :show="isShow"
4
+ :zIndex="tmpConfig.overlay ? 10070 : -1"
5
+ :LockScroll="false"
6
+ :custom-style="overlayStyle"
7
+ >
3
8
  <view :style="[contentStyle]" :class="contentClass">
4
9
  <hy-loading
5
10
  v-if="tmpConfig.loading"
@@ -18,13 +23,15 @@
18
23
  <text
19
24
  :class="[
20
25
  'hy-toast__content--test',
21
- !tmpConfig.icon ? `hy-toast__content--text__${tmpConfig.type}` : ''
26
+ !tmpConfig.icon && !tmpConfig.loading
27
+ ? `hy-toast__content--text__${tmpConfig.type}`
28
+ : ''
22
29
  ]"
23
30
  >
24
31
  {{ tmpConfig.message }}
25
32
  </text>
26
33
  </view>
27
- </HyOverlay>
34
+ </hy-overlay>
28
35
  </template>
29
36
 
30
37
  <script lang="ts">
@@ -42,7 +49,7 @@ export default {
42
49
  import { computed, onMounted, onUnmounted, reactive, ref } from 'vue'
43
50
  import type { CSSProperties } from 'vue'
44
51
  import type ToastOptions from './typing'
45
- import { ColorConfig, iconName, getWindowInfo, hexToRgb } from '../../libs'
52
+ import { ColorConfig, iconName, getWindowInfo, hexToRgb, deepMerge } from '../../libs'
46
53
  // 组件
47
54
  import HyOverlay from '../hy-overlay/hy-overlay.vue'
48
55
  import HyIcon from '../hy-icon/hy-icon.vue'
@@ -75,7 +82,8 @@ const overlayStyle = computed(() => {
75
82
  const style: CSSProperties = {
76
83
  justifyContent: 'center',
77
84
  alignItems: 'center',
78
- display: 'flex'
85
+ display: 'flex',
86
+ flexDirection: 'column'
79
87
  }
80
88
  // 将遮罩设置为100%透明度,避免出现灰色背景
81
89
  style.backgroundColor = 'rgba(0, 0, 0, 0)'
@@ -99,7 +107,7 @@ const iconNameCom = computed(() => {
99
107
  })
100
108
 
101
109
  /**
102
- * @description 内容盒子的样式
110
+ * 内容盒子的样式
103
111
  * */
104
112
  const contentStyle = computed(() => {
105
113
  const windowHeight = getWindowInfo().windowHeight,
@@ -145,13 +153,12 @@ onUnmounted(() => {
145
153
  })
146
154
 
147
155
  /**
148
- * @description 显示toast组件,由父组件通过xxx.show(options)形式调用
156
+ * 显示toast组件,由父组件通过xxx.show(options)形式调用
149
157
  * */
150
158
  const show = (options: ToastOptions) => {
151
- // 不将结果合并到this.config变量,避免多次调用u-toast,前后的配置造成混乱
152
- tmpConfig.value = Object.assign(config, options)
153
159
  // 清除定时器
154
160
  clearTimer()
161
+ tmpConfig.value = { ...config, ...options }
155
162
  isShow.value = true
156
163
  // -1时不自动关闭
157
164
  if (tmpConfig.value.duration !== -1 && !tmpConfig.value.loading) {
@@ -164,19 +171,22 @@ const show = (options: ToastOptions) => {
164
171
  }
165
172
  }
166
173
 
167
- // 隐藏toast组件,由父组件通过this.$refs.xxx.hide()形式调用
174
+ /**
175
+ * 隐藏toast组件,由父组件通过ref形式调用
176
+ * */
168
177
  const hide = () => {
169
- config.loading = false
170
178
  clearTimer()
171
179
  }
172
180
  /**
173
- * @description 清除定时任务
181
+ * 清除定时任务
174
182
  * */
175
183
  const clearTimer = () => {
176
184
  isShow.value = false
177
185
  // 清除定时器
178
186
  clearTimeout(timer)
179
187
  timer = null
188
+ // 防止后面请求还是loading状态
189
+ // config.loading = false
180
190
  }
181
191
 
182
192
  defineExpose({