| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- <template>
- <cl-sticky>
- <cl-topbar fixed safe-area-top>
- <cl-tabs
- :list="list"
- v-model="active"
- height="36px"
- :gutter="20"
- @change="onTabChange"
- ></cl-tabs>
- <template #append>
- <view class="h-[44px] w-[30px] flex items-center justify-center mr-1">
- <cl-icon name="search-line"></cl-icon>
- </view>
- </template>
- </cl-topbar>
- </cl-sticky>
- </template>
- <script setup lang="ts">
- import { debounce, getSafeAreaHeight, isNull } from "@/cool";
- import { usePage, type ClTabsItem } from "@/uni_modules/cool-ui";
- import { getCurrentInstance, onMounted, onUnmounted, ref } from "vue";
- const { proxy } = getCurrentInstance()!;
- const page = usePage();
- // 当前激活tab
- const active = ref("info");
- // 滚动时激活tab
- const scrollActive = ref("");
- // 卡片距离顶部偏移量
- const tops = ref<number[]>([]);
- // tab项列表
- const list = ref<ClTabsItem[]>([
- { label: "商品", value: "info" },
- { label: "评价", value: "comment" },
- { label: "详情", value: "desc" }
- ]);
- /**
- * 获取所有.card顶部坐标
- */
- async function getTops(): Promise<void> {
- return new Promise((resolve) => {
- uni.createSelectorQuery()
- .in(proxy?.$root)
- .selectAll(".card")
- .boundingClientRect((res) => {
- const top = page.getScrollTop() - 44 - getSafeAreaHeight("top"); // 去头部高度
- // 只计算有id的card
- tops.value = (res as NodeInfo[])
- .filter((e) => e.id != "" && !isNull(e.id))
- .map((e) => (e.top ?? 0) + top);
- resolve();
- })
- .exec();
- });
- }
- /**
- * tab切换
- */
- async function onTabChange(value: string) {
- // 设置滚动时激活tab
- scrollActive.value = value;
- // 重新获取卡片位置
- await getTops();
- // 查找符合当前位置的tab索引
- const index = list.value.findIndex((e) => e.value == value);
- if (index < 0) return;
- // 滚动到对应卡片位置
- page.scrollTo(tops.value[index] + 1);
- }
- /**
- * 同步当前tab
- */
- const setActive = debounce(() => {
- active.value = scrollActive.value;
- }, 100);
- /**
- * 滚动时激活tab
- */
- function onScroll(top: number) {
- let index = -1;
- // 查找符合当前位置的tab索引
- for (let i = 0; i < tops.value.length; i++) {
- if (top >= tops.value[i]) {
- index = i;
- }
- }
- // 设置激活tab
- if (index >= 0 && index < list.value.length) {
- scrollActive.value = list.value[index].value as string;
- setActive();
- }
- }
- onMounted(() => {
- // 获取卡片位置
- getTops();
- // 监听页面滚动
- page.onScroll(onScroll);
- });
- onUnmounted(() => {
- // 移除监听
- page.offScroll(onScroll);
- });
- </script>
|