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>

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