UNPKG

vue3-multi-tab-swiper

Version:

### 介绍

244 lines (198 loc) 7.22 kB
# Vue3-multi-tab-swiper ### 介绍 `MultiTabSwiper` 是一个用于 Vue 3 的多功能组件,它提供了丰富的交互特性,包括上拉加载更多数据、下拉刷新列表、顶部标签栏吸顶,以及水平滑动切换标签时的位置记忆功能。[github 仓库](https://github.com/Eureka-M/vue3-multi-tab-swiper)。实现参考:[匠心打造多 tab 自动吸顶下的多滚动容器](https://zhuanlan.zhihu.com/p/410913113) ### 安装 ``` npm i vue3-multi-tab-swiper ``` ### 导入 ``` import { createApp } from "vue"; import App from "./App.vue"; import MultiTabSwiper from "vue3-multi-tab-swiper"; import "vue3-multi-tab-swiper/lib/style.css"; let app = createApp(App); app.use(MultiTabSwiper); app.mount("#app"); ``` ### 使用示例 ##### 上拉加载 <img src="上拉加载.GIF" alt="上拉加载" style="zoom:67%;" /> ##### 下拉刷新 <img src="下拉刷新.GIF" alt="下拉刷新" style="zoom:67%;" /> ##### 水平滑动位置记忆 <img src="横滑.GIF" alt="横滑" style="zoom:67%;" /> ##### 代码 ``` <template> <multi-tab-swiper :tabs="tabs" :loadingEnd="isLoadingEnd" :hasMore="hasMoreData" @pulldownRefresh="pulldownRefresh" @pullupLoadMore="pullupLoadMore" @activeChange="activeChange" > <template #banner-content> <div class="banner-box">顶部内容区</div> </template> <template #refresh-indicator="{ state }"> <div v-if="state === 'pulling'" class="refresh-text">下拉刷新...</div> <div v-if="state === 'releasing'" class="refresh-text">释放刷新...</div> <div v-if="state === 'refreshing'" class="refresh-text">正在刷新...</div> <div v-if="state === 'refreshed'" class="refresh-text">刷新完成!</div> </template> <template #load-more-indicator="{ state }"> <div v-if="state === 'loadMore'" class="load-text">加载更多...</div> <div v-if="state === 'loading'" class="load-text">加载中...</div> <div v-if="state === 'noMoreData'" class="load-text">暂无更多数据...</div> </template> <div class="tab-content"> <div class="data-item" v-for="(item, index) in data1" :key="index"> This is Tab-1, Current data is {{ index + 1 }} </div> </div> <div class="tab-content"> <div class="data-item" v-for="(item, index) in data2" :key="index"> This is Tab-2, Current data is {{ index + 1 }} </div> </div> <div class="tab-content"> <div class="data-item" v-for="(item, index) in data3" :key="index"> This is Tab-3, Current data is {{ index + 1 }} </div> </div> <div class="tab-content"> <div class="data-item" v-for="(item, index) in data4" :key="index"> This is Tab-4, Current data is {{ index + 1 }} </div> </div> <div class="tab-content"> <div class="data-item" v-for="(item, index) in data5" :key="index"> This is Tab-5, Current data is {{ index + 1 }} </div> </div> <div class="tab-content"> <div class="data-item" v-for="(item, index) in data6" :key="index"> This is Tab-6, Current data is {{ index + 1 }} </div> </div> </multi-tab-swiper> </template> <script setup> import { ref } from "vue"; let tabIndex = 0; const tabs = ref(["tab1", "tab2", "tab3", "tab4", "tab5", "tab6"]); const data1 = ref(new Array(20).fill(0)); const data2 = ref(new Array(20).fill(0)); const data3 = ref(new Array(20).fill(0)); const data4 = ref(new Array(20).fill(0)); const data5 = ref(new Array(20).fill(0)); const data6 = ref(new Array(20).fill(0)); let isLoadingEnd = ref(false); let hasMoreData = ref(true); const pulldownRefresh = () => { isLoadingEnd.value = false; setTimeout(() => { console.log("下拉刷新数据"); let data = ref(getCurrentTabData(tabIndex)); data.value = new Array(20).fill(0); isLoadingEnd.value = true; }, 1000); }; const pullupLoadMore = () => { isLoadingEnd.value = false; hasMoreData.value = true; setTimeout(() => { console.log("上拉加载数据"); let newData = new Array(10).fill(0); let data = ref(getCurrentTabData(tabIndex)); data.value = data.value.concat(newData); isLoadingEnd.value = true; hasMoreData.value = data.value.length < 40; }, 1000); }; const getCurrentTabData = (index) => { switch (index) { case 0: return data1; case 1: return data2; case 2: return data3; case 3: return data4; case 4: return data5; case 5: return data6; default: return data1; } }; const activeChange = (index) => { tabIndex = index; }; </script> <style scoped lang="less"> .banner-box { height: 150px; display: flex; align-items: center; justify-content: center; background: #f58391; } :deep(.tabs) { background: pink; .tab-item.active { background: #fff !important; } } .tab-content { padding: 20px; .data-item { display: flex; justify-content: center; height: 40px; line-height: 40px; border: 1px solid #ddd; margin-bottom: 10px; font-size: 14px; border-radius: 4px; background: #ffe9ed; &:last-child { margin-bottom: 0; } } } .main-content { background: #fde7ea; } .refresh-text, .load-text { margin-bottom: 10px; } </style> ``` ### API 参考 ##### props | 名称 | 类型 | 是否必须 | 描述 | | ---------- | ------- | -------- | -------------------- | | tabs | Array | 是 | tabbar 上显示的标签 | | loadingEnd | Boolean | 是 | 请求完成之后通知组件 | | hasMore | Boolean | 是 | 列表是否还有数据 | ##### Slots | 名称 | 描述 | | ------------------- | ------------------------------------------------------------------------------------------------------------------ | | - | 默认插槽,用于渲染每个 tab 项的内容。这里的第一层级 dom 数要和 tabs 数组项数对齐。 | | banner-content | 顶部内容区插槽 | | refresh-indicator | 下拉刷新插槽,是一个作用域插槽。抛出来的 state 的值:'pulling' \|\| 'releasing' \|\| 'refreshing' \|\| 'refreshed' | | load-more-indicator | 上拉加载插槽,是一个作用域插槽。抛出来的 state 的值:'loadMore' \|\| 'loading' \|\| 'noMoreData' | ##### Events | 名称 | 参数 | 描述 | | --------------- | ----- | -------------------------------------------- | | pulldownRefresh | - | 当用户执行下拉刷新操作时触发。 | | pullupLoadMore | - | 当用户滚动到底部并且启用上拉加载更多时触发。 | | activeChange | index | 当用户点击 tab 或者横滑结束后触发。 | ### 目前还存在的问题 左右滑动时,两侧出现的弹动问题。包括 tab 贴顶后,上滑 tab 出现的弹动问题。