uniapp——多头部tab的列表页

在这里插入图片描述

一、使用 vue 页面实现

点此查看录屏效果

  • 缺点一:见视频第18秒,先将列表向上滚动一部分内容,再一口气滑到顶部(即用力一滑,让页面自动滚动到顶部),会直接出发下拉刷新,一般是到顶部后就停了,再下拉才会触发下拉刷新,不过很多人滑到顶部本身就习惯再多下拉一下,刷新页面,保证到了顶部以及获取最新的数据,这有可能刚好符合某些人的需要。
  • 缺点二:见视频第20秒,下拉刷新与滑动切换可能会同时触发,导致感觉上不完美,但是不影响功能,不会导致bug,出现这个效果是因为列表在顶部了,此时手指斜向下拉,同时触发了滑动和下拉刷新的事件导致,不故意这么做的话,一般不会产生这种问题,即使故意这么做了,也不会导致数据加载错误。
  • 缺点一优化方案:使用一个 flag 做为 refresher-enabled 的属性值,判断滚动区域内容当前是否在最顶部,如果不在顶部,该值为 false,否则为 true。
  • 缺点二优化方案:同样使用一个 flag 做为 refresher-enabled 的属性值,同时使用 @transition 和 @animationfinish 监听 swiper 窗口是否开始滑动或滑动结束,在滑动开始时 flag = false,结束时 flag = true。
  • refresher-enabled 为 scroll-view 的属性,作用是设置是否可下拉刷新。

index.vue 页面代码

<template>
	<view class="tui-tabs">
		<scroll-view id="tab-bar" scroll-x scroll-with-animation class="tui-scroll-h" :show-scrollbar="false" :scroll-into-view="scrollInto">
			<view v-for="(tab, index) in tabBars" :key="tab.id" class="tui-tab-item" :id="tab.id" :data-current="index" @click="tabClick">
				<text class="tui-tab-item-title" :class="{ 'tui-tab-item-title-active': tabIndex == index }">{{ tab.name }}</text>
			</view>
		</scroll-view>
		<view class="tui-line-h"></view>
		<swiper :current="tabIndex" class="tui-swiper-box" :duration="300" @change="tabChange" @transition="swiperTransition" @animationfinish="swiperAnimationfinish">
			<swiper-item class="tui-swiper-item" v-for="(tab, index1) in newsList" :key="index1">
				<scroll-view
					class="tui-scroll-v"
					:refresher-enabled="refresherEnabled"
					:refresher-triggered="tab.refreshing"
					refresher-background="#fafafa"
					enable-back-to-top
					:refresher-threshold="100"
					scroll-y
					@scrolltolower="loadMore(index1)"
					@refresherrefresh="onrefresh"
				>
					<view v-for="(newsitem, index2) in tab.data" :key="newsitem.id">
						<news-item :itemData="newsitem" @close="close(index1, index2)" :lastChild="index2 === tab.data.length - 1" @click="goDetail(newsitem)"></news-item>
					</view>
					<view class="tui-loading-more" v-if="tab.isLoading || tab.pageIndex > 3">
						<text class="tui-loadmore-line" v-if="tab.pageIndex > 3"></text>
						<text class="tui-loading-more-text">{{ tab.loadingText }}</text>
					</view>
				</scroll-view>
			</swiper-item>
		</swiper>
	</view>
</template>
<script>
import newsItem from './news-item.vue';

// 缓存最多页数
const MAX_CACHE_PAGEINDEX = 3;
// 缓存页签数量
const MAX_CACHE_PAGE = 3;

const newsData = [
	{
		title: '温故知新老师们这些话要牢记',
		image_url: 'https://img-cdn-qiniu.dcloud.net.cn/uniapp/images/cbd.jpg?imageView2/3/w/200/h/100/q/90',
		comment_count: 3101,
		vote_count: 2356,
		dateTime: '2020-01-01',
		article_type: 1,
		source: '央视网新闻'
	},
	{
		title: '美国会表决通过新驻华大使 月底有望赴华',
		image_url: 'https://img-cdn-qiniu.dcloud.net.cn/uniapp/images/muwu.jpg?imageView2/3/w/200/h/100/q/90',
		comment_count: 3102,
		vote_count: 2356,
		dateTime: '2020-01-01',
		article_type: 1,
		source: '央视网新闻'
	},
	{
		title: '哪些专业毕业后收入高?计算机、金融专业排前列金融专业排前列金融专业排前列金融专业排前列金融专业排前列',
		image_url: 'https://img-cdn-qiniu.dcloud.net.cn/uniapp/images/shuijiao.jpg?imageView2/3/w/200/h/100/q/90',
		comment_count: 3103,
		vote_count: 2356,
		dateTime: '2020-01-01',
		article_type: 1,
		source: '粤港精英联盟'
	},
	{
		title: '科创板交易系统准备就绪,不存在首批名单',
		image_url: 'https://img-cdn-qiniu.dcloud.net.cn/uniapp/images/cbd.jpg?imageView2/3/w/200/h/100/q/90',
		comment_count: 3104,
		vote_count: 2356,
		dateTime: '2020-01-01',
		article_type: 1,
		source: '百科故事大全'
	},
	{
		title: '哪些专业毕业后收入高?计算机、金融专业排前列金融专业排前列金融专业排前列金融专业排前列金融专业排前列',
		image_url: 'https://img-cdn-qiniu.dcloud.net.cn/uniapp/images/shuijiao.jpg?imageView2/3/w/200/h/100/q/90',
		comment_count: 3103,
		vote_count: 2356,
		dateTime: '2020-01-01',
		article_type: 1,
		source: '粤港精英联盟'
	},
	{
		title: '科创板交易系统准备就绪,不存在首批名单',
		image_url: 'https://img-cdn-qiniu.dcloud.net.cn/uniapp/images/cbd.jpg?imageView2/3/w/200/h/100/q/90',
		comment_count: 3104,
		vote_count: 2356,
		dateTime: '2020-01-01',
		article_type: 1,
		source: '百科故事大全'
	},
	{
		title: '哪些专业毕业后收入高?计算机、金融专业排前列金融专业排前列金融专业排前列金融专业排前列金融专业排前列',
		image_url: 'https://img-cdn-qiniu.dcloud.net.cn/uniapp/images/shuijiao.jpg?imageView2/3/w/200/h/100/q/90',
		comment_count: 3103,
		vote_count: 2356,
		dateTime: '2020-01-01',
		article_type: 1,
		source: '粤港精英联盟'
	},
	{
		title: '科创板交易系统准备就绪,不存在首批名单',
		image_url: 'https://img-cdn-qiniu.dcloud.net.cn/uniapp/images/cbd.jpg?imageView2/3/w/200/h/100/q/90',
		comment_count: 3104,
		vote_count: 2356,
		dateTime: '2020-01-01',
		article_type: 1,
		source: '百科故事大全'
	},
];

export default {
	components: {
		newsItem
	},
	data() {
		return {
			isIos: false,
			newsList: [],
			cacheTab: [],
			tabIndex: 0,
			tabBars: [],
			scrollInto: '',
			showTips: false,
			navigateFlag: false,
			pulling: false,
			refreshIcon:
				'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFEAAABRBAMAAABYoVcFAAAAKlBMVEUAAACXl5eZmZmfn5+YmJiXl5eampqZmZmYmJiYmJiZmZmYmJiZmZmZmZl02B9kAAAADXRSTlMAQKAQ0GAsUN+wz5CA21ow0AAAAM5JREFUSMftzLEJAkEQheFR4WzjGji4wC5E0A7E0OgaEIwF4RqwJEEODKcX1114yQ/uhsLtY6Lh57NZ7Dz1heXd27Kwcb+WlQv3Vy1rWcta1rKW/1Q2R8PWt8FYdhPLi79ZLt33KB/hibJzH1E+PaAqRfqAcuMBVSlyMmy1C6hKka0CoCpBAlUJEmgsQQJVCRKoSpBAU0mSaCpJEk0lSSMaS5JG9FuK/IkeQkmSaEjikSSaRpJoHEmiIvOoyCwqMo+KzKMi8+hoZTtte5vDPrSGI5zJ/Z1kAAAAAElFTkSuQmCC'
		};
	},
	onLoad() {
		setTimeout(() => {
			this.tabBars = [
				{
					name: '热门',
					id: 'hot'
				},
				{
					name: '娱乐',
					id: 'yule'
				},
				{
					name: '体育',
					id: 'sports'
				},
				{
					name: '国内',
					id: 'domestic'
				},
				{
					name: '财经',
					id: 'finance'
				},
				{
					name: '科技',
					id: 'keji'
				},
				{
					name: '教育',
					id: 'education'
				},
				{
					name: '汽车',
					id: 'car'
				}
			]
			this.init()
		}, 200);
	},
	methods: {
		init() {
			this.newsList = this.randomfn();
		},
		randomfn() {
			let ary = [];
			for (let i = 0, length = this.tabBars.length; i < length; i++) {
				let aryItem = {
					loadingText: '正在加载...',
					refreshing: false,
					refreshText: '',
					data: [],
					isLoading: false,
					pageIndex: 1
				};
				if (i === 0) {
					aryItem.pageIndex = 2;
					aryItem.data = aryItem.data.concat(newsData);
				}
				ary.push(aryItem);
			}
			console.log(ary)
			return ary;
		},
		getList(index, refresh) {
			let activeTab = this.newsList[index];
			let list = newsData || [];
			if (refresh) {
				activeTab.data = [];
				activeTab.loadingText = '正在加载...';
				activeTab.pageIndex = 2;
				activeTab.data = list || [];
			} else {
				activeTab.data = activeTab.data.concat(list);
				activeTab.pageIndex++;
				activeTab.isLoading = false;
				//根据实际修改判断条件
				if (activeTab.pageIndex > 3) {
					activeTab.loadingText = '没有更多了';
				}
			}
		},
		goDetail(e) {
			if (this.navigateFlag) return;
			this.navigateFlag = true;
			uni.navigateTo({
				url: '/pages/template/news/newsDetail/newsDetail'
			});
			setTimeout(() => {
				this.navigateFlag = false;
			}, 200);
		},
		loadMore(e) {
			let activeTab = this.newsList[this.tabIndex];
			if (activeTab.pageIndex < 4 && !activeTab.isLoading) {
				activeTab.isLoading = true;
				setTimeout(() => {
					this.getList(this.tabIndex);
				}, 300);
			}
		},
		tabClick(e) {
			let index = e.target.dataset.current || e.currentTarget.dataset.current;
			this.switchTab(index);
		},
		tabChange(e) {
			let index = e.target.current || e.detail.current;
			this.switchTab(index);
		},
		swiperTransition() {
			this.refresherEnabled = false;
		},
		swiperAnimationfinish() {
			this.refresherEnabled = true;
		},
		switchTab(index) {
			if (this.tabIndex === index) return;
			if (this.newsList[index].data.length === 0) {
				this.getList(index);
			}
			// 缓存 tabId
			if (this.newsList[this.tabIndex].pageIndex > MAX_CACHE_PAGEINDEX) {
				let isExist = this.cacheTab.indexOf(this.tabIndex);
				if (isExist < 0) {
					this.cacheTab.push(this.tabIndex);
					//console.log("cache index:: " + this.tabIndex);
				}
			}

			this.tabIndex = index;
			let scrollIndex = index - 1 < 0 ? 0 : index - 1;
			this.scrollInto = this.tabBars[scrollIndex].id;

			// 释放 tabId
			if (this.cacheTab.length > MAX_CACHE_PAGE) {
				let cacheIndex = this.cacheTab[0];
				this.clearTabData(cacheIndex);
				this.cacheTab.splice(0, 1);
				//console.log("remove cache index:: " + cacheIndex);
			}
		},
		clearTabData(e) {
			this.newsList[e].data.length = 0;
			this.newsList[e].loadingText = '加载更多...';
		},
		onrefresh(e) {
			var tab = this.newsList[this.tabIndex];
			if (tab.refreshing) {
				return;
			}

			tab.refreshing = true;

			setTimeout(() => {
				uni.stopPullDownRefresh();
				this.getList(this.tabIndex, true);
				this.pulling = true;
				tab.refreshing = false;
				uni.showToast({
					title: '刷新成功',
					icon: 'none'
				});
				setTimeout(() => {
					// TODO fix ios和Android 动画时间相反问题
					this.pulling = false;
				}, 500);
			}, 3000);
		},
	},
	onPullDownRefresh() {
		console.log('onPullDownRefresh')
	}
};
</script>

<style>
page {
	width: 100%;
	min-height: 100%;
	display: flex;
	height: 100vh;
}

.tui-tabs {
	flex: 1;
	flex-direction: column;
	overflow: hidden;
	background-color: #fafafa;
}

.tui-scroll-h {
	white-space: nowrap;
	height: 80rpx;
	background-color: #ffffff;
	display: flex;
	flex-direction: row;
	/* #ifdef H5 */
	position: fixed;
	top: 44px;
	left: 0;
	z-index:999;
	/* #endif */
}

.tui-line-h {
	height: 1rpx;
	background-color: #cccccc;
	position: relative;
}

.tui-tab-item {
	display: inline-block;
	padding-left: 34rpx;
	padding-right: 34rpx;
	flex-wrap: nowrap;
}

.tui-tab-item-title {
	color: #555;
	font-size: 30rpx;
	height: 80rpx;
	line-height: 80rpx;
	flex-wrap: nowrap;
	white-space: nowrap;
}

.tui-tab-item-title-active {
	color: #5677fc;
	font-size: 36rpx;
	font-weight: bold;
	border-bottom: 6rpx solid #5677fc;
	text-align: center;
	display: block;
	box-sizing: border-box;
}

.tui-swiper-box {
	height: 100%;
	overflow-y: auto;
	/* #ifdef H5 */
	margin-top: 80rpx;
	/* #endif */
}

.tui-swiper-item {
	flex: 1 !important;
	flex-direction: row;
}

.tui-scroll-v {
	width: 100%;
	height: 100%;
}

.tui-loading-more {
	align-items: center;
	justify-content: center;
	padding-top: 15px;
	padding-bottom: 15px;
	text-align: center;
	position: relative;
}

.tui-loadmore-line {
	border-bottom-width: 1rpx;
	border-bottom-style: solid;
	border-bottom-color: #e5e5e5;
	width: 320rpx;
	position: absolute;
	z-index: -1;
}

.tui-loading-more-text {
	padding-left: 8rpx;
	padding-right: 8rpx;
	font-size: 28rpx;
	line-height: 28rpx;
	background-color: #fafafa;
	text-align: center;
	color: #999;
}
</style>

二、使用 nvue 页面实现

点此查看录屏效果

  • 这个方式没有以上 vue 页面方式的2个缺点,但有其他缺点
  • 缺点一:使用的是 nvue 页面,nvue 页面的 css 样式不支持很多特性
  • 缺点二:nvue 页面不支持常规模式引入的 iconfont 文字图标,必须使用其特定的方式引入,目前我试过,但还没试成功

index.nvue 页面代码(其内部组件可以是 vue 页面)

<template>
	<view class="tui-tabs">
		<scroll-view id="tab-bar" scroll-with-animation class="tui-scroll-h" :scroll-x="true" :show-scrollbar="false" :scroll-into-view="scrollInto">
			<view v-for="(tab, index) in tabBars" :key="tab.id" class="tui-tab-item" :id="tab.id" :data-current="index" @click="tabClick">
				<!-- #ifdef APP-PLUS -->
				<text class="tui-tab-item-title" :class="{ 'tui-tab-item-title-active': tabIndex == index }">{{ tab.name }}</text>
				<!-- #endif -->
				<!-- #ifndef APP-PLUS -->
				<view class="tui-tab-item-title" :class="{ 'tui-tab-item-title-active': tabIndex == index }">{{ tab.name }}</view>
				<!-- #endif -->
			</view>
		</scroll-view>
		<view class="tui-line-h"></view>
		<swiper :current="tabIndex" class="tui-swiper-box" :duration="300" @change="tabChange">
			<swiper-item class="tui-swiper-item" v-for="(tab, index1) in newsList" :key="index1">
				<!-- #ifdef APP-NVUE -->
				<list class="tui-scroll-v" enableBackToTop="true" scroll-y loadmoreoffset="15" @loadmore="loadMore(index1)">
					<refresh class="tui-refresh" @refresh="onrefresh(index1)" @pullingdown="onpullingdown" :display="tab.refreshing ? 'show' : 'hide'">
						<div class="tui-refresh-view">
							<image
								class="tui-refresh-icon"
								:src="refreshIcon"
								:style="{ width: tab.refreshing || pulling ? 0 : '20px' }"
								:class="{ 'tui-refresh-icon-active': tab.refreshFlag }"
							></image>
							<loading-indicator class="tui-loading-icon" animating="true" v-if="tab.refreshing"></loading-indicator>
							<text class="tui-loading-text">{{ tab.refreshText }}</text>
						</div>
					</refresh>
					<cell v-for="(newsitem, index2) in tab.data" :key="newsitem.id">
						<news-item :itemData="newsitem" @close="close(index1, index2)" :lastChild="index2 === tab.data.length - 1" @click="goDetail(newsitem)"></news-item>
					</cell>
					<cell class="tui-loading-more" v-if="tab.isLoading || tab.pageIndex > 3">
						<text class="tui-loadmore-line" v-if="tab.pageIndex > 3"></text>
						<text class="tui-loading-more-text">{{ tab.loadingText }}</text>
					</cell>
				</list>
				<!-- #endif -->
				<!-- #ifndef APP-NVUE -->
				<scroll-view
					class="tui-scroll-v"
					refresher-enabled
					:refresher-triggered="tab.refreshing"
					refresher-background="#fafafa"
					enable-back-to-top
					:refresher-threshold="100"
					scroll-y
					@scrolltolower="loadMore(index1)"
					@refresherrefresh="onrefresh"
				>
					<view v-for="(newsitem, index2) in tab.data" :key="newsitem.id">
						<news-item :itemData="newsitem" @close="close(index1, index2)" :lastChild="index2 === tab.data.length - 1" @click="goDetail(newsitem)"></news-item>
					</view>
					<view class="tui-loading-more" v-if="tab.isLoading || tab.pageIndex > 3">
						<text class="tui-loadmore-line" v-if="tab.pageIndex > 3"></text>
						<text class="tui-loading-more-text">{{ tab.loadingText }}</text>
					</view>
				</scroll-view>
				<!-- #endif -->
			</swiper-item>
		</swiper>
	</view>
</template>
<script>
import newsItem from './news-item.nvue';

// 缓存最多页数
const MAX_CACHE_PAGEINDEX = 3;
// 缓存页签数量
const MAX_CACHE_PAGE = 3;

const newsData = [
	{
		title: '温故知新老师们这些话要牢记',
		image_url: 'https://img-cdn-qiniu.dcloud.net.cn/uniapp/images/cbd.jpg?imageView2/3/w/200/h/100/q/90',
		comment_count: 3101,
		vote_count: 2356,
		dateTime: '2020-01-01',
		article_type: 1,
		source: '央视网新闻'
	},
	{
		title: '美国会表决通过新驻华大使 月底有望赴华',
		image_url: 'https://img-cdn-qiniu.dcloud.net.cn/uniapp/images/muwu.jpg?imageView2/3/w/200/h/100/q/90',
		comment_count: 3102,
		vote_count: 2356,
		dateTime: '2020-01-01',
		article_type: 1,
		source: '央视网新闻'
	},
	{
		title: '哪些专业毕业后收入高?计算机、金融专业排前列金融专业排前列金融专业排前列金融专业排前列金融专业排前列',
		image_url: 'https://img-cdn-qiniu.dcloud.net.cn/uniapp/images/shuijiao.jpg?imageView2/3/w/200/h/100/q/90',
		comment_count: 3103,
		vote_count: 2356,
		dateTime: '2020-01-01',
		article_type: 1,
		source: '粤港精英联盟'
	},
	{
		title: '科创板交易系统准备就绪,不存在首批名单',
		image_url: 'https://img-cdn-qiniu.dcloud.net.cn/uniapp/images/cbd.jpg?imageView2/3/w/200/h/100/q/90',
		comment_count: 3104,
		vote_count: 2356,
		dateTime: '2020-01-01',
		article_type: 1,
		source: '百科故事大全'
	},
	{
		title: '哪些专业毕业后收入高?计算机、金融专业排前列金融专业排前列金融专业排前列金融专业排前列金融专业排前列',
		image_url: 'https://img-cdn-qiniu.dcloud.net.cn/uniapp/images/shuijiao.jpg?imageView2/3/w/200/h/100/q/90',
		comment_count: 3103,
		vote_count: 2356,
		dateTime: '2020-01-01',
		article_type: 1,
		source: '粤港精英联盟'
	},
	{
		title: '科创板交易系统准备就绪,不存在首批名单',
		image_url: 'https://img-cdn-qiniu.dcloud.net.cn/uniapp/images/cbd.jpg?imageView2/3/w/200/h/100/q/90',
		comment_count: 3104,
		vote_count: 2356,
		dateTime: '2020-01-01',
		article_type: 1,
		source: '百科故事大全'
	},
];

export default {
	components: {
		newsItem
	},
	data() {
		return {
			isIos: false,
			newsList: [],
			cacheTab: [],
			tabIndex: 0,
			tabBars: [
				{
					name: '热门',
					id: 'hot'
				},
				{
					name: '娱乐',
					id: 'yule'
				},
				{
					name: '体育',
					id: 'sports'
				},
				{
					name: '国内',
					id: 'domestic'
				},
				{
					name: '财经',
					id: 'finance'
				},
				{
					name: '科技',
					id: 'keji'
				},
				{
					name: '教育',
					id: 'education'
				},
				{
					name: '汽车',
					id: 'car'
				}
			],
			scrollInto: '',
			showTips: false,
			navigateFlag: false,
			pulling: false,
			refreshIcon:
				'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFEAAABRBAMAAABYoVcFAAAAKlBMVEUAAACXl5eZmZmfn5+YmJiXl5eampqZmZmYmJiYmJiZmZmYmJiZmZmZmZl02B9kAAAADXRSTlMAQKAQ0GAsUN+wz5CA21ow0AAAAM5JREFUSMftzLEJAkEQheFR4WzjGji4wC5E0A7E0OgaEIwF4RqwJEEODKcX1114yQ/uhsLtY6Lh57NZ7Dz1heXd27Kwcb+WlQv3Vy1rWcta1rKW/1Q2R8PWt8FYdhPLi79ZLt33KB/hibJzH1E+PaAqRfqAcuMBVSlyMmy1C6hKka0CoCpBAlUJEmgsQQJVCRKoSpBAU0mSaCpJEk0lSSMaS5JG9FuK/IkeQkmSaEjikSSaRpJoHEmiIvOoyCwqMo+KzKMi8+hoZTtte5vDPrSGI5zJ/Z1kAAAAAElFTkSuQmCC'
		};
	},
	onLoad() {
		setTimeout(() => {
			this.newsList = this.randomfn();
			uni.getSystemInfo({
				success: res => {
					this.isIos = 'ios' == res.platform.toLocaleLowerCase();
				}
			});
		}, 200);
	},
	methods: {
		randomfn() {
			let ary = [];
			for (let i = 0, length = this.tabBars.length; i < length; i++) {
				let aryItem = {
					loadingText: '正在加载...',
					refreshing: false,
					refreshText: '',
					data: [],
					isLoading: false,
					pageIndex: 1
				};
				if (i === 0) {
					aryItem.pageIndex = 2;
					aryItem.data = aryItem.data.concat(newsData);
				}
				ary.push(aryItem);
			}
			console.log(ary)
			return ary;
		},
		getList(index, refresh) {
			let activeTab = this.newsList[index];
			let list = newsData || [];
			if (refresh) {
				activeTab.data = [];
				activeTab.loadingText = '正在加载...';
				activeTab.pageIndex = 2;
				activeTab.data = list || [];
			} else {
				activeTab.data = activeTab.data.concat(list);
				activeTab.pageIndex++;
				activeTab.isLoading = false;
				//根据实际修改判断条件
				if (activeTab.pageIndex > 3) {
					activeTab.loadingText = '没有更多了';
				}
			}
		},
		goDetail(e) {
			if (this.navigateFlag) return;
			this.navigateFlag = true;
			uni.navigateTo({
				url: '/pages/template/news/newsDetail/newsDetail'
			});
			setTimeout(() => {
				this.navigateFlag = false;
			}, 200);
		},
		loadMore(e) {
			let activeTab = this.newsList[this.tabIndex];
			if (activeTab.pageIndex < 4 && !activeTab.isLoading) {
				activeTab.isLoading = true;
				setTimeout(() => {
					this.getList(this.tabIndex);
				}, 300);
			}
		},
		tabClick(e) {
			let index = e.target.dataset.current || e.currentTarget.dataset.current;
			this.switchTab(index);
		},
		tabChange(e) {
			let index = e.target.current || e.detail.current;
			this.switchTab(index);
		},
		switchTab(index) {
			if (this.tabIndex === index) return;
			if (this.newsList[index].data.length === 0) {
				this.getList(index);
			}
			// 缓存 tabId
			if (this.newsList[this.tabIndex].pageIndex > MAX_CACHE_PAGEINDEX) {
				let isExist = this.cacheTab.indexOf(this.tabIndex);
				if (isExist < 0) {
					this.cacheTab.push(this.tabIndex);
					//console.log("cache index:: " + this.tabIndex);
				}
			}

			this.tabIndex = index;
			let scrollIndex = index - 1 < 0 ? 0 : index - 1;
			this.scrollInto = this.tabBars[scrollIndex].id;

			// 释放 tabId
			if (this.cacheTab.length > MAX_CACHE_PAGE) {
				let cacheIndex = this.cacheTab[0];
				this.clearTabData(cacheIndex);
				this.cacheTab.splice(0, 1);
				//console.log("remove cache index:: " + cacheIndex);
			}
		},
		clearTabData(e) {
			this.newsList[e].data.length = 0;
			this.newsList[e].loadingText = '加载更多...';
		},
		onrefresh(e) {
			var tab = this.newsList[this.tabIndex];
			// #ifdef APP-PLUS
			if (!tab.refreshFlag) {
				return;
			}
			// #endif

			// #ifndef APP-PLUS
			if (tab.refreshing) {
				return;
			}
			// #endif

			tab.refreshing = true;
			tab.refreshText = '正在刷新...';

			setTimeout(() => {
				this.getList(this.tabIndex, true);
				this.pulling = true;
				tab.refreshing = false;
				tab.refreshFlag = false;
				tab.refreshText = '刷新成功';
				// #ifndef H5
				uni.showToast({
					title: '刷新成功',
					icon: 'none'
				});
				// #endif
				setTimeout(() => {
					// TODO fix ios和Android 动画时间相反问题
					this.pulling = false;
				}, 500);
			}, 1000);
		},
		onpullingdown(e) {
			var tab = this.newsList[this.tabIndex];
			if (tab.refreshing || this.pulling) {
				return;
			}
			if (Math.abs(e.pullingDistance) > Math.abs(e.viewHeight)) {
				tab.refreshFlag = true;
				tab.refreshText = '释放立即刷新';
			} else {
				tab.refreshFlag = false;
				tab.refreshText = '下拉可以刷新';
			}
		}
	}
};
</script>

<style>
/* #ifndef APP-PLUS */
page {
	width: 100%;
	min-height: 100%;
	display: flex;
}

/* #endif */

.tui-tabs {
	flex: 1;
	flex-direction: column;
	overflow: hidden;
	background-color: #fafafa;
	/* #ifdef MP-ALIPAY || MP-BAIDU */
	height: 100vh;
	/* #endif */
}

.tui-scroll-h {
	width: 750rpx;
	height: 80rpx;
	background-color: #ffffff;
	flex-direction: row;
	/* #ifndef APP-PLUS */
	white-space: nowrap;
	/* #endif */
	/* #ifdef H5 */
	position: fixed;
	top: 44px;
	left: 0;
	z-index:999;
	/* #endif */
}

.tui-line-h {
	/* #ifdef APP-PLUS */
	height: 1rpx;
	background-color: #cccccc;
	/* #endif */
	position: relative;
}
/* #ifndef APP-PLUS*/
.tui-line-h::after {
	content: '';
	position: absolute;
	border-bottom: 1rpx solid #cccccc;
	-webkit-transform: scaleY(0.5);
	transform: scaleY(0.5);
	bottom: 0;
	right: 0;
	left: 0;
}
/* #endif */

.tui-tab-item {
	/* #ifndef APP-PLUS */
	display: inline-block;
	/* #endif */
	flex-wrap: nowrap;
	padding-left: 34rpx;
	padding-right: 34rpx;
}

.tui-tab-item-title {
	color: #555;
	font-size: 30rpx;
	height: 80rpx;
	line-height: 80rpx;
	flex-wrap: nowrap;
	/* #ifndef APP-PLUS */
	white-space: nowrap;
	/* #endif */
}

.tui-tab-item-title-active {
	color: #5677fc;
	font-size: 36rpx;
	font-weight: bold;
	border-bottom-width: 6rpx;
	border-style: solid;
	border-color: #5677fc;
	text-align: center;
}

.tui-swiper-box {
	flex: 1 !important;
	/* #ifdef H5 */
	margin-top: 80rpx;
	/* #endif */
}

.tui-swiper-item {
	flex: 1 !important;
	flex-direction: row;
}

.tui-scroll-v {
	flex: 1;
	/* #ifndef MP-ALIPAY */
	flex-direction: column;
	/* #endif */
	width: 750rpx;
}

.tui-update-tips {
	position: absolute;
	left: 0;
	top: 41px;
	right: 0;
	padding-top: 5px;
	padding-bottom: 5px;
	background-color: #fddd9b;
	align-items: center;
	justify-content: center;
	text-align: center;
}

.tui-update-tips-text {
	font-size: 14px;
	color: #ffffff;
}

.tui-refresh {
	width: 750rpx;
	height: 64px;
	justify-content: center;
}

.tui-refresh-view {
	flex-direction: row;
	flex-wrap: nowrap;
	align-items: center;
	justify-content: center;
}

.tui-refresh-icon {
	width: 20px;
	height: 20px;
	transition-duration: 0.25s;
	transition-property: transform;
	transform: rotate(0deg);
	transform-origin: 10px 10px;
}

.tui-refresh-icon-active {
	transform: rotate(180deg);
}

.tui-loading-icon {
	width: 20px;
	height: 20px;
	margin-right: 5px;
	color: #999999;
}

.tui-loading-text {
	margin-left: 2px;
	font-size: 14px;
	color: #999999;
}

.tui-loading-more {
	align-items: center;
	justify-content: center;
	padding-top: 15px;
	padding-bottom: 15px;
	text-align: center;
	position: relative;
}
.tui-loadmore-line {
	border-bottom-width: 1rpx;
	border-bottom-style: solid;
	border-bottom-color: #e5e5e5;
	width: 320rpx;
	position: absolute;
	z-index: -1;
}

.tui-loading-more-text {
	padding-left: 8rpx;
	padding-right: 8rpx;
	font-size: 28rpx;
	line-height: 28rpx;
	background-color: #fafafa;
	text-align: center;
	color: #999;
}
</style>

三、共同子组件的代码

newsItem.vue 组件代码

<template>
	<view class="media-item" v-if="itemData.title" @click="click">
		<view class="main">
			<text class="media-title media-title2">{{itemData.title}}</text>
			<view v-if="itemData.image_url" class="image-section flex-row image-section-left">
				<image class="image-list1 image-list2" :src="itemData.image_url"></image>
			</view>
		</view>
		<view class="media-foot flex-row">
			<view class="media-info flex-row">
				<text class="info-text">{{itemData.source}}</text>
				<text class="info-text">{{itemData.comment_count}}条评论</text>
				<text class="info-text">{{itemData.vote_count}}条投票</text>
				<text class="info-text">{{itemData.dateTime}}</text>
			</view>
		</view>
		<view class="media-item-line" style="position: absolute;"></view>
	</view>
</template>

<script>
	export default {
		props: {
			itemData: {
				type: Object,
				default: () => {}
			}
		},
		methods: {
			click() {
				this.$emit('click');
			},
		}
	}
</script>

<style scoped>
	.main {
		flexDirection: row-reverse;
	}

	.flex-row {
		flex-direction: row;
	}

	.flex-col {
		flex-direction: column;
	}

	.list-cell {
		padding: 0 30upx;
	}

	.uni-list-cell-hover {
		background-color: #eeeeee;
	}

	.media-item {
		position: relative;
		flex: 1;
		flex-direction: column;
		padding: 20upx 30upx 21upx 30upx;
	}

	.media-item-line {
		position: absolute;
		left: 30upx;
		right: 30upx;
		bottom: 0;
		height: 1upx;
		background-color: #ebebeb;
	}

	.media-image-right {
		flex-direction: row;
	}

	.media-image-left {
		flex-direction: row-reverse;
	}

	.media-title {
		flex: 1;
	}

	.media-title {
		lines: 3;
		text-overflow: ellipsis;
		font-size: 30upx;
		color: #555555;
	}

	.media-title2 {
		flex: 1;
		margin-top: 6upx;
		line-height: 40upx;
	}

	.image-section {
		margin-top: 20upx;
		flex-direction: row;
		justify-content: space-between;
	}

	.image-section-right {
		margin-top: 0upx;
		margin-left: 10upx;
		width: 225upx;
		height: 146upx;
	}

	.image-section-left {
		margin-top: 0upx;
		margin-right: 10upx;
		width: 225upx;
		height: 146upx;
	}

	.image-list1 {
		width: 690upx;
		height: 481upx;
	}

	.image-list2 {
		width: 225upx;
		height: 146upx;
	}

	.image-list3 {
		width: 225upx;
		height: 146upx;
	}

	.media-info {
		flex-direction: row;
		align-items: center;
	}

	.info-text {
		margin-right: 20upx;
		color: #999999;
		font-size: 24upx;
	}

	.media-foot {
		margin-top: 25upx;
		flex-direction: row;
		align-items: center;
		justify-content: space-between;
	}

	.close-view {
		position: relative;
		align-items: center;
		flex-direction: row;
		width: 40upx;
		height: 30upx;
		line-height: 30upx;
		border-width: 1upx;
		border-style: solid;
		border-color: #aaaaaa;
		border-radius: 4px;
		justify-content: center;
		text-align: center;
	}

	.close-l {
		position: absolute;
		width: 18upx;
		height: 1upx;
		background-color: #aaaaaa;
	}

	.close-h {
		transform: rotate(45deg);
	}

	.close-v {
		transform: rotate(-45deg);
	}
</style>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章