vue2-client 1.20.48 → 1.20.50

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue2-client",
3
- "version": "1.20.48",
3
+ "version": "1.20.50",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "serve": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve --no-eslint",
@@ -489,8 +489,6 @@ export default {
489
489
  // 行选择模式
490
490
  selectRowMode: 'default',
491
491
  tableSize: 'default',
492
- /** 是否启用 tbody 虚拟滚动(配置 virtualScroll: true) */
493
- virtualScroll: true,
494
492
  clearSelectRowAfterQuery: false,
495
493
  selectedRowModalVisible: false,
496
494
  // 是否禁用右侧操作行为
@@ -888,7 +886,6 @@ export default {
888
886
  printTemplate = 'DEFAULT_CRUD_PRINT_TEMPLATE',
889
887
  selectRowMode = 'default',
890
888
  tableSize = 'default',
891
- virtualScroll = true,
892
889
  clearSelectRowAfterQuery = false,
893
890
  disableAction = false,
894
891
  extraData,
@@ -955,7 +952,6 @@ export default {
955
952
  this.chartsConfigArray = chartsConfigArray
956
953
  this.selectRowMode = selectRowMode
957
954
  this.tableSize = tableSize
958
- this.virtualScroll = virtualScroll
959
955
  this.clearSelectRowAfterQuery = clearSelectRowAfterQuery
960
956
  this.disableAction = disableAction
961
957
  this.extraData = extraData
@@ -1883,12 +1879,6 @@ export default {
1883
1879
  color: @primary-color;
1884
1880
  }
1885
1881
 
1886
- .innerTable {
1887
- :deep(.ant-form-item) {
1888
- margin: 0;
1889
- }
1890
- }
1891
-
1892
1882
  .hiddenFunctionalArea {
1893
1883
  display: none;
1894
1884
  }
@@ -374,7 +374,12 @@ export default {
374
374
  }),
375
375
  virtualScrollContainers: null,
376
376
  virtualScrollResizeObserver: null,
377
- virtualScrollRafId: null
377
+ /** 滚动:每帧最多一次 RAF,合并同帧内多次 scroll */
378
+ virtualScrollRafId: null,
379
+ /** 滚动时待处理的容器(与 RAF 配合,避免漏读 scrollTop) */
380
+ virtualScrollPendingTarget: null,
381
+ /** ResizeObserver 防抖定时器(窗口/侧栏拖拽时连续触发) */
382
+ virtualScrollResizeDebounceTimer: null
378
383
  }
379
384
  },
380
385
  computed: {
@@ -416,9 +421,9 @@ export default {
416
421
  // 3. 按顺序合并:左固定 + 普通 + 右固定
417
422
  return [...leftFixedColumns, ...normalColumns, ...rightFixedColumns]
418
423
  },
419
- /** 有行展开栅格时行高不可预测,关闭虚拟滚动 */
424
+ /** 默认开启虚拟滚动;有行展开栅格时行高不可预测,关闭虚拟滚动 */
420
425
  enableVirtualScroll () {
421
- return !!this.tableContext.virtualScroll && !this.tableContext.expandedGrid
426
+ return !this.tableContext.expandedGrid
422
427
  },
423
428
  components () {
424
429
  const headerCell = (h, props, children) => {
@@ -692,21 +697,60 @@ export default {
692
697
  },
693
698
  handleVirtualScroll (e) {
694
699
  if (!this.enableVirtualScroll) return
695
- if (this.virtualScrollRafId) return
700
+ this.virtualScrollPendingTarget = e.target
701
+ this.scheduleVirtualScrollRaf()
702
+ },
703
+ /** 将多次 scroll 合并到同一帧 RAF;若 flush 后又产生 pending 则再排一帧 */
704
+ scheduleVirtualScrollRaf () {
705
+ if (this.virtualScrollRafId != null) return
696
706
  this.virtualScrollRafId = requestAnimationFrame(() => {
697
707
  this.virtualScrollRafId = null
698
- this.applyVirtualWindowFromScroll(e.target)
708
+ this.flushVirtualScrollPending()
699
709
  })
700
710
  },
711
+ flushVirtualScrollPending () {
712
+ const container = this.virtualScrollPendingTarget
713
+ this.virtualScrollPendingTarget = null
714
+ if (container && this.enableVirtualScroll) {
715
+ this.applyVirtualWindowFromScroll(container)
716
+ }
717
+ if (this.virtualScrollPendingTarget) {
718
+ this.scheduleVirtualScrollRaf()
719
+ }
720
+ },
721
+ /** ResizeObserver 防抖 + 下一帧再测行高,避免拖拽窗口时连续重算 */
722
+ scheduleVirtualScrollResizeFlush () {
723
+ if (this.virtualScrollResizeDebounceTimer != null) {
724
+ clearTimeout(this.virtualScrollResizeDebounceTimer)
725
+ }
726
+ this.virtualScrollResizeDebounceTimer = setTimeout(() => {
727
+ this.virtualScrollResizeDebounceTimer = null
728
+ if (!this.enableVirtualScroll) return
729
+ requestAnimationFrame(() => {
730
+ if (!this.enableVirtualScroll) return
731
+ this.measureRowHeight()
732
+ const c = this.getScrollContainers()[0]
733
+ if (c) {
734
+ this.applyVirtualWindowFromScroll(c)
735
+ }
736
+ })
737
+ }, 80)
738
+ },
739
+ /** 可视区上下多渲染的行数:缓解行高误差与快速滚动时的白屏 */
740
+ getVirtualOverscanRows (clientH, rh) {
741
+ const base = Math.max(1, rh || 54)
742
+ // 约 2.5 倍视口行数,至少 12 行,避免快速滑动时空窗
743
+ return Math.ceil(Math.max((clientH / base) * 2.5, 12))
744
+ },
701
745
  applyVirtualWindowFromScroll (container) {
702
746
  if (!container || !this.enableVirtualScroll) return
703
747
  const vs = this.virtualState
704
- const rh = vs.rowHeight || 54
748
+ const rh = Math.max(32, vs.rowHeight || 54)
705
749
  const scrollTop = container.scrollTop
706
750
  const clientH = container.clientHeight || 400
707
751
  const total = vs.total
708
752
  if (total <= 0) return
709
- const overscan = Math.ceil(Math.max((clientH / rh) * 1.5, 5))
753
+ const overscan = this.getVirtualOverscanRows(clientH, rh)
710
754
  const start = Math.max(0, Math.floor(scrollTop / rh) - overscan)
711
755
  const viewportRows = Math.ceil(clientH / rh) + overscan * 2
712
756
  const end = Math.min(total, start + viewportRows)
@@ -731,11 +775,25 @@ export default {
731
775
  measureRowHeight () {
732
776
  if (!this.enableVirtualScroll || !this.$el) return
733
777
  this.$nextTick(() => {
734
- const row = this.$el.querySelector('.ant-table-tbody .ant-table-row:not(.x-table-virt-spacer)')
735
- if (!row) return
736
- const h = row.getBoundingClientRect().height
737
- if (h > 0 && Math.abs(h - this.virtualState.rowHeight) > 0.5) {
738
- this.virtualState.rowHeight = h
778
+ const rows = this.$el.querySelectorAll('.ant-table-tbody tr.ant-table-row')
779
+ if (!rows || !rows.length) return
780
+ let maxH = 0
781
+ const n = Math.min(rows.length, 5)
782
+ for (let i = 0; i < n; i++) {
783
+ if (rows[i].classList.contains('x-table-virt-spacer')) continue
784
+ const h = rows[i].getBoundingClientRect().height
785
+ if (h > maxH) maxH = h
786
+ }
787
+ if (maxH > 0) {
788
+ // 取前若干行最大高度并向上取整,略低估行高会导致 start 偏大、底部留白
789
+ const next = Math.ceil(maxH)
790
+ if (Math.abs(next - this.virtualState.rowHeight) > 0.5) {
791
+ this.virtualState.rowHeight = next
792
+ const c = this.getScrollContainers()[0]
793
+ if (c) {
794
+ this.applyVirtualWindowFromScroll(c)
795
+ }
796
+ }
739
797
  }
740
798
  })
741
799
  },
@@ -747,8 +805,8 @@ export default {
747
805
  vs.start = 0
748
806
  const containers = this.getScrollContainers()
749
807
  const ch = containers[0]?.clientHeight || 400
750
- const rh = vs.rowHeight || 54
751
- const overscan = Math.ceil(Math.max((ch / rh) * 1.5, 5))
808
+ const rh = Math.max(32, vs.rowHeight || 54)
809
+ const overscan = this.getVirtualOverscanRows(ch, rh)
752
810
  const viewportRows = Math.ceil(ch / rh) + overscan * 2
753
811
  vs.end = Math.min(total, Math.max(viewportRows, 1))
754
812
  this.$nextTick(() => {
@@ -774,11 +832,7 @@ export default {
774
832
  this.virtualScrollContainers = containers
775
833
  if (typeof ResizeObserver !== 'undefined' && containers[0]) {
776
834
  this.virtualScrollResizeObserver = new ResizeObserver(() => {
777
- this.measureRowHeight()
778
- const c = this.getScrollContainers()[0]
779
- if (c) {
780
- this.applyVirtualWindowFromScroll(c)
781
- }
835
+ this.scheduleVirtualScrollResizeFlush()
782
836
  })
783
837
  this.virtualScrollResizeObserver.observe(containers[0])
784
838
  }
@@ -796,10 +850,15 @@ export default {
796
850
  this.virtualScrollResizeObserver.disconnect()
797
851
  this.virtualScrollResizeObserver = null
798
852
  }
799
- if (this.virtualScrollRafId) {
853
+ if (this.virtualScrollRafId != null) {
800
854
  cancelAnimationFrame(this.virtualScrollRafId)
801
855
  this.virtualScrollRafId = null
802
856
  }
857
+ if (this.virtualScrollResizeDebounceTimer != null) {
858
+ clearTimeout(this.virtualScrollResizeDebounceTimer)
859
+ this.virtualScrollResizeDebounceTimer = null
860
+ }
861
+ this.virtualScrollPendingTarget = null
803
862
  },
804
863
  handleRowClick (record) {
805
864
  this.$emit('rowClick', record)
@@ -824,11 +883,6 @@ export default {
824
883
  }
825
884
  },
826
885
  loadSelectedDataGen (requestParameters) {
827
- console.log('loadSelectedDataGen', {
828
- pageNo: requestParameters?.pageNo,
829
- pageSize: requestParameters?.pageSize
830
- })
831
-
832
886
  const { pageNo = 1, pageSize = 10 } = requestParameters || {}
833
887
  const startIndex = (pageNo - 1) * pageSize
834
888
  const endIndex = startIndex + pageSize
@@ -988,6 +1042,18 @@ export default {
988
1042
  :deep(.ant-pagination > li) {
989
1043
  white-space: nowrap;
990
1044
  }
1045
+ .innerTable {
1046
+ // 行编辑表格输入项样式
1047
+ :deep(.ant-form-item) {
1048
+ margin: 0;
1049
+ .ant-form-item-control-wrapper {
1050
+ width: 100%;
1051
+ }
1052
+ .ant-select {
1053
+ width: 100%;
1054
+ }
1055
+ }
1056
+ }
991
1057
  </style>
992
1058
  <style>
993
1059
  /* 多操作下拉菜单边框与阴影 */