|
@@ -17,50 +17,45 @@
|
|
|
height: theme.resolveSize(props.height),
|
|
height: theme.resolveSize(props.height),
|
|
|
}"
|
|
}"
|
|
|
>
|
|
>
|
|
|
- <template
|
|
|
|
|
|
|
+ <FlexView
|
|
|
v-for="(tab, index) in filteredTabs"
|
|
v-for="(tab, index) in filteredTabs"
|
|
|
|
|
+ :ref="(ref) => tabsRefs[index] = ref"
|
|
|
:key="index"
|
|
:key="index"
|
|
|
|
|
+ direction="row"
|
|
|
|
|
+ :pressedColor="themedUnderlayColor"
|
|
|
|
|
+ :innerStyle="itemStyle"
|
|
|
|
|
+ :width="itemWidthArr[index].width > 0 ?
|
|
|
|
|
+ theme.resolveSize(itemWidthArr[index].width - tabPaddingHorizontal * 2) :
|
|
|
|
|
+ undefined"
|
|
|
|
|
+ :touchable="!tab.disabled"
|
|
|
|
|
+ :flexShrink="0"
|
|
|
|
|
+ :padding="[ 0, tabPaddingHorizontal ]"
|
|
|
|
|
+ center
|
|
|
|
|
+ innerClass="tab-item"
|
|
|
|
|
+ @click="onTabClick(index)"
|
|
|
>
|
|
>
|
|
|
<slot name="tab"
|
|
<slot name="tab"
|
|
|
:tab="tab"
|
|
:tab="tab"
|
|
|
:index="index"
|
|
:index="index"
|
|
|
:width="itemWidthArr[index].width"
|
|
:width="itemWidthArr[index].width"
|
|
|
:active="currentIndex == index"
|
|
:active="currentIndex == index"
|
|
|
- :onClick="() => onTabClick(index)"
|
|
|
|
|
- :tabId="`${idPrefix}${index}`"
|
|
|
|
|
>
|
|
>
|
|
|
- <FlexView
|
|
|
|
|
- :innerId="`${idPrefix}${index}`"
|
|
|
|
|
- direction="row"
|
|
|
|
|
- :pressedColor="themedUnderlayColor"
|
|
|
|
|
- :innerStyle="itemStyle"
|
|
|
|
|
- :width="itemWidthArr[index].width > 0 ?
|
|
|
|
|
- theme.resolveSize(itemWidthArr[index].width - tabPaddingHorizontal * 2) :
|
|
|
|
|
- undefined"
|
|
|
|
|
- :touchable="!tab.disabled"
|
|
|
|
|
- :flexShrink="0"
|
|
|
|
|
- :padding="[ 0, tabPaddingHorizontal ]"
|
|
|
|
|
- center
|
|
|
|
|
- innerClass="tab-item"
|
|
|
|
|
- @click="onTabClick(index)"
|
|
|
|
|
|
|
+ <Badge
|
|
|
|
|
+ content="0"
|
|
|
|
|
+ v-bind="tab.badgeProps"
|
|
|
>
|
|
>
|
|
|
- <Badge
|
|
|
|
|
- content="0"
|
|
|
|
|
- v-bind="tab.badgeProps"
|
|
|
|
|
|
|
+ <text
|
|
|
|
|
+ class="tab-item-text"
|
|
|
|
|
+ :style="{
|
|
|
|
|
+ color: tab.disabled ? themedDisableTextColor : (currentIndex == index ? themedActiveTextColor : themedTextColor),
|
|
|
|
|
+ ...(currentIndex == index ? activeTextStyle : textStyle),
|
|
|
|
|
+ }"
|
|
|
>
|
|
>
|
|
|
- <text
|
|
|
|
|
- class="tab-item-text"
|
|
|
|
|
- :style="{
|
|
|
|
|
- color: tab.disabled ? themedDisableTextColor : (currentIndex == index ? themedActiveTextColor : themedTextColor),
|
|
|
|
|
- ...(currentIndex == index ? activeTextStyle : textStyle),
|
|
|
|
|
- }"
|
|
|
|
|
- >
|
|
|
|
|
- {{ tab.text }}
|
|
|
|
|
- </text>
|
|
|
|
|
- </Badge>
|
|
|
|
|
- </FlexView>
|
|
|
|
|
|
|
+ {{ tab.text }}
|
|
|
|
|
+ </text>
|
|
|
|
|
+ </Badge>
|
|
|
</slot>
|
|
</slot>
|
|
|
- </template>
|
|
|
|
|
|
|
+ </FlexView>
|
|
|
|
|
|
|
|
<view
|
|
<view
|
|
|
v-if="showIndicator"
|
|
v-if="showIndicator"
|
|
@@ -80,7 +75,7 @@
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
-import { computed, nextTick, onMounted, ref, watch } from 'vue';
|
|
|
|
|
|
|
+import { computed, getCurrentInstance, nextTick, onMounted, ref, watch } from 'vue';
|
|
|
import type { BadgeProps } from '../display/Badge.vue';
|
|
import type { BadgeProps } from '../display/Badge.vue';
|
|
|
import Badge from '../display/Badge.vue';
|
|
import Badge from '../display/Badge.vue';
|
|
|
import FlexView from '../layout/FlexView.vue';
|
|
import FlexView from '../layout/FlexView.vue';
|
|
@@ -243,6 +238,7 @@ const themedTextColor = computed(() => theme.resolveThemeColor(props.textColor))
|
|
|
const themedDisableTextColor = computed(() => theme.resolveThemeColor(props.disableTextColor));
|
|
const themedDisableTextColor = computed(() => theme.resolveThemeColor(props.disableTextColor));
|
|
|
|
|
|
|
|
const mersuredTabs = ref<(number|undefined)[]>([]);
|
|
const mersuredTabs = ref<(number|undefined)[]>([]);
|
|
|
|
|
+const tabsRefs = ref<any[]>([]);
|
|
|
const filteredTabs = computed(() => props.tabs.filter(tab => tab.visible !== false));
|
|
const filteredTabs = computed(() => props.tabs.filter(tab => tab.visible !== false));
|
|
|
const itemWidthArr = computed(() => {
|
|
const itemWidthArr = computed(() => {
|
|
|
const result : {
|
|
const result : {
|
|
@@ -255,6 +251,7 @@ const itemWidthArr = computed(() => {
|
|
|
width: 0,
|
|
width: 0,
|
|
|
indicatorWidth: 0,
|
|
indicatorWidth: 0,
|
|
|
});
|
|
});
|
|
|
|
|
+ nextTick(() => measureTab(i))
|
|
|
} else {
|
|
} else {
|
|
|
const itemWidth = filteredTabs.value[i].width ||
|
|
const itemWidth = filteredTabs.value[i].width ||
|
|
|
(
|
|
(
|
|
@@ -267,20 +264,22 @@ const itemWidthArr = computed(() => {
|
|
|
width: itemWidth,
|
|
width: itemWidth,
|
|
|
indicatorWidth: itemIndicatorWidth,
|
|
indicatorWidth: itemIndicatorWidth,
|
|
|
});
|
|
});
|
|
|
- nextTick(() => measureTab(i))
|
|
|
|
|
|
|
+ if (itemWidth <= 0)
|
|
|
|
|
+ nextTick(() => measureTab(i))
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
return result;
|
|
return result;
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
-const currentScrollPosOld = ref(0);
|
|
|
|
|
|
|
+const currentCanMeasure = ref(true);
|
|
|
const currentScrollPos = ref(0);
|
|
const currentScrollPos = ref(0);
|
|
|
const currentIndicatorPos = ref(0);
|
|
const currentIndicatorPos = ref(0);
|
|
|
const currentIndicatorWidth = ref(0);
|
|
const currentIndicatorWidth = ref(0);
|
|
|
|
|
|
|
|
function measureTab(index: number) {
|
|
function measureTab(index: number) {
|
|
|
- const tabItem = uni.createSelectorQuery().select(`#${idPrefix}${index}`);
|
|
|
|
|
- tabItem.boundingClientRect().exec((res) => {
|
|
|
|
|
|
|
+ if (!currentCanMeasure.value)
|
|
|
|
|
+ return;
|
|
|
|
|
+ tabsRefs.value[index]?.measure().then((res: any) => {
|
|
|
if (res[0])
|
|
if (res[0])
|
|
|
mersuredTabs.value[index] = res[0].width;
|
|
mersuredTabs.value[index] = res[0].width;
|
|
|
else
|
|
else
|
|
@@ -296,7 +295,7 @@ function loadPos() {
|
|
|
|
|
|
|
|
const targetWidth = uni.upx2px(current.indicatorWidth);
|
|
const targetWidth = uni.upx2px(current.indicatorWidth);
|
|
|
let scrollLeft = 0;
|
|
let scrollLeft = 0;
|
|
|
- let targetLeft = itemWidth / 2 - targetWidth / 2;
|
|
|
|
|
|
|
+ let targetLeft = 0;
|
|
|
|
|
|
|
|
for (let i = currentIndex - 1; i >= 0; i--) {
|
|
for (let i = currentIndex - 1; i >= 0; i--) {
|
|
|
const width = itemWidthArr.value[i].width > 0 ? uni.upx2px(itemWidthArr.value[i].width) : mersuredTabs.value[i] || 0;
|
|
const width = itemWidthArr.value[i].width > 0 ? uni.upx2px(itemWidthArr.value[i].width) : mersuredTabs.value[i] || 0;
|
|
@@ -304,6 +303,10 @@ function loadPos() {
|
|
|
scrollLeft += width;
|
|
scrollLeft += width;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
|
+ if (targetWidth < itemWidth)
|
|
|
|
|
+ targetLeft += itemWidth / 2 - targetWidth / 2;
|
|
|
|
|
+
|
|
|
currentIndicatorPos.value = targetLeft;
|
|
currentIndicatorPos.value = targetLeft;
|
|
|
currentIndicatorWidth.value = targetWidth;
|
|
currentIndicatorWidth.value = targetWidth;
|
|
|
currentScrollPos.value = scrollLeft + (currentIndex == itemWidthArr.value.length - 1 ? itemWidth : 0);
|
|
currentScrollPos.value = scrollLeft + (currentIndex == itemWidthArr.value.length - 1 ? itemWidth : 0);
|
|
@@ -313,7 +316,13 @@ watch(mersuredTabs, loadPos, { deep: true });
|
|
|
watch(() => props.currentIndex, loadPos);
|
|
watch(() => props.currentIndex, loadPos);
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
|
- nextTick(loadPos);
|
|
|
|
|
|
|
+ nextTick(() => {
|
|
|
|
|
+ currentCanMeasure.value = true;
|
|
|
|
|
+ measureTab(0);
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ loadPos();
|
|
|
|
|
+ }, 200);
|
|
|
|
|
+ });
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
function onTabClick(index: number) {
|
|
function onTabClick(index: number) {
|