centaline-data-driven-v3 0.1.41 → 0.1.42

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": "centaline-data-driven-v3",
3
- "version": "0.1.41",
3
+ "version": "0.1.42",
4
4
  "private": false,
5
5
  "description": "centaline-data-driven-v3",
6
6
  "main": "dist/centaline-data-driven-v3.umd.js",
@@ -102,7 +102,7 @@
102
102
  <template #title>
103
103
  <i class="sign"></i>
104
104
  <span :class="[item.required ? 'requiredLabel' : '']">{{ item.controlLabel
105
- }}</span>
105
+ }}</span>
106
106
  <span v-html="item.sufLabel1"></span>
107
107
  </template>
108
108
 
@@ -293,6 +293,7 @@ const refTip = ref()
293
293
  const tipTopHight = ref(0)
294
294
  const tabTopHight = ref(0)
295
295
  const refTabs = ref()
296
+ const translateX = ref(0)
296
297
 
297
298
  const qrtimer1 = ref(null)
298
299
  const qrtimer2 = ref(null)
@@ -324,6 +325,7 @@ onUpdated(() => {
324
325
  onDeactivated(() => {
325
326
  downloadUrl.value = ''
326
327
  })
328
+
327
329
  onMounted(() => {
328
330
  setCss();
329
331
  if (refForm.value) {
@@ -337,6 +339,13 @@ onMounted(() => {
337
339
  tabTopHight.value = tipTopHight.value;
338
340
  }
339
341
  }
342
+ nextTick(() => {
343
+
344
+ setTimeout(() => {
345
+ attachScrollButtonListeners()
346
+ }, 1000);
347
+
348
+ });
340
349
  })
341
350
  init()
342
351
  //初始化数据
@@ -767,59 +776,73 @@ async function tabClick(pane: TabsPaneContext) {
767
776
  if (props.openType == 'detail') {
768
777
  window.localStorage.setItem(tabActiveNameKey.value, model.value.collapse[event.index].fieldName1);//存储
769
778
  }
770
- // await nextTick() // 等 DOM 更新完再取节点
771
- // debugger
772
- // const navWrapScroll = document.querySelector('.el-tabs__nav-scroll') as HTMLElement
773
- // const firstTab = document.querySelector('.el-tabs__item') as HTMLElement
774
- // if (!navWrapScroll || !firstTab) return
775
-
776
- // // 第一个 tab 的“右边”到容器左边的距离
777
- // const firstRight = firstTab.getBoundingClientRect().right
778
- // const wrapLeft = navWrapScroll.getBoundingClientRect().left
779
-
780
- // // 只要右边还在容器左边之外,就说明还没进来
781
- // const firstVisible = firstRight >= wrapLeft
782
- // const visibleCount = getVisibleTabCount();
783
- // if (pane.index < visibleCount / 2 && firstVisible) {
784
- // return;
785
- // }
786
-
787
- // const navWrap = document.querySelector('.el-tabs__nav') as HTMLElement
788
- // const activeBtn = document.querySelector(
789
- // `.el-tabs__item#tab-${pane.paneName}`
790
- // ) as HTMLElement
791
-
792
- // if (!navWrapScroll || !navWrap || !activeBtn) return
793
-
794
- // const wrapWidth = navWrapScroll.clientWidth
795
- // const btnLeft = activeBtn.offsetLeft
796
- // const btnWidth = activeBtn.offsetWidth
797
-
798
- // /* 想让 activeBtn 居中,需要整个 navWrap 向左移动的距离 */
799
- // const dx = (wrapWidth - btnWidth) / 2 - btnLeft
779
+ await nextTick() // 等 DOM 更新完再取节点
780
+ const navWrapScroll = document.querySelector('.el-tabs__nav-scroll') as HTMLElement
781
+ const navWrap = document.querySelector('.el-tabs__nav') as HTMLElement
782
+ const activeBtn = document.querySelector(`.el-tabs__item#tab-${pane.paneName}`) as HTMLElement
783
+ if (!navWrapScroll || !navWrap || !activeBtn) return
784
+ const visibleCount = getVisibleTabCount()
785
+ if (pane.index <= visibleCount / 2) {
786
+ setTimeout(() => {
787
+ navWrap.style.transition = 'transform .3s ease-out'
788
+ navWrap.style.transform = 'translateX(0px)'
789
+ }, 50);
790
+ translateX.value = 0
791
+ return
792
+ }
793
+ const allTabs = Array.from(navWrap.querySelectorAll('.el-tabs__item')) as HTMLElement[]
794
+ const total = allTabs.length
795
+ if (pane.index >= total - 5) {
796
+ const lastTab = allTabs[total - 1]
797
+ const wrapWidth = navWrapScroll.clientWidth
798
+ const lastWidth = lastTab.offsetWidth
799
+ const lastRight = lastTab.offsetLeft + lastWidth // 最后一个右边到 nav 左边的距离
800
+ const needShift = wrapWidth - lastRight // 负值,让右边对齐容器右边
801
+ setTimeout(() => {
802
+ navWrap.style.transition = 'transform .3s ease-out'
803
+ navWrap.style.transform = `translateX(${needShift}px)`
804
+ }, 50);
805
+ translateX.value = needShift
806
+ return
807
+ }
808
+ /* ---------- 1. 初始状态:还没滑过 ---------- */
809
+ const neverSlid = navWrap.style.transform == 'translateX(0px)'
800
810
 
801
- // setTimeout(() => {
802
- // navWrap.style.transition = 'transform .3s ease-out'
803
- // navWrap.style.transform = `translateX(${dx}px)`
804
- // }, 50);
811
+ if (neverSlid && pane.index >= visibleCount / 2) {
812
+ /* 第一次往后走,直接允许滑动 走居中逻辑 */
813
+ const wrapWidth = navWrapScroll.clientWidth
814
+ const btnLeft = activeBtn.offsetLeft
815
+ const btnWidth = activeBtn.offsetWidth
816
+ const dx = (wrapWidth - btnWidth) / 2 - btnLeft
817
+ setTimeout(() => {
818
+ navWrap.style.transition = 'transform .3s ease-out'
819
+ navWrap.style.transform = `translateX(${dx}px)`
820
+ }, 50);
821
+ translateX.value = dx
822
+ return
823
+ }
805
824
 
806
- // const navWrapScroll = document.querySelector('.el-tabs__nav-scroll') as HTMLElement
807
- // const navWrap = document.querySelector('.el-tabs__nav') as HTMLElement
808
- // const activeBtn = document.querySelector(
809
- // `.el-tabs__item#tab-${pane.paneName}`
810
- // ) as HTMLElement
811
- // if (!navWrapScroll || !activeBtn) return
825
+ /* ---------- 2. 已经滑过 恢复两端贴边即锁死 ---------- */
826
+ const firstTab = navWrap.querySelector('.el-tabs__item') as HTMLElement
827
+ const lastTab = navWrap.querySelector('.el-tabs__item:last-child') as HTMLElement
828
+ if (!firstTab || !lastTab) return
812
829
 
813
- // const wrapWidth = navWrapScroll.clientWidth
814
- // const btnLeft = activeBtn.offsetLeft
815
- // const btnWidth = activeBtn.offsetWidth
830
+ const lastAtRight = lastTab.getBoundingClientRect().right <= navWrapScroll.getBoundingClientRect().right
816
831
 
817
- // // 滚动到“元素中心 - 容器半宽”的位置,就能居中
818
- // navWrapScroll.scrollTo({
819
- // left: btnLeft - (wrapWidth - btnWidth) / 2,
820
- // behavior: 'smooth'
821
- // })
832
+ if ((lastAtRight && pane.index >= total - 5)) {
833
+ return
834
+ } // 已贴边,不滑
822
835
 
836
+ /* 需要居中 */
837
+ const wrapWidth = navWrapScroll.clientWidth
838
+ const btnLeft = activeBtn.offsetLeft
839
+ const btnWidth = activeBtn.offsetWidth
840
+ const dx = (wrapWidth - btnWidth) / 2 - btnLeft
841
+ translateX.value = dx
842
+ setTimeout(() => {
843
+ navWrap.style.transition = 'transform .3s ease-out'
844
+ navWrap.style.transform = `translateX(${dx}px)`
845
+ }, 50);
823
846
  }
824
847
  /** 返回当前屏幕完全可见的 tab 个数 */
825
848
  function getVisibleTabCount(): number {
@@ -839,7 +862,137 @@ function getVisibleTabCount(): number {
839
862
  const avgWidth = totalWidth / allTabs.length
840
863
  return Math.floor(wrapWidth / avgWidth)
841
864
  }
865
+ function attachScrollButtonListeners() {
866
+ if (refTabs.value) {
867
+ const tabsEl = refTabs.value.$el
868
+
869
+ // 监听原生左右箭头点击事件(事件委托)
870
+ const arrowLeft = tabsEl.querySelector('.el-tabs__nav-prev')
871
+ const arrowRight = tabsEl.querySelector('.el-tabs__nav-next')
872
+
873
+ if (arrowLeft) {
874
+ // 1. 移除所有已有事件监听(保险)
875
+ const newArrowLeft = arrowLeft.cloneNode(true)
876
+ arrowLeft.parentNode.replaceChild(newArrowLeft, arrowLeft)
877
+ // 2. 添加自定义事件,彻底阻断原生行为
878
+ newArrowLeft.addEventListener('click', handleArrowLeft, { capture: true })
879
+ newArrowLeft.addEventListener('mousedown', (e) => e.preventDefault(), { capture: true })
880
+ arrowLeft.addEventListener('click', handleArrowLeft)
881
+ }
882
+ if (arrowRight) {
883
+ // 1. 移除所有已有事件监听(保险)
884
+ const newArrowRight = arrowRight.cloneNode(true)
885
+ arrowRight.parentNode.replaceChild(newArrowRight, arrowRight)
886
+ // 2. 添加自定义事件,彻底阻断原生行为
887
+ newArrowRight.addEventListener('click', handleArrowRight, { capture: true })
888
+ newArrowRight.addEventListener('mousedown', (e) => e.preventDefault(), { capture: true })
889
+ }
890
+ }
891
+ }
892
+ function handleArrowLeft(e) {
893
+ // 彻底阻断原生事件传播和默认行为
894
+ e.stopImmediatePropagation()
895
+ e.stopPropagation()
896
+ e.preventDefault()
897
+ scrollTabs('left')
898
+ }
899
+ function handleArrowRight(e) {
900
+ // 彻底阻断原生事件传播和默认行为
901
+ e.stopImmediatePropagation()
902
+ e.stopPropagation()
903
+ e.preventDefault()
904
+ scrollTabs('right')
905
+ }
906
+ function scrollTabs(direction) {
907
+ const navWrapScroll = document.querySelector('.el-tabs__nav-scroll') as HTMLElement
908
+ const navWrap = document.querySelector('.el-tabs__nav') as HTMLElement
909
+ if (!navWrapScroll || !navWrap) return
910
+ const allTabs = Array.from(navWrap.querySelectorAll('.el-tabs__item')) as HTMLElement[]
911
+ if (!allTabs.length) return
912
+ // 找到当前第一个可见的标签索引
913
+ const firstVisibleIndex = getFirstVisibleTabIndex(allTabs)
914
+ if (direction == 'left') {
915
+ if (translateX.value >= 0) {
916
+ translateX.value = 0
917
+ setTimeout(() => {
918
+ navWrap.style.transition = 'transform .3s ease-out'
919
+ navWrap.style.transform = `translateX(${translateX.value}px)`
920
+ }, 50);
921
+ return
922
+ }
923
+
924
+ // 找到当前第一个可见的标签索引
925
+ const firstVisibleIndex = getFirstVisibleTabIndex(allTabs)
926
+ // 计算上一个标签的宽度
927
+ const prevTabWidth = getFirstVisibleTabIndex(allTabs) > 0 ? getTabWidth(allTabs, firstVisibleIndex - 1) : 0
928
+ if (prevTabWidth == 0) {
929
+ translateX.value = 0
930
+ }
931
+ else {
932
+ // 更新偏移量(向右平移)
933
+ translateX.value += prevTabWidth
934
+ }
935
+
936
+ setTimeout(() => {
937
+ navWrap.style.transition = 'transform .3s ease-out'
938
+ navWrap.style.transform = `translateX(${translateX.value}px)`
939
+ }, 50);
940
+ }
941
+ else if (direction == 'right') {
842
942
 
943
+ // 判断最后一个标签是否已靠右,若是则禁止滚动
944
+ if (isLastTabAlignedRight(navWrapScroll, navWrap)) {
945
+ return
946
+ }
947
+
948
+ // 计算下一个标签的宽度
949
+ const nextTabWidth = getTabWidth(allTabs, firstVisibleIndex)
950
+ // 更新偏移量(向左平移)
951
+ translateX.value -= nextTabWidth
952
+ setTimeout(() => {
953
+ navWrap.style.transition = 'transform .3s ease-out'
954
+ navWrap.style.transform = `translateX(${translateX.value}px)`
955
+ }, 50);
956
+ }
957
+ }
958
+ // 获取当前第一个可见的标签索引
959
+ const getFirstVisibleTabIndex = (allTabs) => {
960
+ const scrollLeft = Math.abs(translateX.value)
961
+ let sumWidth = 0
962
+ for (let i = 0; i < allTabs.length; i++) {
963
+ sumWidth += getTabWidth(allTabs, i)
964
+ if (sumWidth > scrollLeft) {
965
+ return i
966
+ }
967
+ }
968
+ return 0
969
+ }
970
+ // 计算单个标签宽度(包含间距)
971
+ const getTabWidth = (allTabs, index) => {
972
+ if (!allTabs[index]) return 0
973
+ const tab = allTabs[index]
974
+ // 获取标签的实际宽度(包含内边距、边框)
975
+ const width = tab.offsetWidth
976
+ // 获取标签的左右外边距(ElementPlus 默认有间距)
977
+ const style = window.getComputedStyle(tab)
978
+ const marginLeft = parseFloat(style.marginLeft) || 0
979
+ const marginRight = parseFloat(style.marginRight) || 0
980
+ return width + marginLeft + marginRight
981
+ }
982
+ // 检查最后一个标签是否已靠最右侧
983
+ const isLastTabAlignedRight = (navWrapScroll, navWrap) => {
984
+
985
+ // 滚动容器的可视宽度
986
+ const containerWidth = navWrapScroll.clientWidth
987
+ // 所有标签的总宽度
988
+ const totalTabsWidth = navWrap.scrollWidth
989
+ // 当前向左偏移的总距离(绝对值)
990
+ const currentOffset = Math.abs(translateX.value)
991
+
992
+ // 最后一个标签靠右的判定条件:偏移量 + 容器宽度 ≥ 总标签宽度
993
+ // 预留2px误差,避免因像素精度问题导致判断失误
994
+ return (currentOffset + containerWidth) >= (totalTabsWidth - 2)
995
+ }
843
996
 
844
997
  </script>
845
998