feat: tab 的点击交互

This commit is contained in:
2026-05-14 14:43:23 +08:00
parent 199c418225
commit 83d4066f72
5 changed files with 61 additions and 6 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -21,7 +21,7 @@ import SpriteAnimator from "@/components/Sprite/SpriteAnimator.vue";
import NoticeMessage from "../NoticeMessage/index.vue"; import NoticeMessage from "../NoticeMessage/index.vue";
import { getLocalWeather } from "@/request/api/MainPageDataApi"; import { getLocalWeather } from "@/request/api/MainPageDataApi";
const weatherText = ref("26°C ☀️"); const weatherText = ref('');
const props = defineProps({ const props = defineProps({
mainPageDataModel: { mainPageDataModel: {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 822 B

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -1,11 +1,17 @@
<template> <template>
<view class="find-tabs-wrapper"> <view class="find-tabs-wrapper">
<scroll-view class="tabs-scroll" scroll-x="true" :scroll-into-view="'tab-' + modelValue" scroll-with-animation="true"> <scroll-view
class="tabs-scroll"
scroll-x="true"
:scroll-left="scrollLeft"
scroll-with-animation="true"
@scroll="handleScroll"
>
<view class="tabs-list"> <view class="tabs-list">
<view <view
v-for="(tab, idx) in tabs" v-for="(tab, idx) in tabs"
:key="idx" :key="idx"
:id="'tab-' + idx" :id="getTabId(idx)"
class="tab-item" class="tab-item"
:class="{ active: modelValue === idx }" :class="{ active: modelValue === idx }"
@tap="handleSwitch(tab, idx)" @tap="handleSwitch(tab, idx)"
@@ -23,10 +29,13 @@
</template> </template>
<script setup> <script setup>
import { getCurrentInstance, nextTick, onMounted, ref, watch } from "vue";
import { isZhiNian } from "@/constant/base"; import { isZhiNian } from "@/constant/base";
import indicatorSrc from "./images/selected_tabs_icon.png"; import indicatorSrc from "./images/selected_tabs_icon.png";
import indicatorSrcB from "./images/selected_tabs_icon_b.png"; import indicatorSrcB from "./images/selected_tabs_icon_b.png";
const instance = getCurrentInstance();
const props = defineProps({ const props = defineProps({
modelValue: { type: Number, default: 0 }, modelValue: { type: Number, default: 0 },
tabs: { tabs: {
@@ -37,11 +46,56 @@ const props = defineProps({
const emit = defineEmits(['update:modelValue', 'change']); const emit = defineEmits(['update:modelValue', 'change']);
const scrollLeft = ref(0);
let currentScrollLeft = 0;
const getTabId = (idx) => `find-tab-${idx}`;
const handleScroll = (e) => {
currentScrollLeft = e.detail?.scrollLeft || 0;
};
const centerActiveTab = async () => {
await nextTick();
const activeIndex = props.modelValue;
if (activeIndex < 0 || activeIndex >= props.tabs.length) return;
if (!instance || typeof uni === "undefined" || !uni.createSelectorQuery) return;
const query = uni.createSelectorQuery().in(instance);
query.select(".tabs-scroll").boundingClientRect();
query.select(".tabs-scroll").scrollOffset();
query.select(`#${getTabId(activeIndex)}`).boundingClientRect();
query.exec((res) => {
const [scrollRect, scrollOffset, activeRect] = res || [];
if (!scrollRect || !activeRect) return;
const currentLeft = scrollOffset?.scrollLeft ?? currentScrollLeft;
const targetScrollLeft =
currentLeft +
activeRect.left - scrollRect.left -
(scrollRect.width - activeRect.width) / 2;
scrollLeft.value = Math.max(0, targetScrollLeft);
});
};
const handleSwitch = (tab, idx) => { const handleSwitch = (tab, idx) => {
emit('update:modelValue', idx); emit('update:modelValue', idx);
emit('change', { tab, idx }); emit('change', { tab, idx });
}; };
watch(
() => [props.modelValue, props.tabs.length],
() => {
centerActiveTab();
}
);
onMounted(() => {
centerActiveTab();
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -46,10 +46,11 @@
} }
.tab-text { .tab-text {
position: relative;
font-size: 16px; font-size: 16px;
font-weight: 500; font-weight: 500;
color: rgba(128, 140, 153, 0.9); color: rgba(128, 140, 153, 0.9);
z-index: 5; z-index: 2;
padding: 0 4px; padding: 0 4px;
line-height: 1; line-height: 1;
} }
@@ -66,5 +67,5 @@
transform: translateX(-50%); transform: translateX(-50%);
width: 56px; width: 56px;
height: auto; height: auto;
z-index: 6; z-index: 1;
} }