bge-ui 1.8.8 → 1.9.0
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/dist/index.js +125 -91
- package/dist/tabs/index.vue.d.ts +8 -4
- package/package.json +1 -1
- package/src/tabs/index.vue +148 -99
package/dist/index.js
CHANGED
|
@@ -6656,43 +6656,124 @@ const _sfc_main$u = /* @__PURE__ */ defineComponent({
|
|
|
6656
6656
|
__name: "index",
|
|
6657
6657
|
props: {
|
|
6658
6658
|
type: {
|
|
6659
|
+
type: String,
|
|
6659
6660
|
default: "bordered",
|
|
6660
|
-
|
|
6661
|
+
validator: (value) => ["bordered", "pills", "pills-elevated"].includes(value)
|
|
6661
6662
|
},
|
|
6662
6663
|
modelValue: {
|
|
6663
6664
|
type: String,
|
|
6664
6665
|
default: ""
|
|
6665
6666
|
},
|
|
6666
6667
|
size: {
|
|
6668
|
+
type: String,
|
|
6667
6669
|
default: "default",
|
|
6668
|
-
|
|
6670
|
+
validator: (value) => ["default", "large", "mini"].includes(value)
|
|
6669
6671
|
}
|
|
6670
6672
|
},
|
|
6671
6673
|
emits: ["update:modelValue"],
|
|
6672
6674
|
setup(__props, { emit: __emit }) {
|
|
6675
|
+
const isBrowser = typeof window !== "undefined" && typeof document !== "undefined";
|
|
6673
6676
|
const props = __props;
|
|
6674
6677
|
const emits = __emit;
|
|
6675
6678
|
const panes = ref([]);
|
|
6679
|
+
const barStyle = ref();
|
|
6680
|
+
const navOffset = ref(0);
|
|
6681
|
+
const scrollable = ref(false);
|
|
6682
|
+
const tabsRef = ref(null);
|
|
6683
|
+
const navScrollRef = ref(null);
|
|
6676
6684
|
function addPane(pane) {
|
|
6677
6685
|
panes.value.push(pane);
|
|
6678
6686
|
}
|
|
6679
|
-
watch(() => props.modelValue, () => {
|
|
6680
|
-
setTimeout(() => {
|
|
6681
|
-
update();
|
|
6682
|
-
}, 100);
|
|
6683
|
-
});
|
|
6684
6687
|
function changeValue(value) {
|
|
6685
6688
|
emits("update:modelValue", value);
|
|
6686
|
-
|
|
6689
|
+
nextTick(() => {
|
|
6687
6690
|
update();
|
|
6688
|
-
}
|
|
6691
|
+
});
|
|
6689
6692
|
}
|
|
6693
|
+
watch(() => props.modelValue, () => {
|
|
6694
|
+
nextTick(() => {
|
|
6695
|
+
update();
|
|
6696
|
+
});
|
|
6697
|
+
});
|
|
6698
|
+
provide(tabsKey$1, {
|
|
6699
|
+
addPane,
|
|
6700
|
+
changeValue
|
|
6701
|
+
});
|
|
6702
|
+
const getBarStyle = () => {
|
|
6703
|
+
let offset2 = 0;
|
|
6704
|
+
let tabSize = 0;
|
|
6705
|
+
const sizeName = "width";
|
|
6706
|
+
if (isBrowser) {
|
|
6707
|
+
panes.value.forEach((tab, index2) => {
|
|
6708
|
+
const $el = tab.ref;
|
|
6709
|
+
if (!$el)
|
|
6710
|
+
return false;
|
|
6711
|
+
if ($el.clientWidth === 0 && index2 === 0) {
|
|
6712
|
+
nextTick(() => {
|
|
6713
|
+
update();
|
|
6714
|
+
});
|
|
6715
|
+
return false;
|
|
6716
|
+
}
|
|
6717
|
+
if (tab.value !== props.modelValue) {
|
|
6718
|
+
tab.setActive(false);
|
|
6719
|
+
return true;
|
|
6720
|
+
}
|
|
6721
|
+
tab.setActive(true);
|
|
6722
|
+
offset2 = $el["offsetLeft"];
|
|
6723
|
+
tabSize = $el["clientWidth"];
|
|
6724
|
+
return false;
|
|
6725
|
+
});
|
|
6726
|
+
} else {
|
|
6727
|
+
panes.value.forEach((tab) => {
|
|
6728
|
+
if (tab.value === props.modelValue) {
|
|
6729
|
+
tab.setActive(true);
|
|
6730
|
+
} else {
|
|
6731
|
+
tab.setActive(false);
|
|
6732
|
+
}
|
|
6733
|
+
});
|
|
6734
|
+
}
|
|
6735
|
+
return {
|
|
6736
|
+
[sizeName]: `${tabSize}px`,
|
|
6737
|
+
transform: `translateX(${offset2}px)`
|
|
6738
|
+
};
|
|
6739
|
+
};
|
|
6740
|
+
const getNavOffset = () => {
|
|
6741
|
+
if (!isBrowser)
|
|
6742
|
+
return;
|
|
6743
|
+
const navScrollElement = navScrollRef.value;
|
|
6744
|
+
if (!navScrollElement)
|
|
6745
|
+
return;
|
|
6746
|
+
panes.value.forEach((tab, index2) => {
|
|
6747
|
+
const $el = tab.ref;
|
|
6748
|
+
if (!$el)
|
|
6749
|
+
return false;
|
|
6750
|
+
if (tab.value === props.modelValue) {
|
|
6751
|
+
const currentOffset = navOffset.value;
|
|
6752
|
+
let newOffset = currentOffset;
|
|
6753
|
+
const activeTabBounding = $el.getBoundingClientRect();
|
|
6754
|
+
const navScrollBounding = navScrollElement.getBoundingClientRect();
|
|
6755
|
+
const maxOffset = navScrollBounding.width;
|
|
6756
|
+
if (activeTabBounding.left < navScrollBounding.left) {
|
|
6757
|
+
newOffset = currentOffset - (navScrollBounding.left - activeTabBounding.left);
|
|
6758
|
+
}
|
|
6759
|
+
if (activeTabBounding.right > navScrollBounding.right) {
|
|
6760
|
+
newOffset = currentOffset + activeTabBounding.right - navScrollBounding.right;
|
|
6761
|
+
}
|
|
6762
|
+
newOffset = Math.max(newOffset, 0);
|
|
6763
|
+
navOffset.value = Math.min(newOffset, maxOffset);
|
|
6764
|
+
}
|
|
6765
|
+
return false;
|
|
6766
|
+
});
|
|
6767
|
+
};
|
|
6690
6768
|
const scrollPrev = () => {
|
|
6691
|
-
if (!
|
|
6769
|
+
if (!isBrowser)
|
|
6770
|
+
return;
|
|
6771
|
+
const navScrollElement = navScrollRef.value;
|
|
6772
|
+
if (!navScrollElement)
|
|
6692
6773
|
return;
|
|
6693
6774
|
let newOffset;
|
|
6694
6775
|
const currentOffset = navOffset.value;
|
|
6695
|
-
const navScrollBounding =
|
|
6776
|
+
const navScrollBounding = navScrollElement.getBoundingClientRect();
|
|
6696
6777
|
const maxOffset = navScrollBounding.width;
|
|
6697
6778
|
panes.value.some((tab, index2) => {
|
|
6698
6779
|
const $el = tab.ref;
|
|
@@ -6700,13 +6781,16 @@ const _sfc_main$u = /* @__PURE__ */ defineComponent({
|
|
|
6700
6781
|
return false;
|
|
6701
6782
|
const activeTabBounding = $el.getBoundingClientRect();
|
|
6702
6783
|
if (activeTabBounding.left >= navScrollBounding.left && index2 > 0) {
|
|
6703
|
-
const
|
|
6704
|
-
if (
|
|
6705
|
-
|
|
6784
|
+
const prevTab = panes.value[index2 - 1];
|
|
6785
|
+
if (prevTab && prevTab.ref) {
|
|
6786
|
+
const tabBounding = prevTab.ref.getBoundingClientRect();
|
|
6787
|
+
if (index2 - 1 === 0) {
|
|
6788
|
+
newOffset = -navScrollBounding.left;
|
|
6789
|
+
return true;
|
|
6790
|
+
}
|
|
6791
|
+
newOffset = currentOffset - (navScrollBounding.left - tabBounding.left);
|
|
6706
6792
|
return true;
|
|
6707
6793
|
}
|
|
6708
|
-
newOffset = currentOffset - (navScrollBounding.left - tabBounding.left);
|
|
6709
|
-
return true;
|
|
6710
6794
|
}
|
|
6711
6795
|
});
|
|
6712
6796
|
if (newOffset) {
|
|
@@ -6715,11 +6799,14 @@ const _sfc_main$u = /* @__PURE__ */ defineComponent({
|
|
|
6715
6799
|
}
|
|
6716
6800
|
};
|
|
6717
6801
|
const scrollNext = () => {
|
|
6718
|
-
if (!
|
|
6802
|
+
if (!isBrowser)
|
|
6803
|
+
return;
|
|
6804
|
+
const navScrollElement = navScrollRef.value;
|
|
6805
|
+
if (!navScrollElement)
|
|
6719
6806
|
return;
|
|
6720
6807
|
let newOffset;
|
|
6721
6808
|
const currentOffset = navOffset.value;
|
|
6722
|
-
const navScrollBounding =
|
|
6809
|
+
const navScrollBounding = navScrollElement.getBoundingClientRect();
|
|
6723
6810
|
const maxOffset = navScrollBounding.width;
|
|
6724
6811
|
panes.value.some((tab, index2) => {
|
|
6725
6812
|
const $el = tab.ref;
|
|
@@ -6736,90 +6823,37 @@ const _sfc_main$u = /* @__PURE__ */ defineComponent({
|
|
|
6736
6823
|
navOffset.value = Math.min(newOffset, maxOffset);
|
|
6737
6824
|
}
|
|
6738
6825
|
};
|
|
6739
|
-
provide(tabsKey$1, {
|
|
6740
|
-
addPane,
|
|
6741
|
-
changeValue
|
|
6742
|
-
});
|
|
6743
|
-
const barStyle = ref();
|
|
6744
|
-
const navOffset = ref(0);
|
|
6745
|
-
const scrollable = ref(false);
|
|
6746
|
-
const getBarStyle = () => {
|
|
6747
|
-
let offset2 = 0;
|
|
6748
|
-
let tabSize = 0;
|
|
6749
|
-
const sizeName = "width";
|
|
6750
|
-
panes.value.forEach((tab, index2) => {
|
|
6751
|
-
const $el = tab.ref;
|
|
6752
|
-
if (!$el)
|
|
6753
|
-
return false;
|
|
6754
|
-
if ($el.clientWidth === 0 && index2 === 0) {
|
|
6755
|
-
setTimeout(() => {
|
|
6756
|
-
update();
|
|
6757
|
-
}, 100);
|
|
6758
|
-
return false;
|
|
6759
|
-
}
|
|
6760
|
-
if (tab.value !== props.modelValue) {
|
|
6761
|
-
tab.setActive(false);
|
|
6762
|
-
return true;
|
|
6763
|
-
}
|
|
6764
|
-
tab.setActive(true);
|
|
6765
|
-
offset2 = $el["offsetLeft"];
|
|
6766
|
-
tabSize = $el["clientWidth"];
|
|
6767
|
-
return false;
|
|
6768
|
-
});
|
|
6769
|
-
return {
|
|
6770
|
-
[sizeName]: `${tabSize}px`,
|
|
6771
|
-
transform: `translateX(${offset2}px)`
|
|
6772
|
-
};
|
|
6773
|
-
};
|
|
6774
|
-
const navScrollRef = ref();
|
|
6775
|
-
const getNavOffset = () => {
|
|
6776
|
-
if (!navScrollRef.value)
|
|
6777
|
-
return;
|
|
6778
|
-
panes.value.forEach((tab, index2) => {
|
|
6779
|
-
const $el = tab.ref;
|
|
6780
|
-
if (!$el)
|
|
6781
|
-
return false;
|
|
6782
|
-
if (tab.value === props.modelValue) {
|
|
6783
|
-
const currentOffset = navOffset.value;
|
|
6784
|
-
let newOffset = currentOffset;
|
|
6785
|
-
const activeTabBounding = $el.getBoundingClientRect();
|
|
6786
|
-
const navScrollBounding = navScrollRef.value.getBoundingClientRect();
|
|
6787
|
-
const maxOffset = navScrollBounding.width;
|
|
6788
|
-
if (activeTabBounding.left < navScrollBounding.left) {
|
|
6789
|
-
newOffset = currentOffset - (navScrollBounding.left - activeTabBounding.left);
|
|
6790
|
-
}
|
|
6791
|
-
if (activeTabBounding.right > navScrollBounding.right) {
|
|
6792
|
-
newOffset = currentOffset + activeTabBounding.right - navScrollBounding.right;
|
|
6793
|
-
}
|
|
6794
|
-
newOffset = Math.max(newOffset, 0);
|
|
6795
|
-
navOffset.value = Math.min(newOffset, maxOffset);
|
|
6796
|
-
}
|
|
6797
|
-
return false;
|
|
6798
|
-
});
|
|
6799
|
-
};
|
|
6800
6826
|
const panesStyle = computed(() => {
|
|
6801
6827
|
return {
|
|
6802
6828
|
transform: `translateX(-${navOffset.value}px)`
|
|
6803
6829
|
};
|
|
6804
6830
|
});
|
|
6805
6831
|
const update = () => {
|
|
6806
|
-
if (
|
|
6807
|
-
const
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6832
|
+
if (isBrowser) {
|
|
6833
|
+
const navScrollElement = navScrollRef.value;
|
|
6834
|
+
if (panes.value.length > 0 && navScrollElement) {
|
|
6835
|
+
const lastPane = panes.value[panes.value.length - 1];
|
|
6836
|
+
const firstPane = panes.value[0];
|
|
6837
|
+
if (lastPane && lastPane.ref && firstPane && firstPane.ref) {
|
|
6838
|
+
const right2 = lastPane.ref.getBoundingClientRect().right;
|
|
6839
|
+
const left2 = firstPane.ref.getBoundingClientRect().left;
|
|
6840
|
+
const navScrollBounding = navScrollElement.getBoundingClientRect();
|
|
6841
|
+
if (left2 < navScrollBounding.left) {
|
|
6842
|
+
scrollable.value = true;
|
|
6843
|
+
} else if (right2 > navScrollBounding.right) {
|
|
6844
|
+
scrollable.value = true;
|
|
6845
|
+
} else {
|
|
6846
|
+
scrollable.value = false;
|
|
6847
|
+
}
|
|
6848
|
+
}
|
|
6816
6849
|
}
|
|
6817
6850
|
}
|
|
6818
6851
|
barStyle.value = getBarStyle();
|
|
6819
6852
|
getNavOffset();
|
|
6820
6853
|
};
|
|
6821
|
-
|
|
6822
|
-
|
|
6854
|
+
if (isBrowser) {
|
|
6855
|
+
useResizeObserver(tabsRef, update);
|
|
6856
|
+
}
|
|
6823
6857
|
onMounted(() => {
|
|
6824
6858
|
update();
|
|
6825
6859
|
});
|
package/dist/tabs/index.vue.d.ts
CHANGED
|
@@ -1,30 +1,34 @@
|
|
|
1
1
|
declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
|
|
2
2
|
type: {
|
|
3
|
+
type: StringConstructor;
|
|
3
4
|
default: string;
|
|
4
|
-
value: string
|
|
5
|
+
validator: (value: string) => boolean;
|
|
5
6
|
};
|
|
6
7
|
modelValue: {
|
|
7
8
|
type: StringConstructor;
|
|
8
9
|
default: string;
|
|
9
10
|
};
|
|
10
11
|
size: {
|
|
12
|
+
type: StringConstructor;
|
|
11
13
|
default: string;
|
|
12
|
-
value: string
|
|
14
|
+
validator: (value: string) => boolean;
|
|
13
15
|
};
|
|
14
16
|
}, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
15
17
|
"update:modelValue": (...args: any[]) => void;
|
|
16
18
|
}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
|
|
17
19
|
type: {
|
|
20
|
+
type: StringConstructor;
|
|
18
21
|
default: string;
|
|
19
|
-
value: string
|
|
22
|
+
validator: (value: string) => boolean;
|
|
20
23
|
};
|
|
21
24
|
modelValue: {
|
|
22
25
|
type: StringConstructor;
|
|
23
26
|
default: string;
|
|
24
27
|
};
|
|
25
28
|
size: {
|
|
29
|
+
type: StringConstructor;
|
|
26
30
|
default: string;
|
|
27
|
-
value: string
|
|
31
|
+
validator: (value: string) => boolean;
|
|
28
32
|
};
|
|
29
33
|
}>> & {
|
|
30
34
|
"onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
|
package/package.json
CHANGED
package/src/tabs/index.vue
CHANGED
|
@@ -12,130 +12,110 @@
|
|
|
12
12
|
</template>
|
|
13
13
|
<script setup lang="ts">
|
|
14
14
|
import { useResizeObserver } from "@vueuse/core"
|
|
15
|
-
import { provide, ref, onMounted, watch, computed,
|
|
15
|
+
import { provide, ref, onMounted, watch, computed, nextTick } from "vue"
|
|
16
|
+
|
|
17
|
+
// 检测是否在浏览器环境中
|
|
18
|
+
const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined'
|
|
16
19
|
defineOptions({
|
|
17
20
|
name: "Tabs",
|
|
18
21
|
})
|
|
19
22
|
|
|
20
23
|
const props = defineProps({
|
|
21
24
|
type: {
|
|
25
|
+
type: String,
|
|
22
26
|
default: 'bordered',
|
|
23
|
-
value: ['bordered', 'pills', 'pills-elevated']
|
|
27
|
+
validator: (value: string) => ['bordered', 'pills', 'pills-elevated'].includes(value)
|
|
24
28
|
},
|
|
25
29
|
modelValue: {
|
|
26
30
|
type: String,
|
|
27
31
|
default: '',
|
|
28
32
|
},
|
|
29
33
|
size: {
|
|
34
|
+
type: String,
|
|
30
35
|
default: 'default',
|
|
31
|
-
value: ['default', 'large', 'mini']
|
|
36
|
+
validator: (value: string) => ['default', 'large', 'mini'].includes(value)
|
|
32
37
|
}
|
|
33
38
|
})
|
|
34
39
|
|
|
35
40
|
const emits = defineEmits(['update:modelValue'])
|
|
36
41
|
|
|
37
|
-
|
|
42
|
+
// 类型定义
|
|
43
|
+
interface TabPane {
|
|
44
|
+
ref: HTMLElement | null
|
|
45
|
+
value: string
|
|
46
|
+
setActive: (active: boolean) => void
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 状态管理
|
|
50
|
+
const panes = ref<TabPane[]>([])
|
|
51
|
+
const barStyle = ref<{ width: string; transform: string } | undefined>()
|
|
52
|
+
const navOffset = ref(0)
|
|
53
|
+
const scrollable = ref(false)
|
|
54
|
+
|
|
55
|
+
// 引用
|
|
56
|
+
const tabsRef = ref<HTMLElement | null>(null)
|
|
57
|
+
const navScrollRef = ref<HTMLElement | null>(null)
|
|
38
58
|
|
|
39
|
-
|
|
59
|
+
// 方法
|
|
60
|
+
function addPane(pane: TabPane) {
|
|
40
61
|
panes.value.push(pane)
|
|
41
62
|
}
|
|
42
63
|
|
|
43
|
-
watch(() => props.modelValue, () => {
|
|
44
|
-
setTimeout(() => {
|
|
45
|
-
update()
|
|
46
|
-
}, 100)
|
|
47
|
-
})
|
|
48
|
-
|
|
49
64
|
function changeValue(value: string) {
|
|
50
65
|
emits('update:modelValue', value)
|
|
51
|
-
|
|
66
|
+
nextTick(() => {
|
|
52
67
|
update()
|
|
53
|
-
}, 100)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const scrollPrev = () => {
|
|
57
|
-
if (!navScrollRef.value) return
|
|
58
|
-
let newOffset
|
|
59
|
-
const currentOffset = navOffset.value
|
|
60
|
-
const navScrollBounding = navScrollRef.value.getBoundingClientRect()
|
|
61
|
-
const maxOffset = navScrollBounding.width
|
|
62
|
-
panes.value.some((tab: any, index: number) => {
|
|
63
|
-
const $el = tab.ref as HTMLElement
|
|
64
|
-
if (!$el) return false
|
|
65
|
-
const activeTabBounding = $el.getBoundingClientRect()
|
|
66
|
-
if (activeTabBounding.left >= navScrollBounding.left && index > 0) {
|
|
67
|
-
const tabBounding = panes.value[index - 1].ref.getBoundingClientRect()
|
|
68
|
-
if (index - 1 === 0) {
|
|
69
|
-
newOffset = -navScrollBounding.left
|
|
70
|
-
return true
|
|
71
|
-
}
|
|
72
|
-
newOffset =
|
|
73
|
-
currentOffset - (navScrollBounding.left - tabBounding.left)
|
|
74
|
-
return true
|
|
75
|
-
}
|
|
76
68
|
})
|
|
77
|
-
if (newOffset) {
|
|
78
|
-
newOffset = Math.max(newOffset, 0)
|
|
79
|
-
navOffset.value = Math.min(newOffset, maxOffset)
|
|
80
|
-
}
|
|
81
69
|
}
|
|
82
70
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const currentOffset = navOffset.value
|
|
87
|
-
const navScrollBounding = navScrollRef.value.getBoundingClientRect()
|
|
88
|
-
const maxOffset = navScrollBounding.width
|
|
89
|
-
panes.value.some((tab: any, index: number) => {
|
|
90
|
-
const $el = tab.ref as HTMLElement
|
|
91
|
-
if (!$el) return false
|
|
92
|
-
const activeTabBounding = $el.getBoundingClientRect()
|
|
93
|
-
if (activeTabBounding.right > navScrollBounding.right) {
|
|
94
|
-
newOffset =
|
|
95
|
-
currentOffset + activeTabBounding.right - navScrollBounding.right
|
|
96
|
-
return true
|
|
97
|
-
}
|
|
71
|
+
watch(() => props.modelValue, () => {
|
|
72
|
+
nextTick(() => {
|
|
73
|
+
update()
|
|
98
74
|
})
|
|
99
|
-
|
|
100
|
-
newOffset = Math.max(newOffset, 0)
|
|
101
|
-
navOffset.value = Math.min(newOffset, maxOffset)
|
|
102
|
-
}
|
|
103
|
-
}
|
|
75
|
+
})
|
|
104
76
|
|
|
105
77
|
const tabsKey = 'bge-tabs-context'
|
|
106
78
|
provide(tabsKey, {
|
|
107
79
|
addPane,
|
|
108
80
|
changeValue
|
|
109
81
|
})
|
|
110
|
-
const barStyle = ref<any>()
|
|
111
|
-
const navOffset = ref(0)
|
|
112
|
-
const scrollable = ref(false)
|
|
113
82
|
|
|
114
|
-
const getBarStyle
|
|
83
|
+
const getBarStyle = (): { width: string; transform: string } => {
|
|
115
84
|
let offset = 0
|
|
116
85
|
let tabSize = 0
|
|
117
86
|
|
|
118
87
|
const sizeName = 'width'
|
|
119
88
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
tab.
|
|
131
|
-
|
|
132
|
-
|
|
89
|
+
if (isBrowser) {
|
|
90
|
+
panes.value.forEach((tab: TabPane, index: number) => {
|
|
91
|
+
const $el = tab.ref
|
|
92
|
+
if (!$el) return false
|
|
93
|
+
if ($el.clientWidth === 0 && index === 0) {
|
|
94
|
+
nextTick(() => {
|
|
95
|
+
update()
|
|
96
|
+
})
|
|
97
|
+
return false
|
|
98
|
+
}
|
|
99
|
+
if (tab.value !== props.modelValue) {
|
|
100
|
+
tab.setActive(false)
|
|
101
|
+
return true
|
|
102
|
+
}
|
|
133
103
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
104
|
+
tab.setActive(true)
|
|
105
|
+
offset = $el['offsetLeft']
|
|
106
|
+
tabSize = $el['clientWidth']
|
|
107
|
+
return false
|
|
108
|
+
})
|
|
109
|
+
} else {
|
|
110
|
+
// 服务端渲染时,为活动标签设置默认样式
|
|
111
|
+
panes.value.forEach((tab: TabPane) => {
|
|
112
|
+
if (tab.value === props.modelValue) {
|
|
113
|
+
tab.setActive(true)
|
|
114
|
+
} else {
|
|
115
|
+
tab.setActive(false)
|
|
116
|
+
}
|
|
117
|
+
})
|
|
118
|
+
}
|
|
139
119
|
|
|
140
120
|
return {
|
|
141
121
|
[sizeName]: `${tabSize}px`,
|
|
@@ -143,17 +123,18 @@ const getBarStyle: any = () => {
|
|
|
143
123
|
}
|
|
144
124
|
}
|
|
145
125
|
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
126
|
+
const getNavOffset = () => {
|
|
127
|
+
if (!isBrowser) return
|
|
128
|
+
const navScrollElement = navScrollRef.value
|
|
129
|
+
if (!navScrollElement) return
|
|
130
|
+
panes.value.forEach((tab: TabPane, index: number) => {
|
|
131
|
+
const $el = tab.ref
|
|
151
132
|
if (!$el) return false
|
|
152
133
|
if (tab.value === props.modelValue) {
|
|
153
134
|
const currentOffset = navOffset.value
|
|
154
135
|
let newOffset = currentOffset
|
|
155
136
|
const activeTabBounding = $el.getBoundingClientRect()
|
|
156
|
-
const navScrollBounding =
|
|
137
|
+
const navScrollBounding = navScrollElement.getBoundingClientRect()
|
|
157
138
|
const maxOffset = navScrollBounding.width
|
|
158
139
|
if (activeTabBounding.left < navScrollBounding.left) {
|
|
159
140
|
newOffset =
|
|
@@ -169,29 +150,97 @@ const getNavOffset: any = () => {
|
|
|
169
150
|
return false
|
|
170
151
|
})
|
|
171
152
|
}
|
|
153
|
+
|
|
154
|
+
const scrollPrev = () => {
|
|
155
|
+
if (!isBrowser) return
|
|
156
|
+
const navScrollElement = navScrollRef.value
|
|
157
|
+
if (!navScrollElement) return
|
|
158
|
+
let newOffset
|
|
159
|
+
const currentOffset = navOffset.value
|
|
160
|
+
const navScrollBounding = navScrollElement.getBoundingClientRect()
|
|
161
|
+
const maxOffset = navScrollBounding.width
|
|
162
|
+
panes.value.some((tab: TabPane, index: number) => {
|
|
163
|
+
const $el = tab.ref
|
|
164
|
+
if (!$el) return false
|
|
165
|
+
const activeTabBounding = $el.getBoundingClientRect()
|
|
166
|
+
if (activeTabBounding.left >= navScrollBounding.left && index > 0) {
|
|
167
|
+
const prevTab = panes.value[index - 1]
|
|
168
|
+
if (prevTab && prevTab.ref) {
|
|
169
|
+
const tabBounding = prevTab.ref.getBoundingClientRect()
|
|
170
|
+
if (index - 1 === 0) {
|
|
171
|
+
newOffset = -navScrollBounding.left
|
|
172
|
+
return true
|
|
173
|
+
}
|
|
174
|
+
newOffset =
|
|
175
|
+
currentOffset - (navScrollBounding.left - tabBounding.left)
|
|
176
|
+
return true
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
})
|
|
180
|
+
if (newOffset) {
|
|
181
|
+
newOffset = Math.max(newOffset, 0)
|
|
182
|
+
navOffset.value = Math.min(newOffset, maxOffset)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const scrollNext = () => {
|
|
187
|
+
if (!isBrowser) return
|
|
188
|
+
const navScrollElement = navScrollRef.value
|
|
189
|
+
if (!navScrollElement) return
|
|
190
|
+
let newOffset
|
|
191
|
+
const currentOffset = navOffset.value
|
|
192
|
+
const navScrollBounding = navScrollElement.getBoundingClientRect()
|
|
193
|
+
const maxOffset = navScrollBounding.width
|
|
194
|
+
panes.value.some((tab: TabPane, index: number) => {
|
|
195
|
+
const $el = tab.ref
|
|
196
|
+
if (!$el) return false
|
|
197
|
+
const activeTabBounding = $el.getBoundingClientRect()
|
|
198
|
+
if (activeTabBounding.right > navScrollBounding.right) {
|
|
199
|
+
newOffset =
|
|
200
|
+
currentOffset + activeTabBounding.right - navScrollBounding.right
|
|
201
|
+
return true
|
|
202
|
+
}
|
|
203
|
+
})
|
|
204
|
+
if (newOffset) {
|
|
205
|
+
newOffset = Math.max(newOffset, 0)
|
|
206
|
+
navOffset.value = Math.min(newOffset, maxOffset)
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
172
210
|
const panesStyle = computed(() => {
|
|
173
211
|
return {
|
|
174
212
|
transform: `translateX(-${navOffset.value}px)`,
|
|
175
213
|
}
|
|
176
214
|
})
|
|
215
|
+
|
|
177
216
|
const update = () => {
|
|
178
|
-
if (
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
217
|
+
if (isBrowser) {
|
|
218
|
+
const navScrollElement = navScrollRef.value
|
|
219
|
+
if (panes.value.length > 0 && navScrollElement) {
|
|
220
|
+
const lastPane = panes.value[panes.value.length - 1]
|
|
221
|
+
const firstPane = panes.value[0]
|
|
222
|
+
if (lastPane && lastPane.ref && firstPane && firstPane.ref) {
|
|
223
|
+
const right = lastPane.ref.getBoundingClientRect().right
|
|
224
|
+
const left = firstPane.ref.getBoundingClientRect().left
|
|
225
|
+
const navScrollBounding = navScrollElement.getBoundingClientRect()
|
|
226
|
+
if (left < navScrollBounding.left) {
|
|
227
|
+
scrollable.value = true
|
|
228
|
+
} else if (right > navScrollBounding.right) {
|
|
229
|
+
scrollable.value = true
|
|
230
|
+
} else {
|
|
231
|
+
scrollable.value = false
|
|
232
|
+
}
|
|
233
|
+
}
|
|
188
234
|
}
|
|
189
235
|
}
|
|
190
236
|
barStyle.value = getBarStyle()
|
|
191
237
|
getNavOffset()
|
|
192
238
|
}
|
|
193
|
-
|
|
194
|
-
|
|
239
|
+
|
|
240
|
+
// 仅在浏览器环境中使用 ResizeObserver
|
|
241
|
+
if (isBrowser) {
|
|
242
|
+
useResizeObserver(tabsRef, update)
|
|
243
|
+
}
|
|
195
244
|
|
|
196
245
|
onMounted(() => {
|
|
197
246
|
update()
|