uni-app tab切换,tab样式。可以滑动实现页面切换的。tab菜单滑动切换。下方内容在剩下的高度滚动,上方的tab菜单固定不跟随滚动。左右切换 滑动菜单 电脑版发表于:2020/11/9 13:49 [TOC] #### 一:需要内容页可以滑动切换,tab菜单会跟着选中。但tab菜单固定显示,不需要滑动切换的 <img src="https://img.tnblog.net/arcimg/aojiancc2/9d86db803fb34c5ca9ea7ee3d9c662c2.png" style="width:399px;height:auto;"> **代码:** ``` <template> <div class="body-view"> <view class="top-menu-view" scroll-x="true" :scroll-into-view="tabCurrent"> <view class="menu-topic-view" v-for="item in tabs" :id="'tabNum' + item.id" :key="(item.id - 1)" @click="switchMenu(item.id - 1)"> <view :class="currentTab === (item.id - 1) ? 'menu-topic-act' : 'menu-topic'"> <span class="menu-topic-text">{{ item.name }}</span> <view class="menu-topic-bottom"> <view class="menu-topic-bottom-color"></view> </view> </view> </view> </view> <!-- 内容 --> <swiper class="swiper-box-list" :current="currentTab" @change="swiperChange"> <swiper-item class="swiper-topic-list" v-for="item in swiperDateList" :key="item.id"> <div class="swiper-item"> {{ item.content }} </div> </swiper-item> </swiper> </div> </template> <script setup lang="ts"> import { ref, onMounted } from 'vue'; const tabs = ref<any>([ { id: 1, name: '日数据' }, { id: 2, name: '周数据' }, { id: 3, name: '月数据' }, ]) const currentTab = ref(0); const tabCurrent = ref('tabNum1'); const swiperDateList = ref<any>([ { id: 1, content: '日数据内容' }, { id: 2, content: '周数据内容' }, { id: 3, content: '月数据内容' }, ]) const switchMenu = (id: number) => { currentTab.value = id; console.log(11, id); tabCurrent.value = 'tabNum' + id; }; const swiperChange = (e: { detail: { current: number } }) => { console.log(22, e.detail.current); const index = e.detail.current; switchMenu(index); }; onMounted(() => { // Perform any initialization logic here }); </script> <style scoped lang="scss"> .body-view { height: 100vh; width: 100%; display: flex; flex: 1; flex-direction: column; overflow: hidden; align-items: flex-start; justify-content: center; } .top-menu-view { display: flex; white-space: nowrap; width: 100%; background-color: #FFFFFF; height: 86rpx; line-height: 86rpx; justify-content: space-between; .menu-topic-view { display: inline-block; white-space: nowrap; height: 86rpx; position: relative; .menu-topic-text { font-size: 30rpx; color: #303133; padding: 10rpx 40rpx; } .menu-topic-bottom { position: absolute; bottom: 0; width: 100%; .menu-topic-bottom-color { width: 40rpx; height: 4rpx; } } .menu-topic-act .menu-topic-bottom { display: flex; justify-content: center; } .menu-topic-act .menu-topic-bottom-color { background: #3d7eff; } } } .swiper-box-list { width: 100%; padding-top: 200rpx; flex: 1; .swiper-topic-list { width: 100%; } } </style> ``` #### 二:需要tab可以滑动切换的,内容页不需要左右滑动切换。下方内容在剩下的高度滚动,上方的tab菜单固定不跟随滚动 <img src="https://img.tnblog.net/arcimg/aojiancc2/c984917c65ac44a8993bc2142fc9302c.png" style="width:502px;height:auto;"> 代码: ``` <template> <!-- 解决滚动穿透 --> <page-meta :page-style="'overflow:' + (state.popupShow ? 'hidden' : 'visible')"></page-meta> <view class="body-view"> <scroll-view class="top-menu-view" scroll-x="true" :scroll-into-view="tabCurrent"> <div class="menu-topic-view" v-for="item in tabs" :id="'tabNum' + item.id" :key="(item.id - 1)" @click="switchMenu(item.id - 1)"> <div :class="currentTab === (item.id - 1) ? 'menu-topic-act' : 'menu-topic'"> <span class="menu-topic-text">{{ item.name }}</span> <div class="menu-topic-bottom"> <div class="menu-topic-bottom-color"></div> </div> </div> </div> </scroll-view> <view class="class-info"> <view class="ci-className">23级移动互联应用技术1班</view> <image :src="`${config.imgBaseUrl}/mp-weixin/smartedu-growing/teacher-icon/arrow.png`" class="class-info-icon-arrow" /> </view> <view style=""> <scroll-view scroll-y="true" style="height:calc(100vh - 160rpx);"> <view class="do-item-wrap"> <view class="do-item" v-for="(initem, index) in 13" :key="index"> <view class="di-task-desc"> <view class="di-td-index">{{ index + 1 }}</view> <view class="di-td-title">体能测试—跑步(女子800米/男子1000米)</view> </view> <view class="di-task-spline"></view> <view class="di-task-statictics"> <view class="di-ts-count"> <view class="di-tst-desc">完成次数:</view> <view class="di-tst-value">2次</view> </view> <view class="di-ts-buttons"> <view class="di-tst-details" @tap="popupMethods.showMonthTaskDetails">详情</view> <view class="di-tst-tocomplete" @tap="methods.toCompletePage" v-if="index < 5">去完成</view> </view> </view> </view> </view> </scroll-view> </view> <uni-popup ref="monthTaskDetailsPopup" background-color="#fff" border-radius="60rpx 60rpx 0rpx 0rpx;" type="bottom" @change="methods.change"> <monthTaskDetails @closePopup="popupMethods.closeMonthTaskDetails" title="参加班级扫除道"> </monthTaskDetails> </uni-popup> </view> </template> <script setup lang="ts"> import { ref, onMounted, reactive } from 'vue'; import config from '@/common/config.ts' import monthTaskDetails from './component/monthTaskDetails.vue' const tabs = ref<any>([ { id: 1, name: '全部' }, { id: 2, name: '德' }, { id: 3, name: '智' }, { id: 4, name: '体' }, { id: 5, name: '美' }, { id: 6, name: '劳' }, { id: 7, name: '技术' }, { id: 8, name: '健康' }, { id: 9, name: '思维' }, ]) const currentTab = ref(0); const tabCurrent = ref('tabNum1'); const state = reactive({ popupShow: false, }) const switchMenu = (id: number) => { currentTab.value = id; // console.log(11, id); tabCurrent.value = 'tabNum' + id; }; onMounted(() => { }); const methods = { change: function (e: any) { state.popupShow = e.show }, toCompletePage: function () { uni.navigateTo({ url: "/pages/student/toDoMonthTask" }) } } let monthTaskDetailsPopup = ref() const popupMethods = { // 打开弹窗 showMonthTaskDetails: () => { monthTaskDetailsPopup.value.open() }, // 关闭弹窗 closeMonthTaskDetails: () => { monthTaskDetailsPopup.value.close() } } </script> <style scoped lang="scss"> .body-view { // min-height: 100vh; // width: 100%; display: flex; height: 100vh; flex-direction: column; // overflow: hidden; // align-items: flex-start; // justify-content: center; } .top-menu-view { display: flex; position: fixed; top: 0rpx; left: 0; white-space: nowrap; width: 100%; background-color: #FFFFFF; height: 86rpx; line-height: 86rpx; // border-top: 1rpx solid #d8dbe6; .menu-topic-view { display: inline-block; white-space: nowrap; height: 86rpx; position: relative; .menu-topic-text { font-size: 30rpx; color: #303133; padding: 10rpx 40rpx; } .menu-topic-bottom { position: absolute; bottom: 0; width: 100%; .menu-topic-bottom-color { width: 40rpx; height: 4rpx; } } .menu-topic-act .menu-topic-bottom { display: flex; justify-content: center; } .menu-topic-act .menu-topic-bottom-color { background: #3d7eff; } } } .class-info { margin-top: 100rpx; // top: 100rpx; // position: fixed; width: 100%; height: 77rpx; background: #FFFFFF; font-size: 26rpx; color: #313960; display: flex; align-items: center; justify-content: space-between; .ci-className { margin-left: 20rpx; } .class-info-icon-arrow { width: 24rpx; height: 13rpx; margin-right: 20rpx; } } .do-item-wrap { // width: 100%; padding-left: 20rpx; padding-right: 20rpx; padding-bottom: 20rpx; .di-task-spline { height: 1rpx; background: #000000; opacity: 0.1; margin-top: 20rpx; margin-left: 20rpx; margin-right: 20rpx; } .do-item { width: 100%; height: 161rpx; background: #FFFFFF; margin-top: 20rpx; .di-task-desc { display: flex; padding-left: 20rpx; padding-top: 20rpx; .di-td-index { width: 34rpx; height: 34rpx; background: #4D9DF5; border-radius: 10rpx 10rpx 10rpx 10rpx; color: #FFFFFF; font-size: 26rpx; text-align: center; line-height: 34rpx; } .di-td-title { font-size: 28rpx; color: #313960; margin-left: 20rpx; } } .di-task-statictics { display: flex; align-items: center; justify-content: space-between; margin-top: 26rpx; padding-left: 20rpx; padding-right: 20rpx; .di-ts-count { display: flex; font-size: 24rpx; .di-tst-desc { color: rgba(0, 0, 0, 0.5) } .di-tst-value { color: #313960; } } .di-ts-buttons { display: flex; .di-tst-details { width: 90rpx; height: 40rpx; border-radius: 35rpx 35rpx 35rpx 35rpx; border: 2rpx solid #4D9DF5; font-size: 24rpx; color: #4D9DF5; text-align: center; line-height: 40rpx; } .di-tst-tocomplete { text-align: center; line-height: 40rpx; color: #67C23A; font-size: 24rpx; width: 114rpx; height: 40rpx; border-radius: 35rpx 35rpx 35rpx 35rpx; border: 2rpx solid #67C23A; margin-left: 15rpx; } } } } } </style> ``` #### 三:tab菜单和内容页都可以左右滑动切换的 非常基础版本的代码,需要改造 ``` <template> <div class="body-view"> <!-- 使用scroll-view实现tabs滑动切换 --> <scroll-view class="top-menu-view" scroll-x="true" :scroll-into-view="tabCurrent"> <div class="menu-topic-view" v-for="item in tabs" :id="'tabNum' + item.id" :key="(item.id - 1)" @click="switchMenu(item.id - 1)"> <div :class="currentTab === (item.id - 1) ? 'menu-topic-act' : 'menu-topic'"> <span class="menu-topic-text">{{ item.name }}</span> <div class="menu-topic-bottom"> <div class="menu-topic-bottom-color"></div> </div> </div> </div> </scroll-view> <!-- 内容 --> <swiper class="swiper-box-list" :current="currentTab" @change="swiperChange"> <swiper-item class="swiper-topic-list" v-for="item in swiperDateList" :key="item.id"> <div class="swiper-item"> {{ item.content }} </div> </swiper-item> </swiper> </div> </template> <script setup lang="ts"> import { ref, onMounted } from 'vue'; const tabs = ref<any>([ { id: 1, name: '推荐' }, { id: 2, name: '交通交通' }, { id: 3, name: '住房' }, { id: 4, name: '社会保障' }, { id: 5, name: '民生热点' }, { id: 6, name: '即日头条' }, { id: 7, name: '新闻联播' }, ]) const currentTab = ref(0); const tabCurrent = ref('tabNum1'); const swiperDateList = ref<any>([ { id: 1, content: '推荐' }, { id: 2, content: '交通交通' }, { id: 3, content: '住房' }, { id: 4, content: '社会保障' }, { id: 5, content: '民生热点' }, { id: 6, content: '即日头条' }, { id: 7, content: '新闻联播' }, ]) const switchMenu = (id: number) => { currentTab.value = id; console.log(11, id); tabCurrent.value = 'tabNum' + id; }; const swiperChange = (e: { detail: { current: number } }) => { console.log(22, e.detail.current); const index = e.detail.current; switchMenu(index); }; onMounted(() => { // Perform any initialization logic here }); </script> <style scoped lang="scss"> .body-view { height: 100vh; width: 100%; display: flex; flex: 1; flex-direction: column; overflow: hidden; align-items: flex-start; justify-content: center; } .top-menu-view { display: flex; position: fixed; top: 100rpx; left: 0; white-space: nowrap; width: 100%; background-color: #FFFFFF; height: 86rpx; line-height: 86rpx; border-top: 1rpx solid #d8dbe6; .menu-topic-view { display: inline-block; white-space: nowrap; height: 86rpx; position: relative; .menu-topic-text { font-size: 30rpx; color: #303133; padding: 10rpx 40rpx; } .menu-topic-bottom { position: absolute; bottom: 0; width: 100%; .menu-topic-bottom-color { width: 40rpx; height: 4rpx; } } .menu-topic-act .menu-topic-bottom { display: flex; justify-content: center; } .menu-topic-act .menu-topic-bottom-color { background: #3d7eff; } } } .swiper-box-list { width: 100%; padding-top: 200rpx; flex: 1; .swiper-topic-list { width: 100%; } } </style> ``` #### 四:备注 更多样式请参考,存储的模板