前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >uni-app实战之社区交友APP(6)动态页开发

uni-app实战之社区交友APP(6)动态页开发

作者头像
cutercorley
发布2021-02-02 10:15:57
1.6K0
发布2021-02-02 10:15:57
举报

文章目录

  • 前言
  • 一、顶部导航栏开发
  • 二、关注列表页开发
    • 1.滑动滚动区域运算
    • 2.导航列表联动实现
    • 3.顶踩操作和上拉加载功能
  • 三、话题专题和分类页开发
    • 1.热门分类组件开发和封装
    • 2.搜索框和轮播图开发
    • 3.话题列表组件开发和封装
    • 4.话题分类页开发
  • 四、话题详情页开发
    • 1.pages.json配置和数据传递
    • 2.话题介绍组件开发和封装
    • 3.精华帖子列表组件开发
    • 4.列表选项卡组件开发
    • 5.话题详情上拉加载更多
  • 总结

前言

本文主要介绍了动态页的开发,主要包括4部分: 顶部导航栏的开发; 关注列表页的开发,包括滑动滚动区域、联动、顶踩事件和上拉加载; 话题专题和分类页开发,包括热门分类组件、搜索框、轮播图、话题列表组件和话题分类页; 话题详情页开发,包括数据传递、话题介绍组件、精华帖子列表、列表选项卡组件和上拉加载更多。

一、顶部导航栏开发

动态页包括顶部导航栏、关注列表和话题列表。 顶部导航栏需要实现自定义,news.vue如下:

代码语言:javascript
复制
<template>
	<view>
		<!-- 导航栏 -->
		<uni-nav-bar>
			<view class="flex align-center justify-center font-weight-bold w-100">
				<view class="font-lg text-main mx-1">关注</view>
				<view class="font-md text-light-muted mx-1">话题</view>
			</view>
			<text slot="right" class="iconfont icon-fatie_icon"></text>
		</uni-nav-bar>
	</view>
</template>

<script>
	import uniNavBar from '@/components/uni-ui/uni-nav-bar/uni-nav-bar.vue';
	export default {
		data() {
			return {
				
			}
		},
		components: {
			uniNavBar
		},
		methods: {
			
		}
	}
</script>

<style>

</style>

base.css如下:

代码语言:javascript
复制
/* 内外边距 */
.p-2 {
	padding: 20rpx;
}

/* flex布局 */
.flex {
	/* #ifndef APP-APP-PLUS-NVUE */
	display: flex;
	/* #endif */
	flex-direction: row;
}

.flex-wrap {
	flex-wrap: wrap;
}

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

.align-center {
	align-items: center;
}

.justify-between {
	justify-content: space-between;
}

.justify-center {
	justify-content: center;
}

.flex-1 {
	flex: 1;
}

/* 圆角 */
.rounded-circle {
	border-radius: 100%;
}

.rounded {
	border-radius: 8rpx;
}

/* margin */
.mr-2 {
	margin-right: 20rpx;
}

.my-1 {
	margin-top: 10rpx;
	margin-bottom: 10rpx;
}

.mx-2 {
	margin-left: 20rpx;
	margin-right: 20rpx;
}

.mx-1 {
	margin-left: 10rpx;
	margin-right: 10rpx;
}

.mt-1 {
	margin-top: 10rpx;
}

.ml-auto {
	margin-left: auto;
}

/* padding */
.p-2 {
	padding-left: 20rpx;
	padding-right: 20rpx;
	padding-top: 20rpx;
	padding-bottom: 20rpx;
}

.px-5 {
	padding-left: 50rpx;
	padding-right: 50rpx;
}

.px-3 {
	padding-left: 30rpx;
	padding-right: 30rpx;
}

.px-2 {
	padding-left: 20rpx;
	padding-right: 20rpx;
}

.px-1 {
	padding-left: 10rpx;
	padding-right: 10rpx;
}

.py-3 {
	padding-top: 30rpx;
	padding-bottom: 30rpx;
}

.py-2 {
	padding-top: 20rpx;
	padding-bottom: 20rpx;
}

.pt-7 {
	padding-top: 70rpx;
}

.pb-2 {
	padding-bottom: 20rpx;
}

/* 边框 */
.border {
	border-width: 1rpx;
	border-style: solid;
	border-color: #DEE2E6;
}

.border-bottom {
	border-bottom: 1rpx solid #DEE2E6;
}

.border-light-secondary {
	border: 1rpx solid #AAA8AB;
}

/* 字体 */
.font-lg {
	font-size: 40rpx;
}

.font-md {
	font-size: 35rpx;
}

.font {
	font-size: 30rpx;
}

.font-sm {
	font-size: 25rpx;
}

.font-weight-bold {
	font-weight: bold;
}

/* 文字颜色 */
.text-white {
	color: #FFFFFF;
}

.text-light-muted {
	color: #A9A5A0;
}

/* 文字换行溢出处理 */
.text-ellipsis {
	/* #ifndef APP-PLUS-APP-PLUS-NVUE */
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
	/* #endif */
	/* #ifdef APP-PLUS-APP-PLUS-NVUE */
		lines: 1;
	/* #endif */
}

/* 宽度 */
/* #ifndef APP-PLUS-NVUE */
.w-100 {
	width: 100%;
}

/* #endif */

/* scroll-view */
/* #ifndef APP-PLUS-NVUE */
.scroll-row {
	width: 100%;
	white-space: nowrap;
}

.scroll-row-item {
	display: inline-block !important;
}

/* #endif */

/* 背景 */
.bg-light {
	background-color: #F8F9FA;
}

.bg-white {
	background-color: #FFFFFF;
}

.bg-dark {
	background-color: #333333;
}

/* 定位 */
.position-relative {
	position: relative;
}

.position-absolute {
	position: absolute;
}

.position-fixed {
	position: fixed;
}

/* 定位-固定顶部 */
.fixed-top {
	position: fixed;
	top: 0;
	right: 0;
	left: 0;
	z-index: 1030;
}

/* 定位-固定底部 */
.fixed-bottom {
	position: fixed;
	right: 0;
	bottom: 0;
	left: 0;
	z-index: 1030;
}

.top-0 {
	top: 0;
}

.left-0 {
	left: 0;
}

.right-0 {
	right: 0;
}

.bottom-0 {
	bottom: 0;
}

common.css如下:

代码语言:javascript
复制
/* 本项目全局样式 */
/* 背景 */
.bg-main {
	background-color: #FF4A6A;
}

/* 文本颜色 */
.text-main {
	color: #FF4A6A;
}

.text-secondry {
	color: #AAA8AB;
}

.text-dark {
	color: #333333;
}

显示:

uniapp social app trend develop navbar first
uniapp social app trend develop navbar first

可以看到,已经搭建好初步页面。

再完善样式,news.vue中给自定义导航栏取消边界、固定位置、添加状态栏,如下:

代码语言:javascript
复制
<!-- 导航栏 -->
<uni-nav-bar :border="false" :fixed="true" :statusBar="true">
    <view class="flex align-center justify-center font-weight-bold w-100">
        <view class="font-lg text-main mx-1">关注</view>
        <view class="font-md text-light-muted mx-1">话题</view>
    </view>
    <text slot="right" class="iconfont icon-fatie_icon"></text>
</uni-nav-bar>

同时在pages.json中禁止原生导航栏,如下:

代码语言:javascript
复制
{
    "path" : "pages/news/news",
    "style" :                                                                                    
    {
        "navigationBarTitleText": "",
        "enablePullDownRefresh": false,
        "app-plus": {
            "titleNView": false
        }
    }
    
}

显示:

uniapp social app trend develop navbar better
uniapp social app trend develop navbar better

显然,此时更加美观。

再添加点击事件,如下:

代码语言:javascript
复制
<template>
	<view>
		<!-- 导航栏 -->
		<uni-nav-bar :border="false" :fixed="true" :statusBar="true" @clickRight="openAddInput">
			<view class="flex align-center justify-center font-weight-bold w-100">
				<view class="mx-1" v-for="(item, index) in tabBars" :key="index" :class="tabIndex === index ? 'font-lg text-main' : 'font-md text-light-muted'" @click="changeTab(index)">{{item.name}}</view>
			</view>
			<text slot="right" class="iconfont icon-fatie_icon"></text>
		</uni-nav-bar>
	</view>
</template>

<script>
	import uniNavBar from '@/components/uni-ui/uni-nav-bar/uni-nav-bar.vue';
	export default {
		data() {
			return {
				tabBars: [{
						name: '关注'
					},
					{
						name: '话题'
					}
				],
				tabIndex: 0
			}
		},
		components: {
			uniNavBar
		},
		methods: {
			// 打开发布页
			openAddInput() {
				uni.navigateTo({
					url: '../add-input/add-input'
				});
			},
			// 切换选项卡
			changeTab(index) {
				this.tabIndex = index;
			}
		}
	}
</script>

<style>

</style>

显示:

uniapp social app trend develop navbar click
uniapp social app trend develop navbar click

显然,可以实现点击切换。

二、关注列表页开发

1.滑动滚动区域运算

关注和话题页面也是滚动区域,也是通过swiper嵌套scroll-view实现。 计算时,需要整体可用高度减去状态栏和自定义导航栏高度,如下:

代码语言:javascript
复制
<template>
	<view>
		<!-- 导航栏 -->
		<uni-nav-bar :border="false" :fixed="true" :statusBar="true" @clickRight="openAddInput">
			<view class="flex align-center justify-center font-weight-bold w-100">
				<view class="mx-1" v-for="(item, index) in tabBars" :key="index" :class="tabIndex === index ? 'font-lg text-main' : 'font-md text-light-muted'" @click="changeTab(index)">{{item.name}}</view>
			</view>
			<text slot="right" class="iconfont icon-fatie_icon"></text>
		</uni-nav-bar>
		<!-- 滑块 -->
		<swiper :duration="150" :style="'height: '+scrollH+'px;'">
			<swiper-item>
				<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'">
					<view v-for="i in 50">{{i}}: https://blog.csdn.net/CUFEECR</view>
				</scroll-view>
			</swiper-item>
		</swiper>
	</view>
</template>

<script>
	import uniNavBar from '@/components/uni-ui/uni-nav-bar/uni-nav-bar.vue';
	export default {
		data() {
			return {
				tabBars: [{
						name: '关注'
					},
					{
						name: '话题'
					}
				],
				tabIndex: 0,
				scrollH: 500
			}
		},
		components: {
			uniNavBar
		},
		onLoad() {
			uni.getSystemInfo({
				success: function(res) {
					console.log(res);
					this.scrollH = res.windowHeight - res.statusBarHeight - 44;
				}
			})
		},
		methods: {
			// 打开发布页
			openAddInput() {
				uni.navigateTo({
					url: '../add-input/add-input'
				});
			},
			// 切换选项卡
			changeTab(index) {
				this.tabIndex = index;
			}
		}
	}
</script>

<style>

</style>

显示:

uniapp social app trend develop follow list calculate
uniapp social app trend develop follow list calculate

可以看到,计算出了正确高度,显示出了模拟的列表项。

2.导航列表联动实现

导航栏和列表的联动主要通过tabIndex进行关联,即tabIndex的变化同时影响导航栏和列表,实现同步变化。 news.vue如下:

代码语言:javascript
复制
<template>
	<view>
		<!-- 导航栏 -->
		<uni-nav-bar :border="false" :fixed="true" :statusBar="true" @clickRight="openAddInput">
			<view class="flex align-center justify-center font-weight-bold w-100">
				<view class="mx-1" v-for="(item, index) in tabBars" :key="index" :class="tabIndex === index ? 'font-lg text-main' : 'font-md text-light-muted'" @click="changeTab(index)">{{item.name}}</view>
			</view>
			<text slot="right" class="iconfont icon-fatie_icon"></text>
		</uni-nav-bar>
		<!-- 滑块 -->
		<swiper :current="tabIndex" :duration="150" :style="'height: '+scrollH+'px;'" @change="onChangeTab">
			<!-- 关注 -->
			<swiper-item>
				<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'">
					<block v-for="(item, index) in list" :key="index">
						<common-list :item="item" :index="index"></common-list>
						<divider></divider>
					</block>
				</scroll-view>
			</swiper-item>
			<!-- 话题 -->
			<swiper-item>
				<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'">
					话题
				</scroll-view>
			</swiper-item>
		</swiper>
	</view>
</template>

<script>
	// 测试数据
	const test_data = [{
			username: "Corley",
			userpic: "/static/img/userpic/12.jpg",
			newstime: "2021-01-24 上午11:30",
			isFollow: false,
			title: "uni-app入门教程",
			titlepic: "/static/img/datapic/42.jpg",
			support: {
				type: "support", // 顶
				support_count: 1,
				unsupport_count: 2
			},
			comment_count: 2,
			share_count: 2
		},
		{
			username: "Brittany",
			userpic: "/static/img/userpic/16.jpg",
			newstime: "2021-01-24 下午14:00",
			isFollow: false,
			title: "商业数据分析从入门到入职",
			support: {
				type: "unsupport", // 踩
				support_count: 2,
				unsupport_count: 3
			},
			comment_count: 5,
			share_count: 1
		},
		{
			username: "Jessica",
			userpic: "/static/img/userpic/7.jpg",
			newstime: "2021-01-24 下午14:44",
			isFollow: true,
			title: "Django+Vue开发生鲜电商平台",
			titlepic: "/static/img/datapic/11.jpg",
			support: {
				type: "", // 未操作
				support_count: 2,
				unsupport_count: 7
			},
			comment_count: 0,
			share_count: 2
		},
		{
			username: "Ashley",
			userpic: "/static/img/userpic/20.jpg",
			newstime: "2021-01-24 下午18:20",
			isFollow: true,
			title: "uni-app实战之社区交友APP",
			titlepic: "/static/img/datapic/30.jpg",
			support: {
				type: "support",
				support_count: 5,
				unsupport_count: 1
			},
			comment_count: 3,
			share_count: 0
		}
	];
	import uniNavBar from '@/components/uni-ui/uni-nav-bar/uni-nav-bar.vue';
	import commonList from '@/components/common/common-list.vue';
	export default {
		data() {
			return {
				tabBars: [{
						name: '关注'
					},
					{
						name: '话题'
					}
				],
				tabIndex: 0,
				scrollH: 500,
				// 关注列表
				list: []
			}
		},
		components: {
			uniNavBar,
			commonList
		},
		onLoad() {
			uni.getSystemInfo({
				success: function(res) {
					console.log(res);
					this.scrollH = res.windowHeight - res.statusBarHeight - 44;
				}
			}),
			// 加载测试数据
			this.list = test_data;
		},
		methods: {
			// 打开发布页
			openAddInput() {
				uni.navigateTo({
					url: '../add-input/add-input'
				});
			},
			// 切换选项卡
			changeTab(index) {
				this.tabIndex = index;
			},
			// 滑动
			onChangeTab(e) {
				this.tabIndex = e.detail.current;
			}
		}
	}
</script>

<style>

</style>

显示:

uniapp social app trend develop tab list connect
uniapp social app trend develop tab list connect

显然,实现了联动变化和列表显示。

3.顶踩操作和上拉加载功能

现实现顶踩、关注和上拉加载功能。 因为是在关注列表中,所有用户均为已关注用户,因此不需要实现关注功能。

先实现顶踩功能,如下:

代码语言:javascript
复制
<template>
	<view>
		<!-- 导航栏 -->
		<uni-nav-bar :border="false" :fixed="true" :statusBar="true" @clickRight="openAddInput">
			<view class="flex align-center justify-center font-weight-bold w-100">
				<view class="mx-1" v-for="(item, index) in tabBars" :key="index" :class="tabIndex === index ? 'font-lg text-main' : 'font-md text-light-muted'" @click="changeTab(index)">{{item.name}}</view>
			</view>
			<text slot="right" class="iconfont icon-fatie_icon"></text>
		</uni-nav-bar>
		<!-- 滑块 -->
		<swiper :current="tabIndex" :duration="150" :style="'height: '+scrollH+'px;'" @change="onChangeTab">
			<!-- 关注 -->
			<swiper-item>
				<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'">
					<block v-for="(item, index) in list" :key="index">
						<common-list :item="item" :index="index" @doSupport="doSupport"></common-list>
						<divider></divider>
					</block>
				</scroll-view>
			</swiper-item>
			<!-- 话题 -->
			<swiper-item>
				<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'">
					话题
				</scroll-view>
			</swiper-item>
		</swiper>
	</view>
</template>

<script>
	// 测试数据
	const test_data = [{
			username: "Corley",
			userpic: "/static/img/userpic/12.jpg",
			newstime: "2021-01-24 上午11:30",
			isFollow: true,
			title: "uni-app入门教程",
			titlepic: "/static/img/datapic/42.jpg",
			support: {
				type: "support", // 顶
				support_count: 1,
				unsupport_count: 2
			},
			comment_count: 2,
			share_count: 2
		},
		{
			username: "Brittany",
			userpic: "/static/img/userpic/16.jpg",
			newstime: "2021-01-24 下午14:00",
			isFollow: true,
			title: "商业数据分析从入门到入职",
			support: {
				type: "unsupport", // 踩
				support_count: 2,
				unsupport_count: 3
			},
			comment_count: 5,
			share_count: 1
		},
		{
			username: "Jessica",
			userpic: "/static/img/userpic/7.jpg",
			newstime: "2021-01-24 下午14:44",
			isFollow: true,
			title: "Django+Vue开发生鲜电商平台",
			titlepic: "/static/img/datapic/11.jpg",
			support: {
				type: "", // 未操作
				support_count: 2,
				unsupport_count: 7
			},
			comment_count: 0,
			share_count: 2
		},
		{
			username: "Ashley",
			userpic: "/static/img/userpic/20.jpg",
			newstime: "2021-01-24 下午18:20",
			isFollow: true,
			title: "uni-app实战之社区交友APP",
			titlepic: "/static/img/datapic/30.jpg",
			support: {
				type: "support",
				support_count: 5,
				unsupport_count: 1
			},
			comment_count: 3,
			share_count: 0
		}
	];
	import uniNavBar from '@/components/uni-ui/uni-nav-bar/uni-nav-bar.vue';
	import commonList from '@/components/common/common-list.vue';
	export default {
		data() {
			return {
				tabBars: [{
						name: '关注'
					},
					{
						name: '话题'
					}
				],
				tabIndex: 0,
				scrollH: 500,
				// 关注列表
				list: []
			}
		},
		components: {
			uniNavBar,
			commonList
		},
		onLoad() {
			uni.getSystemInfo({
				success: function(res) {
					console.log(res);
					this.scrollH = res.windowHeight - res.statusBarHeight - 44;
				}
			}),
			// 加载测试数据
			this.list = test_data;
		},
		methods: {
			// 打开发布页
			openAddInput() {
				uni.navigateTo({
					url: '../add-input/add-input'
				});
			},
			// 切换选项卡
			changeTab(index) {
				this.tabIndex = index;
			},
			// 滑动
			onChangeTab(e) {
				this.tabIndex = e.detail.current;
			},
			// 顶踩操作
			doSupport(e) {
				console.log(e);
				// 获取当前列表项
				let item = this.list[e.index];
				let msg = e.type === 'support' ? '顶' : '踩';
				// 之前未顶踩过
				if (item.support.type === '') {
					item.support[e.type + '_count']++;
				}
				// 之前已顶过并且现在的操作为踩,则顶-1、踩+1
				else if (item.support.type === 'support' && e.type === 'unsupport') {
					item.support.support_count--;
					item.support.unsupport_count++;
				}
				// 之前已踩过并且现在的操作为顶,则踩-1、顶+1
				else if (item.support.type === 'unsupport' && e.type === 'support') {
					item.support.unsupport_count--;
					item.support.support_count++;
				}
				item.support.type = e.type;
				uni.showToast({
					title: msg + '成功'
				})
			},
		}
	}
</script>

<style>

</style>

显示:

uniapp social app trend develop updown load updown
uniapp social app trend develop updown load updown

可以看到,也实现了顶踩功能。

再实现加载功能,如下:

代码语言:javascript
复制
<template>
	<view>
		<!-- 导航栏 -->
		<uni-nav-bar :border="false" :fixed="true" :statusBar="true" @clickRight="openAddInput">
			<view class="flex align-center justify-center font-weight-bold w-100">
				<view class="mx-1" v-for="(item, index) in tabBars" :key="index" :class="tabIndex === index ? 'font-lg text-main' : 'font-md text-light-muted'"
				 @click="changeTab(index)">{{item.name}}</view>
			</view>
			<text slot="right" class="iconfont icon-fatie_icon"></text>
		</uni-nav-bar>
		<!-- 滑块 -->
		<swiper :current="tabIndex" :duration="150" :style="'height: '+scrollH+'px;'" @change="onChangeTab">
			<!-- 关注 -->
			<swiper-item>
				<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'" @scrolltolower="loadmoreEvent">
					<block v-for="(item, index) in list" :key="index">
						<common-list :item="item" :index="index" @doSupport="doSupport"></common-list>
						<divider></divider>
					</block>
					<load-more :loadmore="loadmore"></load-more>
				</scroll-view>
			</swiper-item>
			<!-- 话题 -->
			<swiper-item>
				<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'">
					话题
				</scroll-view>
			</swiper-item>
		</swiper>
	</view>
</template>

<script>
	// 测试数据
	const test_data = [{
			username: "Corley",
			userpic: "/static/img/userpic/12.jpg",
			newstime: "2021-01-24 上午11:30",
			isFollow: true,
			title: "uni-app入门教程",
			titlepic: "/static/img/datapic/42.jpg",
			support: {
				type: "support", // 顶
				support_count: 1,
				unsupport_count: 2
			},
			comment_count: 2,
			share_count: 2
		},
		{
			username: "Brittany",
			userpic: "/static/img/userpic/16.jpg",
			newstime: "2021-01-24 下午14:00",
			isFollow: true,
			title: "商业数据分析从入门到入职",
			support: {
				type: "unsupport", // 踩
				support_count: 2,
				unsupport_count: 3
			},
			comment_count: 5,
			share_count: 1
		},
		{
			username: "Jessica",
			userpic: "/static/img/userpic/7.jpg",
			newstime: "2021-01-24 下午14:44",
			isFollow: true,
			title: "Django+Vue开发生鲜电商平台",
			titlepic: "/static/img/datapic/11.jpg",
			support: {
				type: "", // 未操作
				support_count: 2,
				unsupport_count: 7
			},
			comment_count: 0,
			share_count: 2
		},
		{
			username: "Ashley",
			userpic: "/static/img/userpic/20.jpg",
			newstime: "2021-01-24 下午18:20",
			isFollow: true,
			title: "uni-app实战之社区交友APP",
			titlepic: "/static/img/datapic/30.jpg",
			support: {
				type: "support",
				support_count: 5,
				unsupport_count: 1
			},
			comment_count: 3,
			share_count: 0
		}
	];
	import uniNavBar from '@/components/uni-ui/uni-nav-bar/uni-nav-bar.vue';
	import commonList from '@/components/common/common-list.vue';
	import loadMore from '../../components/common/load-more.vue';
	export default {
		data() {
			return {
				tabBars: [{
						name: '关注'
					},
					{
						name: '话题'
					}
				],
				tabIndex: 0,
				scrollH: 500,
				// 关注列表
				list: [],
				loadmore: "上拉加载更多"
			}
		},
		components: {
			uniNavBar,
			commonList,
			loadMore
		},
		onLoad() {
			uni.getSystemInfo({
					success: function(res) {
						console.log(res);
						this.scrollH = res.windowHeight - res.statusBarHeight - 44;
					}
				}),
				// 加载测试数据
				this.list = test_data;
		},
		methods: {
			// 打开发布页
			openAddInput() {
				uni.navigateTo({
					url: '../add-input/add-input'
				});
			},
			// 切换选项卡
			changeTab(index) {
				this.tabIndex = index;
			},
			// 滑动
			onChangeTab(e) {
				this.tabIndex = e.detail.current;
			},
			// 顶踩操作
			doSupport(e) {
				console.log(e);
				// 获取当前列表项
				let item = this.list[e.index];
				let msg = e.type === 'support' ? '顶' : '踩';
				// 之前未顶踩过
				if (item.support.type === '') {
					item.support[e.type + '_count']++;
				}
				// 之前已顶过并且现在的操作为踩,则顶-1、踩+1
				else if (item.support.type === 'support' && e.type === 'unsupport') {
					item.support.support_count--;
					item.support.unsupport_count++;
				}
				// 之前已踩过并且现在的操作为顶,则踩-1、顶+1
				else if (item.support.type === 'unsupport' && e.type === 'support') {
					item.support.unsupport_count--;
					item.support.support_count++;
				}
				item.support.type = e.type;
				uni.showToast({
					title: msg + '成功'
				})
			},
			// 上拉加载更多
			loadmoreEvent() {
				// 验证当前是否处于可加载状态
				if (this.loadmore !== '上拉加载更多') return;
				// 设置加载状态
				this.loadmore = '加载中...';
				// 模拟请求数据
				setTimeout(() => {
					// 加载数据
					this.list = [...this.list, ...this.list];
					// 设置加载状态
					this.loadmore = '上拉加载更多';
				}, 2000)
			}
		}
	}
</script>

<style>

</style>

显示:

uniapp social app trend develop updown load loadmore
uniapp social app trend develop updown load loadmore

可以看到,已经实现了动态加载更多。

三、话题专题和分类页开发

话题专题页开发包括热门分类组件、轮播图、搜索框话题列表组件等开发。

1.热门分类组件开发和封装

为了本文项目练手所需,需要在https://www.iconfont.cn/中选择进入搜索置顶等图标并更新icon.css

热门分类包括标题、跳转按钮和关键词等部分,如下:

代码语言:javascript
复制
<template>
	<view>
		<!-- 导航栏 -->
		<uni-nav-bar :border="false" :fixed="true" :statusBar="true" @clickRight="openAddInput">
			<view class="flex align-center justify-center font-weight-bold w-100">
				<view class="mx-1" v-for="(item, index) in tabBars" :key="index" :class="tabIndex === index ? 'font-lg text-main' : 'font-md text-light-muted'"
				 @click="changeTab(index)">{{item.name}}</view>
			</view>
			<text slot="right" class="iconfont icon-fatie_icon"></text>
		</uni-nav-bar>
		<!-- 滑块 -->
		<swiper :current="tabIndex" :duration="150" :style="'height: '+scrollH+'px;'" @change="onChangeTab">
			<!-- 关注 -->
			<swiper-item>
				<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'" @scrolltolower="loadmoreEvent">
					<block v-for="(item, index) in list" :key="index">
						<common-list :item="item" :index="index" @doSupport="doSupport"></common-list>
						<divider></divider>
					</block>
					<load-more :loadmore="loadmore"></load-more>
				</scroll-view>
			</swiper-item>
			<!-- 话题 -->
			<swiper-item>
				<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'">
					<!-- 热门分类 -->
					<view class="flex align-center justify-between px-2">
						<text class="font-md">热门分类</text>
						<view class="flex align-center font text-secondry animate__animated" hover-class="animate__jello">
							更多<text class="iconfont icon-bangzhujinru"></text>
						</view>
					</view>
					<view class="flex align-center px-2 py-3 border-bottom">
						<view class="border rounded bg-light mx-1 px-2 animate__animated" hover-class="animate__jello">
							关注
						</view>
						<view class="border rounded bg-light mx-1 px-2 animate__animated" hover-class="animate__jello">
							推荐
						</view>
						<view class="border rounded bg-light mx-1 px-2 animate__animated" hover-class="animate__jello">
							体育
						</view>
						<view class="border rounded bg-light mx-1 px-2 animate__animated" hover-class="animate__jello">
							热点
						</view>
						<view class="border rounded bg-light mx-1 px-2 animate__animated" hover-class="animate__jello">
							财经
						</view>
						<view class="border rounded bg-light mx-1 px-2 animate__animated" hover-class="animate__jello">
							娱乐
						</view>
					</view>
					<!-- 搜索框 -->
					<!-- 轮播图 -->
					<!-- 最近更新 -->
				</scroll-view>
			</swiper-item>
		</swiper>
	</view>
</template>

<script>
	// 测试数据
	const test_data = [{
			username: "Corley",
			userpic: "/static/img/userpic/12.jpg",
			newstime: "2021-01-24 上午11:30",
			isFollow: true,
			title: "uni-app入门教程",
			titlepic: "/static/img/datapic/42.jpg",
			support: {
				type: "support", // 顶
				support_count: 1,
				unsupport_count: 2
			},
			comment_count: 2,
			share_count: 2
		},
		{
			username: "Brittany",
			userpic: "/static/img/userpic/16.jpg",
			newstime: "2021-01-24 下午14:00",
			isFollow: true,
			title: "商业数据分析从入门到入职",
			support: {
				type: "unsupport", // 踩
				support_count: 2,
				unsupport_count: 3
			},
			comment_count: 5,
			share_count: 1
		},
		{
			username: "Jessica",
			userpic: "/static/img/userpic/7.jpg",
			newstime: "2021-01-24 下午14:44",
			isFollow: true,
			title: "Django+Vue开发生鲜电商平台",
			titlepic: "/static/img/datapic/11.jpg",
			support: {
				type: "", // 未操作
				support_count: 2,
				unsupport_count: 7
			},
			comment_count: 0,
			share_count: 2
		},
		{
			username: "Ashley",
			userpic: "/static/img/userpic/20.jpg",
			newstime: "2021-01-24 下午18:20",
			isFollow: true,
			title: "uni-app实战之社区交友APP",
			titlepic: "/static/img/datapic/30.jpg",
			support: {
				type: "support",
				support_count: 5,
				unsupport_count: 1
			},
			comment_count: 3,
			share_count: 0
		}
	];
	import uniNavBar from '@/components/uni-ui/uni-nav-bar/uni-nav-bar.vue';
	import commonList from '@/components/common/common-list.vue';
	import loadMore from '../../components/common/load-more.vue';
	export default {
		data() {
			return {
				tabBars: [{
						name: '关注'
					},
					{
						name: '话题'
					}
				],
				tabIndex: 0,
				scrollH: 500,
				// 关注列表
				list: [],
				loadmore: "上拉加载更多"
			}
		},
		components: {
			uniNavBar,
			commonList,
			loadMore
		},
		onLoad() {
			uni.getSystemInfo({
					success: function(res) {
						console.log(res);
						this.scrollH = res.windowHeight - res.statusBarHeight - 44;
					}
				}),
				// 加载测试数据
				this.list = test_data;
		},
		methods: {
			// 打开发布页
			openAddInput() {
				uni.navigateTo({
					url: '../add-input/add-input'
				});
			},
			// 切换选项卡
			changeTab(index) {
				this.tabIndex = index;
			},
			// 滑动
			onChangeTab(e) {
				this.tabIndex = e.detail.current;
			},
			// 顶踩操作
			doSupport(e) {
				console.log(e);
				// 获取当前列表项
				let item = this.list[e.index];
				let msg = e.type === 'support' ? '顶' : '踩';
				// 之前未顶踩过
				if (item.support.type === '') {
					item.support[e.type + '_count']++;
				}
				// 之前已顶过并且现在的操作为踩,则顶-1、踩+1
				else if (item.support.type === 'support' && e.type === 'unsupport') {
					item.support.support_count--;
					item.support.unsupport_count++;
				}
				// 之前已踩过并且现在的操作为顶,则踩-1、顶+1
				else if (item.support.type === 'unsupport' && e.type === 'support') {
					item.support.unsupport_count--;
					item.support.support_count++;
				}
				item.support.type = e.type;
				uni.showToast({
					title: msg + '成功'
				})
			},
			// 上拉加载更多
			loadmoreEvent() {
				// 验证当前是否处于可加载状态
				if (this.loadmore !== '上拉加载更多') return;
				// 设置加载状态
				this.loadmore = '加载中...';
				// 模拟请求数据
				setTimeout(() => {
					// 加载数据
					this.list = [...this.list, ...this.list];
					// 设置加载状态
					this.loadmore = '上拉加载更多';
				}, 2000)
			}
		}
	}
</script>

<style>

</style>

显示:

uniapp social app trend develop topic project hot cate view
uniapp social app trend develop topic project hot cate view

显然,已经显示了热点分类,并且添加了点击的动画效果。

再实现将热门分类组件进行封装,减少代码、更易于维护。 在components目录下新建news子目录,下新建hot-cate.vue如下:

代码语言:javascript
复制
<template>
	<view>
		<view class="flex align-center justify-between px-2">
			<text class="font-md">热门分类</text>
			<view class="flex align-center font text-secondry animate__animated" hover-class="animate__jello" @click="openMore()">
				更多<text class="iconfont icon-bangzhujinru"></text>
			</view>
		</view>
		<view class="flex align-center px-2 py-3 border-bottom">
			<view class="border rounded bg-light mx-1 px-2 animate__animated" hover-class="animate__jello" v-for="(item, index) in hotCate" :key="index" @click="openDetail(item)">
				{{item.name}}
			</view>
		</view>
	</view>
</template>

<script>
	export default {
		props: ['hotCate'],
		methods: {
			openMore() {
				console.log('opening more');
			},
			openDetail(item) {
				console.log('opening detail');
			}
		}
	}
</script>

<style>
</style>

news.vue修改如下:

代码语言:javascript
复制
<template>
	<view>
		<!-- 导航栏 -->
		<uni-nav-bar :border="false" :fixed="true" :statusBar="true" @clickRight="openAddInput">
			<view class="flex align-center justify-center font-weight-bold w-100">
				<view class="mx-1" v-for="(item, index) in tabBars" :key="index" :class="tabIndex === index ? 'font-lg text-main' : 'font-md text-light-muted'"
				 @click="changeTab(index)">{{item.name}}</view>
			</view>
			<text slot="right" class="iconfont icon-fatie_icon"></text>
		</uni-nav-bar>
		<!-- 滑块 -->
		<swiper :current="tabIndex" :duration="150" :style="'height: '+scrollH+'px;'" @change="onChangeTab">
			<!-- 关注 -->
			<swiper-item>
				<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'" @scrolltolower="loadmoreEvent">
					<block v-for="(item, index) in list" :key="index">
						<common-list :item="item" :index="index" @doSupport="doSupport"></common-list>
						<divider></divider>
					</block>
					<load-more :loadmore="loadmore"></load-more>
				</scroll-view>
			</swiper-item>
			<!-- 话题 -->
			<swiper-item>
				<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'">
					<!-- 热门分类 -->
					<hot-cate :hotCate="hotCate"></hot-cate>
					<!-- 搜索框 -->
					<!-- 轮播图 -->
					<!-- 最近更新 -->
				</scroll-view>
			</swiper-item>
		</swiper>
	</view>
</template>

<script>
	// 测试数据
	const test_data = [{
			username: "Corley",
			userpic: "/static/img/userpic/12.jpg",
			newstime: "2021-01-24 上午11:30",
			isFollow: true,
			title: "uni-app入门教程",
			titlepic: "/static/img/datapic/42.jpg",
			support: {
				type: "support", // 顶
				support_count: 1,
				unsupport_count: 2
			},
			comment_count: 2,
			share_count: 2
		},
		{
			username: "Brittany",
			userpic: "/static/img/userpic/16.jpg",
			newstime: "2021-01-24 下午14:00",
			isFollow: true,
			title: "商业数据分析从入门到入职",
			support: {
				type: "unsupport", // 踩
				support_count: 2,
				unsupport_count: 3
			},
			comment_count: 5,
			share_count: 1
		},
		{
			username: "Jessica",
			userpic: "/static/img/userpic/7.jpg",
			newstime: "2021-01-24 下午14:44",
			isFollow: true,
			title: "Django+Vue开发生鲜电商平台",
			titlepic: "/static/img/datapic/11.jpg",
			support: {
				type: "", // 未操作
				support_count: 2,
				unsupport_count: 7
			},
			comment_count: 0,
			share_count: 2
		},
		{
			username: "Ashley",
			userpic: "/static/img/userpic/20.jpg",
			newstime: "2021-01-24 下午18:20",
			isFollow: true,
			title: "uni-app实战之社区交友APP",
			titlepic: "/static/img/datapic/30.jpg",
			support: {
				type: "support",
				support_count: 5,
				unsupport_count: 1
			},
			comment_count: 3,
			share_count: 0
		}
	];
	import uniNavBar from '@/components/uni-ui/uni-nav-bar/uni-nav-bar.vue';
	import commonList from '@/components/common/common-list.vue';
	import loadMore from '../../components/common/load-more.vue';
	import hotCate from '@/components/news/hot-cate.vue';
	export default {
		data() {
			return {
				tabBars: [{
						name: '关注'
					},
					{
						name: '话题'
					}
				],
				tabIndex: 0,
				scrollH: 500,
				// 关注列表
				list: [],
				loadmore: "上拉加载更多",
				hotCate: [
					{
						name: '关注'
						
					},
					{
						name: '推荐'
						
					},
					{
						name: '体育'
						
					},
					{
						name: '热点'
						
					},
					{
						name: '财经'
						
					},
					{
						name: '娱乐'
						
					}
				]
			}
		},
		components: {
			uniNavBar,
			commonList,
			loadMore,
			hotCate
		},
		onLoad() {
			uni.getSystemInfo({
					success: function(res) {
						console.log(res);
						this.scrollH = res.windowHeight - res.statusBarHeight - 44;
					}
				}),
				// 加载测试数据
				this.list = test_data;
		},
		methods: {
			// 打开发布页
			openAddInput() {
				uni.navigateTo({
					url: '../add-input/add-input'
				});
			},
			// 切换选项卡
			changeTab(index) {
				this.tabIndex = index;
			},
			// 滑动
			onChangeTab(e) {
				this.tabIndex = e.detail.current;
			},
			// 顶踩操作
			doSupport(e) {
				console.log(e);
				// 获取当前列表项
				let item = this.list[e.index];
				let msg = e.type === 'support' ? '顶' : '踩';
				// 之前未顶踩过
				if (item.support.type === '') {
					item.support[e.type + '_count']++;
				}
				// 之前已顶过并且现在的操作为踩,则顶-1、踩+1
				else if (item.support.type === 'support' && e.type === 'unsupport') {
					item.support.support_count--;
					item.support.unsupport_count++;
				}
				// 之前已踩过并且现在的操作为顶,则踩-1、顶+1
				else if (item.support.type === 'unsupport' && e.type === 'support') {
					item.support.unsupport_count--;
					item.support.support_count++;
				}
				item.support.type = e.type;
				uni.showToast({
					title: msg + '成功'
				})
			},
			// 上拉加载更多
			loadmoreEvent() {
				// 验证当前是否处于可加载状态
				if (this.loadmore !== '上拉加载更多') return;
				// 设置加载状态
				this.loadmore = '加载中...';
				// 模拟请求数据
				setTimeout(() => {
					// 加载数据
					this.list = [...this.list, ...this.list];
					// 设置加载状态
					this.loadmore = '上拉加载更多';
				}, 2000)
			}
		}
	}
</script>

<style>

</style>

效果与之前相同。

2.搜索框和轮播图开发

先实现搜索框,如下:

代码语言:javascript
复制
<!-- 搜索框 -->
<view class="p-2">
    <view class="bg-light rounded flex align-center justify-center py-2 text-secondry">
        <text class="iconfont icon-sousuo mr-2"></text>搜索话题
    </view>
</view>

显示:

uniapp social app trend develop topic project search
uniapp social app trend develop topic project search

显然,实现了搜索框。

再实现轮播图,使用swiper组件实现,如下:

代码语言:javascript
复制
<!-- 轮播图 -->
<swiper class="px-2 pb-2" :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000">
    <swiper-item>
        <image src="../../static/img/banner/banner1.jpg" style="height: 300rpx;" class="w-100 rounded" mode=""></image>
    </swiper-item>
    <swiper-item>
        <image src="../../static/img/banner/banner2.jpeg" style="height: 300rpx;" class="w-100 rounded" mode=""></image>
    </swiper-item>
    <swiper-item>
        <image src="../../static/img/banner/banner3.jpg" style="height: 300rpx;" class="w-100 rounded" mode=""></image>
    </swiper-item>
</swiper>

显示:

uniapp social app trend develop topic project banner
uniapp social app trend develop topic project banner

显然,已经实现了轮播图效果。

如需轮播图图片素材等文件,可以直接点击加QQ群

Python极客部落
Python极客部落

963624318 ,在群文件夹uni-app实战之社区交友APP中下载即可。

3.话题列表组件开发和封装

最近更新下的内容即为话题列表,开发如下:

代码语言:javascript
复制
<!-- 最近更新 -->
<view class="p-2 font-md">最近更新</view>
<!-- 话题列表 -->
<view class="flex align-center p-2">
    <image class="rounded mr-2" src="/static/img/topicpic/14.jpeg" style="width: 150rpx; height: 150rpx;"></image>
    <view class="flex flex-column flex-1">
        <text class="font-md text-dark">#话题名称#</text>
        <text class="font text-secondry">话题描述</text>
        <view class="flex align-center font text-secondry">
            <text class="mr-2">动态:10</text>
            <text>今日:1</text>
        </view>
    </view>
</view>

显示:

uniapp social app trend develop topic project topiclist view
uniapp social app trend develop topic project topiclist view

可以看到,显示出了话题列表。

现进一步将话题列表封装为组件,先构建数据,如下:

代码语言:javascript
复制
<template>
	<view>
		<!-- 导航栏 -->
		<uni-nav-bar :border="false" :fixed="true" :statusBar="true" @clickRight="openAddInput">
			<view class="flex align-center justify-center font-weight-bold w-100">
				<view class="mx-1" v-for="(item, index) in tabBars" :key="index" :class="tabIndex === index ? 'font-lg text-main' : 'font-md text-light-muted'"
				 @click="changeTab(index)">{{item.name}}</view>
			</view>
			<text slot="right" class="iconfont icon-fatie_icon"></text>
		</uni-nav-bar>
		<!-- 滑块 -->
		<swiper :current="tabIndex" :duration="150" :style="'height: '+scrollH+'px;'" @change="onChangeTab">
			<!-- 关注 -->
			<swiper-item>
				<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'" @scrolltolower="loadmoreEvent">
					<block v-for="(item, index) in list" :key="index">
						<common-list :item="item" :index="index" @doSupport="doSupport"></common-list>
						<divider></divider>
					</block>
					<load-more :loadmore="loadmore"></load-more>
				</scroll-view>
			</swiper-item>
			<!-- 话题 -->
			<swiper-item>
				<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'">
					<!-- 热门分类 -->
					<hot-cate :hotCate="hotCate"></hot-cate>
					<!-- 搜索框 -->
					<view class="p-2">
						<view class="bg-light rounded flex align-center justify-center py-2 text-secondry">
							<text class="iconfont icon-sousuo mr-2"></text>搜索话题
						</view>
					</view>
					<!-- 轮播图 -->
					<swiper class="px-2 pb-2" :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000">
						<swiper-item>
							<image src="/static/img/banner/banner1.jpg" style="height: 300rpx;" class="w-100 rounded" mode=""></image>
						</swiper-item>
						<swiper-item>
							<image src="/static/img/banner/banner2.jpeg" style="height: 300rpx;" class="w-100 rounded" mode=""></image>
						</swiper-item>
						<swiper-item>
							<image src="/static/img/banner/banner3.jpg" style="height: 300rpx;" class="w-100 rounded" mode=""></image>
						</swiper-item>
					</swiper>
					<!-- 最近更新 -->
					<view class="p-2 font-md">最近更新</view>
					<!-- 话题列表 -->
					<block v-for="(item, index) in topicList" :key="index">
						<view class="flex align-center p-2">
							<image class="rounded mr-2" :src="item.cover" style="width: 150rpx; height: 150rpx;"></image>
							<view class="flex flex-column flex-1">
								<text class="font-md text-dark">#{{item.title}}#</text>
								<text class="font text-secondry">{{item.desc}}</text>
								<view class="flex align-center font text-secondry">
									<text class="mr-2">动态:{{item.news_count}}</text>
									<text>今日:{{item.today_count}}</text>
								</view>
							</view>
						</view>
					</block>
				</scroll-view>
			</swiper-item>
		</swiper>
	</view>
</template>

<script>
	// 测试数据
	const test_data = [{
			username: "Corley",
			userpic: "/static/img/userpic/12.jpg",
			newstime: "2021-01-24 上午11:30",
			isFollow: true,
			title: "uni-app入门教程",
			titlepic: "/static/img/datapic/42.jpg",
			support: {
				type: "support", // 顶
				support_count: 1,
				unsupport_count: 2
			},
			comment_count: 2,
			share_count: 2
		},
		{
			username: "Brittany",
			userpic: "/static/img/userpic/16.jpg",
			newstime: "2021-01-24 下午14:00",
			isFollow: true,
			title: "商业数据分析从入门到入职",
			support: {
				type: "unsupport", // 踩
				support_count: 2,
				unsupport_count: 3
			},
			comment_count: 5,
			share_count: 1
		},
		{
			username: "Jessica",
			userpic: "/static/img/userpic/7.jpg",
			newstime: "2021-01-24 下午14:44",
			isFollow: true,
			title: "Django+Vue开发生鲜电商平台",
			titlepic: "/static/img/datapic/11.jpg",
			support: {
				type: "", // 未操作
				support_count: 2,
				unsupport_count: 7
			},
			comment_count: 0,
			share_count: 2
		},
		{
			username: "Ashley",
			userpic: "/static/img/userpic/20.jpg",
			newstime: "2021-01-24 下午18:20",
			isFollow: true,
			title: "uni-app实战之社区交友APP",
			titlepic: "/static/img/datapic/30.jpg",
			support: {
				type: "support",
				support_count: 5,
				unsupport_count: 1
			},
			comment_count: 3,
			share_count: 0
		}
	];
	import uniNavBar from '@/components/uni-ui/uni-nav-bar/uni-nav-bar.vue';
	import commonList from '@/components/common/common-list.vue';
	import loadMore from '../../components/common/load-more.vue';
	import hotCate from '@/components/news/hot-cate.vue';
	export default {
		data() {
			return {
				tabBars: [{
						name: '关注'
					},
					{
						name: '话题'
					}
				],
				tabIndex: 0,
				scrollH: 500,
				// 关注列表
				list: [],
				loadmore: "上拉加载更多",
				hotCate: [
					{
						name: '关注'
						
					},
					{
						name: '推荐'
						
					},
					{
						name: '体育'
						
					},
					{
						name: '热点'
						
					},
					{
						name: '财经'
						
					},
					{
						name: '娱乐'
						
					}
				],
				topicList: [
					{
						cover: '/static/img/topicpic/14.jpeg',
						title: '毛伟明当选湖南省人民政府省长',
						desc: '毛伟明当选湖南省人民政府省长',
						news_count: 10,
						today_count: 1
					},
					{
						cover: '/static/img/topicpic/2.jpeg',
						title: '个别自美赴华乘客篡改阳性记录',
						desc: '中国驻旧金山总领馆:个别自美赴华乘客篡改、隐瞒阳性记录',
						news_count: 7,
						today_count: 2
					},
					{
						cover: '/static/img/topicpic/5.jpeg',
						title: '中纪委披露安徽太和县骗保事件',
						desc: '安徽省太和县发生骗保事件,中纪委网站披露骗保百般花样',
						news_count: 21,
						today_count: 3
					},
					{
						cover: '/static/img/topicpic/8.jpeg',
						title: '篮网正式签约佩莱',
						desc: '对阵篮网4次封盖,13分钟7个篮板,怒帽小乔丹的佩莱加盟篮网',
						news_count: 11,
						today_count: 2
					},
					{
						cover: '/static/img/topicpic/10.jpeg',
						title: '被孟佳团队抄袭图片的模特发文',
						desc: '孟佳团队背锅承认抄袭,外国模特发文回应:没有在第一时间联系',
						news_count: 7,
						today_count: 0
					},
					{
						cover: '/static/img/topicpic/16.jpeg',
						title: 'FF将通过并购在纳斯达克上市',
						desc: 'FF将通过与PSAC合并在纳斯达克上市;传蚂蚁集团将重组为央行监管的...',
						news_count: 15,
						today_count: 4
					},
					{
						cover: '/static/img/topicpic/11.jpeg',
						title: '"现实版樊胜美"弟弟疑遭人肉网暴',
						desc: '现实版樊胜美弟弟疑遭人肉网暴 挂出其母弟弟住址电话',
						news_count: 6,
						today_count: 0
					}
				]
			}
		},
		components: {
			uniNavBar,
			commonList,
			loadMore,
			hotCate
		},
		onLoad() {
			uni.getSystemInfo({
					success: function(res) {
						console.log(res);
						this.scrollH = res.windowHeight - res.statusBarHeight - 44;
					}
				}),
				// 加载测试数据
				this.list = test_data;
		},
		methods: {
			// 打开发布页
			openAddInput() {
				uni.navigateTo({
					url: '../add-input/add-input'
				});
			},
			// 切换选项卡
			changeTab(index) {
				this.tabIndex = index;
			},
			// 滑动
			onChangeTab(e) {
				this.tabIndex = e.detail.current;
			},
			// 顶踩操作
			doSupport(e) {
				console.log(e);
				// 获取当前列表项
				let item = this.list[e.index];
				let msg = e.type === 'support' ? '顶' : '踩';
				// 之前未顶踩过
				if (item.support.type === '') {
					item.support[e.type + '_count']++;
				}
				// 之前已顶过并且现在的操作为踩,则顶-1、踩+1
				else if (item.support.type === 'support' && e.type === 'unsupport') {
					item.support.support_count--;
					item.support.unsupport_count++;
				}
				// 之前已踩过并且现在的操作为顶,则踩-1、顶+1
				else if (item.support.type === 'unsupport' && e.type === 'support') {
					item.support.unsupport_count--;
					item.support.support_count++;
				}
				item.support.type = e.type;
				uni.showToast({
					title: msg + '成功'
				})
			},
			// 上拉加载更多
			loadmoreEvent() {
				// 验证当前是否处于可加载状态
				if (this.loadmore !== '上拉加载更多') return;
				// 设置加载状态
				this.loadmore = '加载中...';
				// 模拟请求数据
				setTimeout(() => {
					// 加载数据
					this.list = [...this.list, ...this.list];
					// 设置加载状态
					this.loadmore = '上拉加载更多';
				}, 2000)
			}
		}
	}
</script>

<style>

</style>

显示:

uniapp social app trend develop topic project topiclist data
uniapp social app trend develop topic project topiclist data

此时,已经有话题列表。

再封装组件,components/news下新建topic-list.vue如下:

代码语言:javascript
复制
<template>
	<view class="flex align-center p-2">
		<image class="rounded mr-2" :src="item.cover" style="width: 150rpx; height: 150rpx;"></image>
		<view class="flex flex-column flex-1">
			<text class="font-md text-dark">#{{item.title}}#</text>
			<text class="font text-secondry">{{item.desc}}</text>
			<view class="flex align-center font text-secondry">
				<text class="mr-2">动态:{{item.news_count}}</text>
				<text>今日:{{item.today_count}}</text>
			</view>
		</view>
	</view>
</template>

<script>
	export default {
		props: {
			item: Object,
			index: Number
		},
	}
</script>

<style>
</style>

news.vue如下:

代码语言:javascript
复制
<template>
	<view>
		<!-- 导航栏 -->
		<uni-nav-bar :border="false" :fixed="true" :statusBar="true" @clickRight="openAddInput">
			<view class="flex align-center justify-center font-weight-bold w-100">
				<view class="mx-1" v-for="(item, index) in tabBars" :key="index" :class="tabIndex === index ? 'font-lg text-main' : 'font-md text-light-muted'"
				 @click="changeTab(index)">{{item.name}}</view>
			</view>
			<text slot="right" class="iconfont icon-fatie_icon"></text>
		</uni-nav-bar>
		<!-- 滑块 -->
		<swiper :current="tabIndex" :duration="150" :style="'height: '+scrollH+'px;'" @change="onChangeTab">
			<!-- 关注 -->
			<swiper-item>
				<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'" @scrolltolower="loadmoreEvent">
					<block v-for="(item, index) in list" :key="index">
						<common-list :item="item" :index="index" @doSupport="doSupport"></common-list>
						<divider></divider>
					</block>
					<load-more :loadmore="loadmore"></load-more>
				</scroll-view>
			</swiper-item>
			<!-- 话题 -->
			<swiper-item>
				<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'">
					<!-- 热门分类 -->
					<hot-cate :hotCate="hotCate"></hot-cate>
					<!-- 搜索框 -->
					<view class="p-2">
						<view class="bg-light rounded flex align-center justify-center py-2 text-secondry">
							<text class="iconfont icon-sousuo mr-2"></text>搜索话题
						</view>
					</view>
					<!-- 轮播图 -->
					<swiper class="px-2 pb-2" :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000">
						<swiper-item>
							<image src="/static/img/banner/banner1.jpg" style="height: 300rpx;" class="w-100 rounded" mode=""></image>
						</swiper-item>
						<swiper-item>
							<image src="/static/img/banner/banner2.jpeg" style="height: 300rpx;" class="w-100 rounded" mode=""></image>
						</swiper-item>
						<swiper-item>
							<image src="/static/img/banner/banner3.jpg" style="height: 300rpx;" class="w-100 rounded" mode=""></image>
						</swiper-item>
					</swiper>
					<!-- 最近更新 -->
					<view class="p-2 font-md">最近更新</view>
					<!-- 话题列表 -->
					<block v-for="(item, index) in topicList" :key="index">
						<topic-list :item="item" :index="index"></topic-list>
					</block>
				</scroll-view>
			</swiper-item>
		</swiper>
	</view>
</template>

<script>
	// 测试数据
	const test_data = [{
			username: "Corley",
			userpic: "/static/img/userpic/12.jpg",
			newstime: "2021-01-24 上午11:30",
			isFollow: true,
			title: "uni-app入门教程",
			titlepic: "/static/img/datapic/42.jpg",
			support: {
				type: "support", // 顶
				support_count: 1,
				unsupport_count: 2
			},
			comment_count: 2,
			share_count: 2
		},
		{
			username: "Brittany",
			userpic: "/static/img/userpic/16.jpg",
			newstime: "2021-01-24 下午14:00",
			isFollow: true,
			title: "商业数据分析从入门到入职",
			support: {
				type: "unsupport", // 踩
				support_count: 2,
				unsupport_count: 3
			},
			comment_count: 5,
			share_count: 1
		},
		{
			username: "Jessica",
			userpic: "/static/img/userpic/7.jpg",
			newstime: "2021-01-24 下午14:44",
			isFollow: true,
			title: "Django+Vue开发生鲜电商平台",
			titlepic: "/static/img/datapic/11.jpg",
			support: {
				type: "", // 未操作
				support_count: 2,
				unsupport_count: 7
			},
			comment_count: 0,
			share_count: 2
		},
		{
			username: "Ashley",
			userpic: "/static/img/userpic/20.jpg",
			newstime: "2021-01-24 下午18:20",
			isFollow: true,
			title: "uni-app实战之社区交友APP",
			titlepic: "/static/img/datapic/30.jpg",
			support: {
				type: "support",
				support_count: 5,
				unsupport_count: 1
			},
			comment_count: 3,
			share_count: 0
		}
	];
	import uniNavBar from '@/components/uni-ui/uni-nav-bar/uni-nav-bar.vue';
	import commonList from '@/components/common/common-list.vue';
	import loadMore from '../../components/common/load-more.vue';
	import hotCate from '@/components/news/hot-cate.vue';
	import topicList from '@/components/news/topic-list.vue';
	export default {
		data() {
			return {
				tabBars: [{
						name: '关注'
					},
					{
						name: '话题'
					}
				],
				tabIndex: 0,
				scrollH: 500,
				// 关注列表
				list: [],
				loadmore: "上拉加载更多",
				hotCate: [{
						name: '关注'

					},
					{
						name: '推荐'

					},
					{
						name: '体育'

					},
					{
						name: '热点'

					},
					{
						name: '财经'

					},
					{
						name: '娱乐'

					}
				],
				topicList: [{
						cover: '/static/img/topicpic/14.jpeg',
						title: '毛伟明当选湖南省人民政府省长',
						desc: '毛伟明当选湖南省人民政府省长',
						news_count: 10,
						today_count: 1
					},
					{
						cover: '/static/img/topicpic/2.jpeg',
						title: '个别自美赴华乘客篡改阳性记录',
						desc: '中国驻旧金山总领馆:个别自美赴华乘客篡改、隐瞒阳性记录',
						news_count: 7,
						today_count: 2
					},
					{
						cover: '/static/img/topicpic/5.jpeg',
						title: '中纪委披露安徽太和县骗保事件',
						desc: '安徽省太和县发生骗保事件,中纪委网站披露骗保百般花样',
						news_count: 21,
						today_count: 3
					},
					{
						cover: '/static/img/topicpic/8.jpeg',
						title: '篮网正式签约佩莱',
						desc: '对阵篮网4次封盖,13分钟7个篮板,怒帽小乔丹的佩莱加盟篮网',
						news_count: 11,
						today_count: 2
					},
					{
						cover: '/static/img/topicpic/10.jpeg',
						title: '被孟佳团队抄袭图片的模特发文',
						desc: '孟佳团队背锅承认抄袭,外国模特发文回应:没有在第一时间联系',
						news_count: 7,
						today_count: 0
					},
					{
						cover: '/static/img/topicpic/16.jpeg',
						title: 'FF将通过并购在纳斯达克上市',
						desc: 'FF将通过与PSAC合并在纳斯达克上市;传蚂蚁集团将重组为央行监管的...',
						news_count: 15,
						today_count: 4
					},
					{
						cover: '/static/img/topicpic/11.jpeg',
						title: '"现实版樊胜美"弟弟疑遭人肉网暴',
						desc: '现实版樊胜美弟弟疑遭人肉网暴 挂出其母弟弟住址电话',
						news_count: 6,
						today_count: 0
					}
				]
			}
		},
		components: {
			uniNavBar,
			commonList,
			loadMore,
			hotCate,
			topicList
		},
		onLoad() {
			uni.getSystemInfo({
					success: function(res) {
						console.log(res);
						this.scrollH = res.windowHeight - res.statusBarHeight - 44;
					}
				}),
				// 加载测试数据
				this.list = test_data;
		},
		methods: {
			// 打开发布页
			openAddInput() {
				uni.navigateTo({
					url: '../add-input/add-input'
				});
			},
			// 切换选项卡
			changeTab(index) {
				this.tabIndex = index;
			},
			// 滑动
			onChangeTab(e) {
				this.tabIndex = e.detail.current;
			},
			// 顶踩操作
			doSupport(e) {
				console.log(e);
				// 获取当前列表项
				let item = this.list[e.index];
				let msg = e.type === 'support' ? '顶' : '踩';
				// 之前未顶踩过
				if (item.support.type === '') {
					item.support[e.type + '_count']++;
				}
				// 之前已顶过并且现在的操作为踩,则顶-1、踩+1
				else if (item.support.type === 'support' && e.type === 'unsupport') {
					item.support.support_count--;
					item.support.unsupport_count++;
				}
				// 之前已踩过并且现在的操作为顶,则踩-1、顶+1
				else if (item.support.type === 'unsupport' && e.type === 'support') {
					item.support.unsupport_count--;
					item.support.support_count++;
				}
				item.support.type = e.type;
				uni.showToast({
					title: msg + '成功'
				})
			},
			// 上拉加载更多
			loadmoreEvent() {
				// 验证当前是否处于可加载状态
				if (this.loadmore !== '上拉加载更多') return;
				// 设置加载状态
				this.loadmore = '加载中...';
				// 模拟请求数据
				setTimeout(() => {
					// 加载数据
					this.list = [...this.list, ...this.list];
					// 设置加载状态
					this.loadmore = '上拉加载更多';
				}, 2000)
			}
		}
	}
</script>

<style>

</style>

效果与之前相同。

4.话题分类页开发

话题分类页和首页类似,可以复用

需要先新建话题分类页面topic-nav(包括同名目录,本项目创建页面时默认创建同名目录)。

pages.json配置如下:

代码语言:javascript
复制
{
    "path" : "pages/topic-nav/topic-nav",
    "style" :                                                                                    
    {
        "navigationBarTitleText": "话题分类",
        "enablePullDownRefresh": false
    }
    
}

该页面需要从热点分类组件进入,hot-cate.vue如下:

代码语言:javascript
复制
openMore() {
    console.log('opening more');
    uni.navigateTo({
        url: '../../pages/topic-nav/topic-nav'
    });
},

topic-nav.vue页面如下:

代码语言:javascript
复制
<template>
	<view>
		<!-- 顶部选项卡 -->
		<scroll-view scroll-x="true" class="scroll-row" :scroll-into-view="scrollInto" :scroll-with-animation="true" style="height: 100rpx;">
			<view v-for="(item, index) in tabBars" :key="index" class="scroll-row-item px-3 py-2 font-md" :id="'tab'+index"
			 :class="tabIndex === index ? 'text-main font-lg font-weight-bold' : ''" @click="changeTab(index)">{{item.name}}</view>
		</scroll-view>
		<!-- 滑块 -->
		<swiper :duration="150" :current="tabIndex" @change="onChangeTab" :style="'height: '+scrollH+'px;'">
			<swiper-item v-for="(item, index) in topicArray" :key="index">
				<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'" @scrolltolower="loadMore(index)">
					<!-- 有数据 -->
					<template v-if="item.list.length > 0">
						<!-- 列表 -->
						<block v-for="(item2, index2) in item.list" :key="index2">
							<!-- 列表组件 -->
							<topic-list :item="item2" :index="index2"></topic-list>
						</block>
						<!-- 上拉加载 -->
						<load-more :loadmore="item.loadmore"></load-more>
					</template>
					<!-- 无数据 -->
					<template v-else>
						<no-thing></no-thing>
					</template>
				</scroll-view>
			</swiper-item>
		</swiper>

	</view>
</template>

<script>
	// 测试数据
	const test_data = [{
			cover: '/static/img/topicpic/14.jpeg',
			title: '毛伟明当选湖南省人民政府省长',
			desc: '毛伟明当选湖南省人民政府省长',
			news_count: 10,
			today_count: 1
		},
		{
			cover: '/static/img/topicpic/2.jpeg',
			title: '个别自美赴华乘客篡改阳性记录',
			desc: '中国驻旧金山总领馆:个别自美赴华乘客篡改、隐瞒阳性记录',
			news_count: 7,
			today_count: 2
		},
		{
			cover: '/static/img/topicpic/5.jpeg',
			title: '中纪委披露安徽太和县骗保事件',
			desc: '安徽省太和县发生骗保事件,中纪委网站披露骗保百般花样',
			news_count: 21,
			today_count: 3
		},
		{
			cover: '/static/img/topicpic/8.jpeg',
			title: '篮网正式签约佩莱',
			desc: '对阵篮网4次封盖,13分钟7个篮板,怒帽小乔丹的佩莱加盟篮网',
			news_count: 11,
			today_count: 2
		},
		{
			cover: '/static/img/topicpic/10.jpeg',
			title: '被孟佳团队抄袭图片的模特发文',
			desc: '孟佳团队背锅承认抄袭,外国模特发文回应:没有在第一时间联系',
			news_count: 7,
			today_count: 0
		},
		{
			cover: '/static/img/topicpic/16.jpeg',
			title: 'FF将通过并购在纳斯达克上市',
			desc: 'FF将通过与PSAC合并在纳斯达克上市;传蚂蚁集团将重组为央行监管的...',
			news_count: 15,
			today_count: 4
		},
		{
			cover: '/static/img/topicpic/11.jpeg',
			title: '"现实版樊胜美"弟弟疑遭人肉网暴',
			desc: '现实版樊胜美弟弟疑遭人肉网暴 挂出其母弟弟住址电话',
			news_count: 6,
			today_count: 0
		}
	];
	import topicList from '@/components/news/topic-list.vue';
	import loadMore from '@/components/common/load-more.vue';
	export default {
		data() {
			return {
				topicArray: [],
				// 顶部选项卡
				tabBars: [{
						name: '关注'
					},
					{
						name: '推荐'
					},
					{
						name: '体育'
					},
					{
						name: '热点'
					},
					{
						name: '财经'
					},
					{
						name: '娱乐'
					},
					{
						name: '军事'
					},
					{
						name: '历史'
					},
					{
						name: '本地'
					}

				],
				tabIndex: 0,
				scrollInto: '',
				// 列表高度
				scrollH: 600
			}
		},
		components: {
			topicList,
			loadMore
		},
		onLoad() {
			uni.getSystemInfo({
					success: function(res) {
						console.log(res);
						this.scrollH = res.windowHeight - uni.upx2px(100);
					}
				}),
				// 根据选项生成列表
				this.getData();
		},
		methods: {
			// 切换选项
			changeTab(index) {
				if (this.tabIndex === index) {
					return;
				}
				this.tabIndex = index;
				// 滚动到指定元素
				this.scrollInto = 'tab' + index;
			},
			// 监听滑动
			onChangeTab(e) {
				console.log(e);
				this.changeTab(e.detail.current);
			},
			// 获取数据
			getData() {
				var arr = [];
				for (let i = 0; i < this.tabBars.length; i++) {
					// 生成列表模板
					let obj = {
						// 3种状态:1.上拉加载更多;2.加载中...;3.没有更多了。
						loadmore: "上拉加载更多",
						list: []
					}
					if (i % 3 !== 2) {
						obj.list = test_data;
					}
					arr.push(obj)
				}
				this.topicArray = arr;
			},
			// 上拉加载更多
			loadMore(index) {
				// 获取当前列表
				let item = this.topicArray[index];
				// 判断是否处于可加载状态
				if (item.loadmore !== '上拉加载更多') return;
				// 修改当前列表加载状态
				item.loadmore = '加载中...';
				// 模拟数据请求
				setTimeout(() => {
					// 加载数据
					item.list = [...item.list, ...item.list];
					// 恢复加载状态
					this.topicArray[index].loadmore = '上拉加载更多';
				}, 2000)
			}
		}
	}
</script>

<style>

</style>

显示:

uniapp social app trend develop topic category view
uniapp social app trend develop topic category view

可以看到,实现了话题分类页开发。

四、话题详情页开发

1.pages.json配置和数据传递

先创建话题详情页topic-detail,如下:

代码语言:javascript
复制
<template>
	<view>
		话题详情
	</view>
</template>

<script>
	export default {
		data() {
			return {
				
			}
		},
		onLoad(e) {
			console.log(e);
			if (e.detail) {
				let res = JSON.parse(e.detail);
				console.log(res);
			}
		},
		methods: {
			
		}
	}
</script>

<style>

</style>

pages.json中配置导航栏样式如下:

代码语言:javascript
复制
{
    "path" : "pages/topic-detail/topic-detail",
    "style" :                                                                                    
    {
        "app-plus": {
            "titleNView": {
                "type":"transparent",
                "buttons": [
                    {
                        "type":"menu"
                    }
                ]
            }
        }
    }
    
}

topic_list.vue中传递数据如下:

代码语言:javascript
复制
<template>
	<view class="flex align-center p-2" @click="open()">
		<image class="rounded mr-2" :src="item.cover" style="width: 150rpx; height: 150rpx;"></image>
		<view class="flex flex-column flex-1">
			<text class="font-md text-dark">#{{item.title}}#</text>
			<text class="font text-secondry">{{item.desc}}</text>
			<view class="flex align-center font text-secondry">
				<text class="mr-2">动态:{{item.news_count}}</text>
				<text>今日:{{item.today_count}}</text>
			</view>
		</view>
	</view>
</template>

<script>
	export default {
		props: {
			item: Object,
			index: Number
		},
		methods: {
			open() {
				uni.navigateTo({
					url: '../../pages/topic-detail/topic-detail?detail='+JSON.stringify(this.item)
				});
			}
		}
	}
</script>

<style>
</style>

topic_list页中在跳转路由后以关键字传参的方式将当前的话题项传递给topic-detail页,数据形式是以detail为键的对象,topic-detail页中在onLoad()生命周期中接收并解析获取到传递过来的数据。

显示:

uniapp social app trend develop topic detail data send
uniapp social app trend develop topic detail data send

显然,实现了传递数据并跳转到话题详情页。

2.话题介绍组件开发和封装

话题详情页面顶部的话题介绍包括了颜色渐变的图片,下面包含话题的一些信息。 topic-detail.vue如下:

代码语言:javascript
复制
<template>
	<view>
		<view class="position-relative">
			<image src="/static/img/topicpic/12.jpeg" style="height: 300rpx;" class="w-100 filter"></image>
		</view>
		<view class="position-relative bg-white px-2" style="z-index: 10;">
			<view class="flex">
				<image src="/static/img/topicpic/12.jpeg" style="width: 150rpx; height: 150rpx; margin-top: -75rpx;" class="rounded mr-2"></image>
				<text>#话题标题#</text>
			</view>
			<view class="flex align-center font text-secondry mt-1">
				<text class="mr-2">动态:10</text>
				<text>今日:1</text>
			</view>
			<view class="font-md text-secondry">话题描述</view>
		</view>
		
	</view>
</template>

显示:

uniapp social app trend develop topic detail introduce view
uniapp social app trend develop topic detail introduce view

可以看到,话题介绍的布局已经设置好。

再将其封装为组件,components下新建目录topic-detail,下建topic-info.vue组件,如下:

代码语言:javascript
复制
<template>
	<view >
		<view class="position-relative">
			<image :src="info.cover" style="height: 300rpx;" class="w-100 filter"></image>
		</view>
		<view class="position-relative bg-white px-2 pb-2" style="z-index: 10;">
			<view class="flex">
				<image :src="info.cover" style="width: 150rpx; height: 150rpx; margin-top: -75rpx;" class="rounded mr-2"></image>
				<text>#{{info.title}}#</text>
			</view>
			<view class="flex align-center font text-secondry mt-1">
				<text class="mr-2">动态:{{info.news_count}}</text>
				<text>今日:{{info.today_count}}</text>
			</view>
			<view class="font-md text-secondry">{{info.desc}}</view>
		</view>
	</view>
</template>

<script>
	export default {
		props: ['info']
	}
</script>

<style>
</style>

topic-detail.vue如下:

代码语言:javascript
复制
<template>
	<view>
		<topic-info :info="info"></topic-info>
		<divider></divider>
	</view>
</template>

<script>
	import topicInfo from '@/components/topic-detail/topic-info.vue';
	export default {
		data() {
			return {
				info: {
					cover: '/static/img/topicpic/14.jpeg',
					title: '毛伟明当选湖南省人民政府省长',
					desc: '毛伟明当选湖南省人民政府省长',
					news_count: 10,
					today_count: 1
				}
			}
		},
		components: {
			topicInfo
		},
		onLoad(e) {
			console.log(e);
			if (e.detail) {
				let res = JSON.parse(e.detail);
				console.log(res);
			}
		},
		methods: {

		}
	}
</script>

<style>
	.filter {
		filter: blur(10px);
	}
</style>

效果与之前相同。

3.精华帖子列表组件开发

精华帖子也是一个列表,如下:

代码语言:javascript
复制
<template>
	<view>
		<topic-info :info="info"></topic-info>
		<divider></divider>
		<view class="p-2 flex align-center border-bottom" hover-class="bg-light">
			<text class="iconfont icon-zhiding text-main"></text>
			<text class="font text-dark text-ellipsis">面试之算法基础系列(1)最长子字符串、字符串同构</text>
		</view>
		<view class="p-2 flex align-center border-bottom" hover-class="bg-light">
			<text class="iconfont icon-zhiding text-main"></text>
			<text class="font text-dark text-ellipsis">uni-app开发 常见异常和解决办法</text>
		</view>
	</view>
</template>

显示:

uniapp social app trend develop topic detail essence view
uniapp social app trend develop topic detail essence view

显示出了精华帖子列表。

还可以优化如下:

代码语言:javascript
复制
<template>
	<view>
		<topic-info :info="info"></topic-info>
		<divider></divider>
		<block v-for="(item, index) in hotList" :key="index">
			<view class="p-2 flex align-center border-bottom" hover-class="bg-light">
				<text class="iconfont icon-zhiding text-main"></text>
				<text class="font text-dark text-ellipsis">{{item.title}}</text>
			</view>
		</block>
		<divider></divider>
	</view>
</template>

<script>
	import topicInfo from '@/components/topic-detail/topic-info.vue';
	export default {
		data() {
			return {
				info: {
					cover: '/static/img/topicpic/14.jpeg',
					title: '毛伟明当选湖南省人民政府省长',
					desc: '毛伟明当选湖南省人民政府省长',
					news_count: 10,
					today_count: 1
				},
				hotList: [
					{
						title: '面试之算法基础系列(1)最长子字符串、字符串同构'
					},
					{
						title: 'uni-app开发 常见异常和解决办法'
					}
				]
			}
		},
		components: {
			topicInfo
		},
		onLoad(e) {
			console.log(e);
			if (e.detail) {
				let res = JSON.parse(e.detail);
				console.log(res);
			}
		},
		methods: {

		}
	}
</script>

<style>
	.filter {
		filter: blur(10px);
	}
</style>

效果相同。

4.列表选项卡组件开发

展示列表选项卡包括默认和最新,展示该话题下的内容。

先实现标签栏,如下:

代码语言:javascript
复制
<!-- 标签栏 -->
<view class="flex align-center py-2">
    <view class="flex-1 font-lg font-weight-bold text-main flex align-center justify-center">默认</view>
    <view class="flex-1 font-md  flex align-center justify-center">最新</view>
</view>

显示:

uniapp social app trend develop topic detail selectcard tab
uniapp social app trend develop topic detail selectcard tab

已经展示出选项卡。

现进一步实现列表,如下:

代码语言:javascript
复制
<template>
	<view>
		<!-- 话题信息 -->
		<topic-info :info="info"></topic-info>
		<divider></divider>
		<!-- 精华帖 -->
		<block v-for="(item, index) in hotList" :key="'hot'+index">
			<view class="p-2 flex align-center border-bottom" hover-class="bg-light">
				<text class="iconfont icon-zhiding text-main"></text>
				<text class="font text-dark text-ellipsis">{{item.title}}</text>
			</view>
		</block>
		<divider></divider>
		<!-- 标签栏 -->
		<view class="flex align-center py-2">
			<view class="flex-1 flex align-center justify-center" v-for="(item ,index) in tabBars" :key="'tab'+index" :class="index === tabIndex ? 'font-lg font-weight-bold text-main' : 'font-md'" @click="changeTab(index)">{{item.name}}</view>
		</view>
		<!-- 列表 -->
		<block v-for="(item, index) in list1" :key="index">
			<common-list :item="item" :index="index"></common-list>
		</block>
	</view>
</template>

<script>
	// 测试数据
	const test_data = [{
			username: "Corley",
			userpic: "/static/img/userpic/12.jpg",
			newstime: "2021-01-24 上午11:30",
			isFollow: false,
			title: "uni-app入门教程",
			titlepic: "/static/img/datapic/42.jpg",
			support: {
				type: "support", // 顶
				support_count: 1,
				unsupport_count: 2
			},
			comment_count: 2,
			share_count: 2
		},
		{
			username: "Brittany",
			userpic: "/static/img/userpic/16.jpg",
			newstime: "2021-01-24 下午14:00",
			isFollow: false,
			title: "商业数据分析从入门到入职",
			support: {
				type: "unsupport", // 踩
				support_count: 2,
				unsupport_count: 3
			},
			comment_count: 5,
			share_count: 1
		},
		{
			username: "Jessica",
			userpic: "/static/img/userpic/7.jpg",
			newstime: "2021-01-24 下午14:44",
			isFollow: true,
			title: "Django+Vue开发生鲜电商平台",
			titlepic: "/static/img/datapic/11.jpg",
			support: {
				type: "", // 未操作
				support_count: 2,
				unsupport_count: 7
			},
			comment_count: 0,
			share_count: 2
		},
		{
			username: "Ashley",
			userpic: "/static/img/userpic/20.jpg",
			newstime: "2021-01-24 下午18:20",
			isFollow: true,
			title: "uni-app实战之社区交友APP",
			titlepic: "/static/img/datapic/30.jpg",
			support: {
				type: "support",
				support_count: 5,
				unsupport_count: 1
			},
			comment_count: 3,
			share_count: 0
		}
	];
	import topicInfo from '@/components/topic-detail/topic-info.vue';
	import commonList from '@/components/common/common-list.vue';
	export default {
		data() {
			return {
				info: {
					cover: '/static/img/topicpic/14.jpeg',
					title: '毛伟明当选湖南省人民政府省长',
					desc: '毛伟明当选湖南省人民政府省长',
					news_count: 10,
					today_count: 1
				},
				hotList: [
					{
						title: '面试之算法基础系列(1)最长子字符串、字符串同构'
					},
					{
						title: 'uni-app开发 常见异常和解决办法'
					}
				],
				tabIndex: 0,
				tabBars: [
					{
						name: '默认'
					},
					{
						name: '最新'
					}
				],
				list1: [],
				list2: []
			}
		},
		components: {
			topicInfo,
			commonList
		},
		onLoad(e) {
			console.log(e);
			if (e.detail) {
				let res = JSON.parse(e.detail);
				console.log(res);
			}
			this.list1 = test_data;
			this.list2 = test_data
		},
		methods: {
			changeTab(index) {
				this.tabIndex = index;
			}
		}
	}
</script>

<style>
	.filter {
		filter: blur(10px);
	}
</style>

显示:

uniapp social app trend develop topic detail selectcard list
uniapp social app trend develop topic detail selectcard list

已经实现了列表展示和标签栏点击。

再利用计算属性实现默认和最新列表切换,如下:

代码语言:javascript
复制
<template>
	<view>
		<!-- 话题信息 -->
		<topic-info :info="info"></topic-info>
		<divider></divider>
		<!-- 精华帖 -->
		<block v-for="(item, index) in hotList" :key="'hot'+index">
			<view class="p-2 flex align-center border-bottom" hover-class="bg-light">
				<text class="iconfont icon-zhiding text-main"></text>
				<text class="font text-dark text-ellipsis">{{item.title}}</text>
			</view>
		</block>
		<divider></divider>
		<!-- 标签栏 -->
		<view class="flex align-center py-2">
			<view class="flex-1 flex align-center justify-center" v-for="(item ,index) in tabBars" :key="'tab'+index" :class="index === tabIndex ? 'font-lg font-weight-bold text-main' : 'font-md'"
			 @click="changeTab(index)">{{item.name}}</view>
		</view>
		<!-- 列表 -->
		<template v-if="listData.length > 0">
			<block v-for="(item, index) in listData" :key="index">
				<common-list :item="item" :index="index"></common-list>
				<divider></divider>
			</block>
		</template>
		<template v-else>
			<no-thing></no-thing>
		</template>
	</view>
</template>

<script>
	// 测试数据
	const test_data = [{
			username: "Corley",
			userpic: "/static/img/userpic/12.jpg",
			newstime: "2021-01-24 上午11:30",
			isFollow: false,
			title: "uni-app入门教程",
			titlepic: "/static/img/datapic/42.jpg",
			support: {
				type: "support", // 顶
				support_count: 1,
				unsupport_count: 2
			},
			comment_count: 2,
			share_count: 2
		},
		{
			username: "Brittany",
			userpic: "/static/img/userpic/16.jpg",
			newstime: "2021-01-24 下午14:00",
			isFollow: false,
			title: "商业数据分析从入门到入职",
			support: {
				type: "unsupport", // 踩
				support_count: 2,
				unsupport_count: 3
			},
			comment_count: 5,
			share_count: 1
		},
		{
			username: "Jessica",
			userpic: "/static/img/userpic/7.jpg",
			newstime: "2021-01-24 下午14:44",
			isFollow: true,
			title: "Django+Vue开发生鲜电商平台",
			titlepic: "/static/img/datapic/11.jpg",
			support: {
				type: "", // 未操作
				support_count: 2,
				unsupport_count: 7
			},
			comment_count: 0,
			share_count: 2
		},
		{
			username: "Ashley",
			userpic: "/static/img/userpic/20.jpg",
			newstime: "2021-01-24 下午18:20",
			isFollow: true,
			title: "uni-app实战之社区交友APP",
			titlepic: "/static/img/datapic/30.jpg",
			support: {
				type: "support",
				support_count: 5,
				unsupport_count: 1
			},
			comment_count: 3,
			share_count: 0
		}
	];
	import topicInfo from '@/components/topic-detail/topic-info.vue';
	import commonList from '@/components/common/common-list.vue';
	import noThing from '@/components/common/no-thing.vue';
	export default {
		data() {
			return {
				info: {
					cover: '/static/img/topicpic/14.jpeg',
					title: '毛伟明当选湖南省人民政府省长',
					desc: '毛伟明当选湖南省人民政府省长',
					news_count: 10,
					today_count: 1
				},
				hotList: [{
						title: '面试之算法基础系列(1)最长子字符串、字符串同构'
					},
					{
						title: 'uni-app开发 常见异常和解决办法'
					}
				],
				tabIndex: 0,
				tabBars: [{
						name: '默认'
					},
					{
						name: '最新'
					}
				],
				// 默认
				list1: [],
				// 最新
				list2: []
			}
		},
		components: {
			topicInfo,
			commonList,
			noThing
		},
		computed: {
			listData() {
				return this['list' + (this.tabIndex + 1)];
			}
		},
		onLoad(e) {
			console.log(e);
			if (e.detail) {
				let res = JSON.parse(e.detail);
				console.log(res);
			}
			this.list1 = test_data;
		},
		methods: {
			changeTab(index) {
				this.tabIndex = index;
			}
		}
	}
</script>

<style>
	.filter {
		filter: blur(10px);
	}
</style>

显示:

uniapp social app trend develop topic detail selectcard list computed
uniapp social app trend develop topic detail selectcard list computed

可以看到,实现了联动动态显示。

5.话题详情上拉加载更多

这里因为列表不是用scroll-view组件实现的,因此上拉加载也不能使用@scrolltolower事件实现,需要使用页面上拉加载事件来实现,即onReachBottom事件,这是页面滚动到底部的事件,不同于scroll-view滚到底,常用于下拉下一页数据。

topic-detail.vue如下:

代码语言:javascript
复制
<template>
	<view>
		<!-- 话题信息 -->
		<topic-info :info="info"></topic-info>
		<divider></divider>
		<!-- 精华帖 -->
		<block v-for="(item, index) in hotList" :key="'hot'+index">
			<view class="p-2 flex align-center border-bottom" hover-class="bg-light">
				<text class="iconfont icon-zhiding text-main"></text>
				<text class="font text-dark text-ellipsis">{{item.title}}</text>
			</view>
		</block>
		<divider></divider>
		<!-- 标签栏 -->
		<view class="flex align-center py-2">
			<view class="flex-1 flex align-center justify-center" v-for="(item ,index) in tabBars" :key="'tab'+index" :class="index === tabIndex ? 'font-lg font-weight-bold text-main' : 'font-md'"
			 @click="changeTab(index)">{{item.name}}</view>
		</view>
		<!-- 列表 -->
		<template v-if="listData.length > 0">
			<block v-for="(item, index) in listData" :key="index">
				<common-list :item="item" :index="index"></common-list>
				<divider></divider>
			</block>
		</template>
		<template v-else>
			<no-thing></no-thing>
		</template>
		<!-- 上拉加载 -->
		<load-more :loadmore="loadtext"></load-more>
	</view>
</template>

<script>
	// 测试数据
	const test_data = [{
			username: "Corley",
			userpic: "/static/img/userpic/12.jpg",
			newstime: "2021-01-24 上午11:30",
			isFollow: false,
			title: "uni-app入门教程",
			titlepic: "/static/img/datapic/42.jpg",
			support: {
				type: "support", // 顶
				support_count: 1,
				unsupport_count: 2
			},
			comment_count: 2,
			share_count: 2
		},
		{
			username: "Brittany",
			userpic: "/static/img/userpic/16.jpg",
			newstime: "2021-01-24 下午14:00",
			isFollow: false,
			title: "商业数据分析从入门到入职",
			support: {
				type: "unsupport", // 踩
				support_count: 2,
				unsupport_count: 3
			},
			comment_count: 5,
			share_count: 1
		},
		{
			username: "Jessica",
			userpic: "/static/img/userpic/7.jpg",
			newstime: "2021-01-24 下午14:44",
			isFollow: true,
			title: "Django+Vue开发生鲜电商平台",
			titlepic: "/static/img/datapic/11.jpg",
			support: {
				type: "", // 未操作
				support_count: 2,
				unsupport_count: 7
			},
			comment_count: 0,
			share_count: 2
		},
		{
			username: "Ashley",
			userpic: "/static/img/userpic/20.jpg",
			newstime: "2021-01-24 下午18:20",
			isFollow: true,
			title: "uni-app实战之社区交友APP",
			titlepic: "/static/img/datapic/30.jpg",
			support: {
				type: "support",
				support_count: 5,
				unsupport_count: 1
			},
			comment_count: 3,
			share_count: 0
		}
	];
	import topicInfo from '@/components/topic-detail/topic-info.vue';
	import commonList from '@/components/common/common-list.vue';
	import noThing from '@/components/common/no-thing.vue';
	import loadMore from '@/components/common/load-more.vue';
	export default {
		data() {
			return {
				info: {
					cover: '/static/img/topicpic/14.jpeg',
					title: '毛伟明当选湖南省人民政府省长',
					desc: '毛伟明当选湖南省人民政府省长',
					news_count: 10,
					today_count: 1
				},
				hotList: [{
						title: '面试之算法基础系列(1)最长子字符串、字符串同构'
					},
					{
						title: 'uni-app开发 常见异常和解决办法'
					}
				],
				tabIndex: 0,
				tabBars: [{
						name: '默认'
					},
					{
						name: '最新'
					}
				],
				// 默认
				list1: [],
				loadtext1: '上拉加载更多',
				// 最新
				list2: [],
				loadtext2: '上拉加载更多'
			}
		},
		components: {
			topicInfo,
			commonList,
			noThing
		},
		computed: {
			// 当前列表数据
			listData() {
				return this['list' + (this.tabIndex + 1)];
			},
			// 当前下拉加载
			loadtext() {
				return this['loadtext' + (this.tabIndex + 1)];
			}
		},
		onLoad(e) {
			console.log(e);
			if (e.detail) {
				let res = JSON.parse(e.detail);
				console.log(res);
			}
			this.list1 = test_data;
		},
		// 触底事件
		onReachBottom() {
			console.log('Reaching bottom');
			this.loadmore();
		},
		methods: {
			changeTab(index) {
				this.tabIndex = index;
			},
			// 上拉加载更多
			loadmore() {
				// 获取当前列表
				let index = this.tabIndex;
				// 是否处于可加载状态
				if (this.loadtext !== '上拉加载更多') return;
				// 设置上拉加载状态
				this['loadtext' + (index + 1)] = '加载中...';
				// 请求数据
				setTimeout(() => {
					this['list' + (index + 1)] = [...this['list' + (index + 1)], ...this['list' + (index + 1)]];
					this['loadtext' + (index + 1)] = '上拉加载更多';
				}, 2000);
			}
		}
	}
</script>

<style>
	.filter {
		filter: blur(10px);
	}
</style>

显示:

uniapp social app trend develop topic detail loadmore
uniapp social app trend develop topic detail loadmore

可以看到,实现了切换和加载更多。 使用了计算属性,可以很方便地切换listloadtext

总结

随着项目的增大,需要对项目进行优化,比如将常用的元素封装为组件,可以提高代码的复用率,包括热门分类、话题列表组件和话题介绍组件等,大大优化了代码结构。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-01-30 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 前言
  • 一、顶部导航栏开发
  • 二、关注列表页开发
    • 1.滑动滚动区域运算
      • 2.导航列表联动实现
        • 3.顶踩操作和上拉加载功能
        • 三、话题专题和分类页开发
          • 1.热门分类组件开发和封装
            • 2.搜索框和轮播图开发
              • 3.话题列表组件开发和封装
                • 4.话题分类页开发
                • 四、话题详情页开发
                  • 1.pages.json配置和数据传递
                    • 2.话题介绍组件开发和封装
                      • 3.精华帖子列表组件开发
                        • 4.列表选项卡组件开发
                          • 5.话题详情上拉加载更多
                          • 总结
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档