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

文章目录

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

小编目前在做毕业设计,主题为“高考志愿信息交流平台”,面向高中生和大学生,辛苦各位读者大佬朋友们填下问卷,点击链接https://www.wjx.cn/jq/98944127.aspx或扫描二维码、微信小程序码均可,希望各位能提供一些调查数据,先在这里谢过各位了(*^_^*)
问卷1
问卷微信小程序码

前言

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

一、顶部导航栏开发

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

<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如下:

/* 内外边距 */
.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如下:

/* 本项目全局样式 */
/* 背景 */
.bg-main {
     
	background-color: #FF4A6A;
}

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

.text-secondry {
     
	color: #AAA8AB;
}

.text-dark {
     
	color: #333333;
}

显示:
uni-app实战之社区交友APP(6)动态页开发_第1张图片

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

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


<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中禁止原生导航栏,如下:

{
     
    "path" : "pages/news/news",
    "style" :                                                                                    
    {
     
        "navigationBarTitleText": "",
        "enablePullDownRefresh": false,
        "app-plus": {
     
            "titleNView": false
        }
    }
    
}

显示:
uni-app实战之社区交友APP(6)动态页开发_第2张图片

显然,此时更加美观。

再添加点击事件,如下:

<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>

显示:
uni-app实战之社区交友APP(6)动态页开发_第3张图片

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

二、关注列表页开发

1.滑动滚动区域运算

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

<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/CUFEECRview>
				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>

显示:

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

2.导航列表联动实现

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

<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>

显示:

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

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

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

先实现顶踩功能,如下:

<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>

显示:

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

再实现加载功能,如下:

<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>

显示:

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

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

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

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

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

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

<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>

显示:

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

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

<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修改如下:

<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.搜索框和轮播图开发

先实现搜索框,如下:


<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>

显示:
uni-app实战之社区交友APP(6)动态页开发_第4张图片

显然,实现了搜索框。

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


<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>

显示:

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

如需轮播图图片素材等文件,可以直接点击加QQ群 Python极客部落963624318 ,在群文件夹uni-app实战之社区交友APP中下载即可。

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

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


<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">动态:10text>
            <text>今日:1text>
        view>
    view>
view>

显示:
uni-app实战之社区交友APP(6)动态页开发_第5张图片

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

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

<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>

显示:

此时,已经有话题列表。

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

<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如下:

<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配置如下:

{
     
    "path" : "pages/topic-nav/topic-nav",
    "style" :                                                                                    
    {
     
        "navigationBarTitleText": "话题分类",
        "enablePullDownRefresh": false
    }
    
}

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

openMore() {
     
    console.log('opening more');
    uni.navigateTo({
     
        url: '../../pages/topic-nav/topic-nav'
    });
},

topic-nav.vue页面如下:

<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>

显示:

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

四、话题详情页开发

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

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

<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中配置导航栏样式如下:

{
     
    "path" : "pages/topic-detail/topic-detail",
    "style" :                                                                                    
    {
     
        "app-plus": {
     
            "titleNView": {
     
                "type":"transparent",
                "buttons": [
                    {
     
                        "type":"menu"
                    }
                ]
            }
        }
    }
    
}

topic_list.vue中传递数据如下:

<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()生命周期中接收并解析获取到传递过来的数据。

显示:

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

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

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

<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">动态:10text>
				<text>今日:1text>
			view>
			<view class="font-md text-secondry">话题描述view>
		view>
		
	view>
template>

显示:
uni-app实战之社区交友APP(6)动态页开发_第6张图片

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

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

<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如下:

<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.精华帖子列表组件开发

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

<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>

显示:
uni-app实战之社区交友APP(6)动态页开发_第7张图片

显示出了精华帖子列表。

还可以优化如下:

<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.列表选项卡组件开发

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

先实现标签栏,如下:


<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>

显示:
uni-app实战之社区交友APP(6)动态页开发_第8张图片

已经展示出选项卡。

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

<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>

显示:

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

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

<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>

显示:

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

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

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

topic-detail.vue如下:

<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>

显示:

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

总结

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

你可能感兴趣的:(移动应用开发实战,uni-app实战,社区交友APP,动态页开发)