<template> <view class="content"> <!-- 顶部选项卡 --> <scroll-view id="nav-bar" class="nav-bar" scroll-x scroll-with-animation :scroll-left="scrollLeft"> <view v-for="(item,index) in tabBars" :key="item.id" class="nav-item" :class="{current: index === tabCurrentIndex}" :id="'tab'+index" @click="changeTab(index)" >{{item.itemName}}</view> </scroll-view> <!-- 下拉刷新组件 --> <mix-pulldown-refresh ref="mixPulldownRefresh" class="panel-content" :top="90" @refresh="onPulldownReresh" @setEnableScroll="setEnableScroll"> <!-- 内容部分 --> <swiper id="swiper" class="swiper-box" :duration="300" :current="tabCurrentIndex" @change="changeTab" > <swiper-item v-for="tabItem in tabBars" :key="tabItem.id"> <scroll-view class="panel-scroll-box" :scroll-y="enableScroll" @scrolltolower="loadMore" > <!-- * 新闻列表 * 和nvue的区别只是需要把uni标签转为weex标签而已 * class 和 style的绑定限制了一些语法,其他并没有不同 --> <view v-for="(item, index) in tabItem.newsList" :key="index" class="news-item" @click.stop="navToDetails(index)"> <text :class="['title', 'title'+item.contentLayout]">{{item.articleTitle}}</text> <view class="video-wrapper" v-if="item.contentLayout == 4" style="margin-top:20upx"> <video class="video" :src="imgUrl+item.articleContent" controls objectFit="fill" :autoplay="false" ></video> </view> <view v-if="item.articleCovers.length > 0" :class="['img-list', 'img-list'+item.contentLayout, item.articleCovers.length == 1 && item.contentLayout==2 ? 'img-list-single': '']"> <view v-for="(imgItem, imgIndex) in item.articleCovers" :key="imgIndex" :class="['img-wrapper', 'img-wrapper'+item.contentLayout, item.articleCovers.length == 1 && item.contentLayout==2 ? 'img-wrapper-single': '']" > <image class="img" v-if="item.contentLayout == 3" mode="aspectFit" :src="imgUrl+imgItem"></image> <image class="img" v-if="item.contentLayout == 2" mode="scaleToFill" :src="imgUrl+imgItem"></image> </view> </view> <view v-if="item.articleCovers.length == 0 && item.contentLayout != 4" class="img-empty"></view> <view :class="['bot', 'bot'+item.contentLayout]"> <text :class="['author', 'author'+item.contentLayout]">{{item.hospitalName}}</text> <text class="time">{{item.publishTime ? item.publishTime.split(" ")[0]:''}}</text> </view> </view> <!-- 上滑加载更多组件 --> <mix-load-more :status="tabItem.loadMoreStatus"></mix-load-more> </scroll-view> </swiper-item> </swiper> </mix-pulldown-refresh> </view> </template> <script> import json from '@/json' import mixPulldownRefresh from '@/components/mix-pulldown-refresh/mix-pulldown-refresh'; import mixLoadMore from '@/components/mix-load-more/mix-load-more'; let windowWidth = 0, scrollTimer = false, tabBar; export default { components: { mixPulldownRefresh, mixLoadMore, }, data() { return { imgUrl:"http://139.9.163.126/gastric/", tabCurrentIndex: 0, //当前选项卡索引 scrollLeft: 0, //顶部选项卡左滑距离 enableScroll: true, tabBars: [], newsList:[] } }, computed: { }, onShow() { }, onLoad() { this.getArticleType() // 获取屏幕宽度 windowWidth = uni.getSystemInfoSync().windowWidth; }, onReady(){ /** * 启动页广告 使用文档(滑稽) * 1. 引入组件并注册 * import mixAdvert from '@/components/mix-advert/vue/mix-advert'; * components: {mixAdvert}, <!-- #ifndef MP --> <mix-advert ref="mixAdvert" :timedown="8" imageUrl="/static/advert.jpg" :url="advertNavUrl" ></mix-advert> <!-- #endif --> * 2. 调用组件的initAdvert()方法进行初始化 * * 初始化的时机应该是在splash关闭时,否则会造成在app端广告显示了数秒后首屏才渲染出来 */ // #ifndef MP // this.$refs.mixAdvert.initAdvert(); // #endif }, methods: { getArticleType(){ const data = ["articleType"] this.$http.post(`/gastric-cancer-data/enumerate/codes`,data).then(res => { if(res.data.code == 1){ let tabList = res.data.object[0].items tabList.forEach(item=>{ item.newsList = []; item.pageNum = 0 item.loadMoreStatus = 0; //加载更多 0加载前,1加载中,2没有更多了 item.refreshing = 0; }) this.tabBars = tabList; if(this.tabBars.length>0){ this.loadNewsList('add'); } } }) }, //新闻列表 loadNewsList(type){ let tabItem = this.tabBars[this.tabCurrentIndex]; //type add 加载更多 refresh下拉刷新 if(type === 'add'){ if(tabItem.loadMoreStatus === 2){ return; } tabItem.loadMoreStatus = 1; tabItem.pageNum += 1 } // #ifdef APP-PLUS else if(type === 'refresh'){ tabItem.refreshing = true; } // #endif if(type === 'refresh'){ tabItem.pageNum = 1 tabItem.newsList = []; //刷新前清空数组 } // let hospitalId = this.$store.getters.userInfo.hospitalId const data = {"pageNum":tabItem.pageNum,"pageSize":10,'type':tabItem.itemCode,'published': 1} this.$http.post(`/gastric-cancer-data/article/page`,data).then(res => { if(res.data.code == 1){ let list = res.data.object.list if(list.length>0){ list.forEach(item=>{ tabItem.newsList.push(item) }) }else{ tabItem.loadMoreStatus = 2 // 已无更多数据 } if(res.data.object.totalCount <=10){ tabItem.loadMoreStatus = 2 } } }) //下拉刷新 关闭刷新动画 if(type === 'refresh'){ this.$refs.mixPulldownRefresh && this.$refs.mixPulldownRefresh.endPulldownRefresh(); // #ifdef APP-PLUS tabItem.refreshing = false; // #endif tabItem.loadMoreStatus = 0; } //上滑加载 处理状态 if(type === 'add'){ tabItem.loadMoreStatus = tabItem.newsList.length > 40 ? 2: 0; } }, //新闻详情 navToDetails(index){ let id = this.tabBars[this.tabCurrentIndex].newsList[index].id // let url = item.videoSrc ? 'videoDetails' : 'details'; uni.navigateTo({ url: `/educationViews/details/index?id=${id}` }) }, //下拉刷新 onPulldownReresh(){ this.loadNewsList('refresh'); }, //上滑加载 loadMore(){ this.loadNewsList('add'); }, //设置scroll-view是否允许滚动,在小程序里下拉刷新时避免列表可以滑动 setEnableScroll(enable){ if(this.enableScroll !== enable){ this.enableScroll = enable; } }, //tab切换 async changeTab(e){ if(scrollTimer){ //多次切换只执行最后一次 clearTimeout(scrollTimer); scrollTimer = false; } let index = e; //e=number为点击切换,e=object为swiper滑动切换 if(typeof e === 'object'){ index = e.detail.current } if(typeof tabBar !== 'object'){ tabBar = await this.getElSize("nav-bar") } //计算宽度相关 let tabBarScrollLeft = tabBar.scrollLeft; let width = 0; let nowWidth = 0; //获取可滑动总宽度 for (let i = 0; i <= index; i++) { let result = await this.getElSize('tab' + i); width += result.width; if(i === index){ nowWidth = result.width; } } if(typeof e === 'number'){ //点击切换时先切换再滚动tabbar,避免同时切换视觉错位 this.tabCurrentIndex = index; } //延迟300ms,等待swiper动画结束再修改tabbar scrollTimer = setTimeout(()=>{ if (width - nowWidth/2 > windowWidth / 2) { //如果当前项越过中心点,将其放在屏幕中心 this.scrollLeft = width - nowWidth/2 - windowWidth / 2; }else{ this.scrollLeft = 0; } if(typeof e === 'object'){ this.tabCurrentIndex = index; } this.tabCurrentIndex = index; //第一次切换tab,动画结束后需要加载数据 let tabItem = this.tabBars[this.tabCurrentIndex]; if(this.tabCurrentIndex !== 0 && tabItem.loaded !== true){ this.loadNewsList('add'); tabItem.loaded = true; } }, 300) }, //获得元素的size getElSize(id) { return new Promise((res, rej) => { let el = uni.createSelectorQuery().select('#' + id); el.fields({ size: true, scrollOffset: true, rect: true }, (data) => { res(data); }).exec(); }); }, } } </script> <style lang='scss' scoped> page, .content{ background-color: #f8f8f8; height: 100%; overflow: hidden; } .content{ height: 100%; } /* 顶部tabbar */ .nav-bar{ position: relative; z-index: 10; height: 90upx; white-space: nowrap; box-shadow: 0 2upx 8upx rgba(0,0,0,.06); background-color: #fff; .nav-item{ display: inline-block; width: 150upx; height: 90upx; text-align: center; line-height: 90upx; font-size: 30upx; color: #303133; position: relative; &:after{ content: ''; width: 0; height: 0; border-bottom: 4upx solid #007aff; position: absolute; left: 50%; bottom: 0; transform: translateX(-50%); transition: .3s; } } .current{ color: #007aff; &:after{ width: 50%; } } } .swiper-box{ height: 100%; } .panel-scroll-box{ height: 100%; .panel-item{ background: #fff; padding: 30px 0; border-bottom: 2px solid #000; } } /** * 新闻列表 直接拿的nvue样式修改,, * 一共需要修改不到10行代码, 另外px需要直接修改为upx,只有单位不一样,计算都是一样的 * 吐槽:难道不能在编译的时候把nuve中的upx转为px? 这样就不用修改单位了 */ .video-wrapper{ width: 100%; height: 440upx; .video{ width: 100%; } } view{ display:flex; flex-direction: column; } .img{ width: 100%; height: 100%; } .news-item{ position:relative; } /* 修改结束 */ /* 新闻列表 emmm 仅供参考 */ .news-item{ width: 750upx; padding: 24upx 30upx; padding-bottom: 0; background-color: #fff; } .title{ font-size: 32upx; color: black; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; white-space:pre-wrap; word-break:break-all; line-height: 46upx; } .bot{ flex-direction: row; border-bottom: 1upx solid rgba(0,0,0,0.25); padding-bottom: 24upx; } .author{ font-size: 24upx; color: #aaa; max-width: 580upx; min-width: 580upx; overflow: hidden; text-overflow:ellipsis; white-space: nowrap; } .author2{ max-width: 360upx; min-width: 360upx; } .time{ font-size: 24upx; color: #aaa; min-width: 270upx; } .img-list{ flex-shrink: 0; flex-direction: row; background-color: #fff; width: 200upx; height: 140upx; } .img-wrapper{ flex: 1; flex-direction: row; height: 140upx; position: relative; overflow: hidden; } .img{ flex: 1; } .img-empty{ height: 20upx; } .img-list1{ position:absolute; left: 30upx; top: 24upx; } /* .title1{ padding-left: 240upx; } .bot1{ padding-left: 240upx; margin-top: 20upx; } */ /* 图在左 */ .img-list2{ position:absolute; left: 30upx; top: 24upx; } .title2{ padding-left: 220upx; height:92upx; } .bot2{ padding-left: 220upx; margin-top: 20upx; } /* 图 */ .img-list3{ width: 700upx; margin: 16upx 0upx; } .img-wrapper3{ margin-right: 12upx; } /* 底部大图 */ /* .img-list-single{ width: 690upx; height: 300upx; margin: 16upx 0upx; } .img-wrapper-single{ height: 300upx; margin-right: 0upx; } */ .video-tip{ /* position: absolute; left: 0; top: 0; display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; background-color: rgba(0,0,0,.3); */ } .video-tip-icon{ width: 60upx; height:60upx; } </style>