前端开发~uni-app ·[项目-仿糗事百科] 学习笔记 ·008【首页开发】

注:前言、目录见 https://god-excious.blog.csdn.net/article/details/105312456

【024】page-json配置

官方文档 https://uniapp.dcloud.io/collocation/pages?id=配置项列表

官方文档 https://uniapp.dcloud.io/collocation/pages?id=style

可以在page-json中配置一些样式,包括“导航栏”、“按钮”、“下拉刷新”等样式。

大多数内容可以到官方文档中找到,下面给出一种配置的样式

{
	"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
		{
			"path": "pages/index/index",
			"style": {
				// "navigationBarTitleText": "仿糗事百科"
             
				"app-plus": {
					// 隐藏滚动条
					"scrollIndicator":"none",
					// 配置导航栏
					"titleNView": {
						// 配置搜索框
						"searchInput": {
							// 对齐方式(默认值center)
							"align": "center",
							// 背景色
							"backgroundColor": "#F7F7F7",
							// 边框圆角
							"borderRadius": "4px",
							// 提示文字
							"placeholder": "搜索糗事",
							// 阻止输入(一般都是阻止输入,点击后跳转到搜索页面)
							"disabled": "true"
						},
						// 配置按钮
						"buttons": [
							// 左边按钮
							{
								// 设置颜色
								"color": "#FF9619",
								// 设置按钮按下的颜色
								"colorPressed": "#BBBBBB",
								// 设置浮动
								"float": "left",
								// 设置按钮上文字大小
								"fontSize": "22px",
								// 设置字体文件的路径
								"fontSrc": "/static/font/icon.ttf",
								// 设置按钮上显示的文字
								"text": "\ue609"
							},
							// 右边按钮
							{
								"color": "#000000",
								"colorPressed": "#BBBBBB",
								"float": "right",
								"fontSize": "22px",
								"fontSrc": "/static/font/icon.ttf",
								"text": "\ue653"
							}
						]
					}
				}
			}
		}
        ,{
            "path" : "pages/news/news",
            "style" : {}
        }
        ,{
            "path" : "pages/paper/paper",
            "style" : {}
        }
        ,{
            "path" : "pages/home/home",
            "style" : {}
        }
    ],
	"globalStyle": {
		"navigationBarTextStyle": "black",
		"navigationBarTitleText": "仿糗事百科",
		"navigationBarBackgroundColor": "#F8F8F8",
		"backgroundColor": "#F8F8F8"
	},
	"tabBar": {
		"color":"#adadad",         // 导航栏文字默认颜色
		"selectedColor":"#fee42a", // 导航栏选中颜色
		"backgroundColor":"#fff",  // 导航栏背景颜色
		"borderStyle":"white",     // 导航栏边框样式
		"list":[                   // tab的列表
			{
				"pagePath":"pages/index/index",                 // 导航栏对应页面路径(不用写.vue)
				"text":"糗事",                                  // 导航栏文字
				"iconPath":"static/tabbar/index.png",           // 导航栏未选中的图标路径
				"selectedIconPath":"static/tabbar/indexed.png"  // 导航栏已选中的图标路径
			},
			{
				"pagePath":"pages/news/news",
				"text":"动态",
				"iconPath":"static/tabbar/news.png",
				"selectedIconPath":"static/tabbar/newsed.png"
			},
			{
				"pagePath":"pages/paper/paper",
				"text":"小纸条",
				"iconPath":"static/tabbar/paper.png",
				"selectedIconPath":"static/tabbar/papered.png"
			},
			{
				"pagePath":"pages/home/home",
				"text":"我的",
				"iconPath":"static/tabbar/home.png",
				"selectedIconPath":"static/tabbar/homed.png"
			}
		]
	}
}

注:

  • buttons中字体的路径fontSrc对应了图标项目中的iconfont.ttf文件的路径,一般将其引入到uni-app项目中的/static/font文件夹下
  • buttons中提示文字text,填写的内容为图标项目中demo_index.html打开后Unicode下,该图标的编号。例如:某图标在Unicode中编号为,就应该填写"text": "\ue601",以此类推。

【025】图文、视频和列表样式(上)

图片引入

图片组件——官方文档 https://uniapp.dcloud.io/component/image

格式大致如下

<image src="../../static/demo/userpic/12.jpg" mode="widthFix" lazy-load></image>
属性 功能
src 图片路径
mode 图片裁剪、缩放的模式(widthFix代表宽度不变,高度自动变化,保持原图宽高比不变
lazy-load 图片懒加载

设计细节

在设计时,需要注意以下一些细节

  1. 首先按照设计图,对某个区域可以分成若干行,我们把这些行都做成class="网页名-list-i"view组件,然后将它们放到一个class="网页名-list"view组件中
  2. 像是头像、昵称这一组,或者是**+icon、关注这一组,都是水平方向上垂直居中排列的,可以把文字(直接写到父标签下,不一定要新建标签)、图像放到一个view组件下,然后以flex布局(默认主轴方向即可)设置交叉轴(纵向)居中——align-item: center;**,即可在同一行上垂直居中排版
  3. 像是赞数、踩数这一组,或者是评论数、转发数这一组,水平方向上垂直居中和上面类似,还要设计好图标与文字之间的间距,可以给图标设置一个**margin-right,如果有多个图标和文字的组,并且排列在同一侧,可以给图标的父标签设置一个margin-right**,让组与组之间保持间距。
  4. 设计图中的一些圆角不要忽略了
  5. 行与行之间的间距可以通过给类名为网页名-list-i的元素设置一个padding-top,最后一个行元素可以考虑设置一个padding: ??px, 0;让上下都保持一部分间距
  6. 整个区域内部的边缘地区若有少量间距,可以对整个区域的标签设置一个padding,显示出这样的空隙。
  7. 整个区域往下的分隔线,可以通过设置border-bottom属性实现
  8. 阿里巴巴矢量图库项目的图标引入,可以参考章节【010】
  9. 为了增强CSS代码复用性,可以把flex布局的相关代码提取出来,封装到common.css文件里去,一般根据flex布局的样式来起名,我们可以取出类似u-fu-f-acu-f-ajcu-f-jsb这样的类名,然后给需要的标签加上这些类名。

整体代码

  • index.css文件

    <template>
    	<view>
    		<view class="index-list">
    			<view class="index-list1 u-f-ac u-f-jsb">
    				<view class="u-f-ac">
    					<image src="../../static/demo/userpic/12.jpg" mode="widthFix" lazy-load></image>
    					昵称
    				</view>
    				<view class="u-f-ac">
    					<view class="icon iconfont icon-zengjia"></view>关注
    				</view>
    			</view>
    			<view class="index-list2">这是标题</view>
    			<view class="index-list3">
    				<image src="../../static/demo/datapic/11.jpg" mode="widthFix" lazy-load></image>
    			</view>
    			<view class="index-list4 u-f-ac u-f-jsb">
    				<view class="u-f-ac">
    					<view class="u-f-ac">
    						<view class="icon iconfont icon-icon_xiaolian-mian u-f-ac"></view>
    						10
    					</view>
    					<view class="u-f-ac">
    						<view class="icon iconfont icon-kulian u-f-ac"></view>
    						10
    					</view>
    				</view>
    				<view class="u-f-ac">
    					<view class="u-f-ac">
    						<view class="icon iconfont icon-pinglun1 u-f-ac"></view>
    						10
    					</view>
    					<view class="u-f-ac">
    						<view class="icon iconfont icon-zhuanfa u-f-ac"></view>
    						10
    					</view>
    				</view>
    			</view>
    		</view>
    	</view>
    </template>
    
    <script>
    	export default {
    		data() {
    			return {
    				title: 'Hello'
    			}
    		},
    		onLoad() {
    
    		},
    		methods: {
    
    		}
    	}
    </script>
    
    <style>
    	/* common.css在App.vue文件中引入了进来 */
    	.index-list {
    		padding: 20upx;
    		border-bottom: 1upx solid #EEEEEE;
    	}
    	
    	.index-list1>view:first-child {
    		color: #999999;
    	}
    	
    	.index-list1>view:first-child image {
    		width: 90upx;
    		height: 90upx;
    		border-radius: 50%;
    		margin-right: 10upx;
    	}
    	
    	.index-list1>view:last-child {		
    		background-color: #F4F4F4;
    		border-radius: 5upx;
    		padding: 0 10upx;
    	}
    	
    	.index-list2 {
    		padding-top: 15upx;
    		font-size: 32upx;
    	}
    
    	.index-list3 {
    		padding-top: 15upx;
    	}
    
    	.index-list3>image {
    		width: 100%;
    		border-radius: 20upx;
    	}
    
    	.index-list4 {
    		padding: 15upx 0;
    	}
    	
    	.index-list4>view {
    		color: #999999;
    	}
    	
    	.index-list4>view>view:first-child, .index-list4>view>view>view {
    		margin-right: 10upx;
    	}
    </style>
    
  • common.css文件

    /* 代表flex布局 */
    .u-f, .u-f-ac, .u-f-ajc, .u-f-jsb {
    	display: flex;
    }
    
    .u-f-ac, .u-f-ajc {
    	align-items: center;
    }
    
    .u-f-ajc {
    	justify-content: center;
    }
    
    .u-f-jsb {
    	justify-content: space-between;
    }
    
  • App.vue文件

    <script>
    	export default {
    		onLaunch: function() {
    			console.log('App Launch')
    		},
    		onShow: function() {
    			console.log('App Show')
    		},
    		onHide: function() {
    			console.log('App Hide')
    		}
    	}
    </script>
    
    <style>
    	/*每个页面公共css */
        @import './common/uni.css';
        @import './common/icon.css';
        @import './common/animate.css';
        @import './common/common.css';
    </style>
    
  • pages.json文件

    和上一节一样

  • 效果图

    1

【026】图文、视频和列表样式(下)

设计细节

在设计时,有以下一些细节

  1. 要让某个组件显示在另一个组件之上,可以把他们放到同一个父组件下,然后对父组件用postion: relative;,对子组件用postion: absolute;。然后如果需要显示在父组件的正中央,可以给父组件设置一个class="u-f-ajc";如果需要显示在父组件的边上,可以设置rightlefttopbottom其中的不同方向上的两个。
  2. 如果需要调节带透明的背景色,可以到Chrome浏览器中打开开发者工具,随便找一个元素,添加属性color,然后点击对应的颜色,拖动透明度条,进行调节,如果需要rgba,点击上下切换的小箭头切换,然后把color属性里的rgba值复制过来。
  3. 对于阿里巴巴矢量图标库项目中,通过添加类名引入的图标,如果要设置其大小,只需要设置font-size属性即可。

整体代码

  • index.vue文件

    和上一节课相比,主要增加、改动的地方是17~21行、94行、115~130行

    <template>
    	<view>
    		<view class="index-list">
    			<view class="index-list1 u-f-ac u-f-jsb">
    				<view class="u-f-ac">
    					<image src="../../static/demo/userpic/12.jpg" mode="widthFix" lazy-load></image>
    					昵称
    				</view>
    				<view class="u-f-ac">
    					<view class="icon iconfont icon-zengjia"></view>关注
    				</view>
    			</view>
    			<view class="index-list2">这是标题</view>
    			<view class="index-list3 u-f-ajc">
    				<!-- 图片 -->
    				<image src="../../static/demo/datapic/11.jpg" mode="widthFix" lazy-load></image>
    				<!-- 视频 -->
    				<view class="index-list-play icon iconfont icon-bofang"></view>
    				<view class="index-list-playinfo">
    					20w次播放 2:17
    				</view>
    			</view>
    			<view class="index-list4 u-f-ac u-f-jsb">
    				<view class="u-f-ac">
    					<view class="u-f-ac">
    						<view class="icon iconfont icon-icon_xiaolian-mian u-f-ac"></view>
    						10
    					</view>
    					<view class="u-f-ac">
    						<view class="icon iconfont icon-kulian u-f-ac"></view>
    						10
    					</view>
    				</view>
    				<view class="u-f-ac">
    					<view class="u-f-ac">
    						<view class="icon iconfont icon-pinglun1 u-f-ac"></view>
    						10
    					</view>
    					<view class="u-f-ac">
    						<view class="icon iconfont icon-zhuanfa u-f-ac"></view>
    						10
    					</view>
    				</view>
    			</view>
    		</view>
    	</view>
    </template>
    
    <script>
    	export default {
    		data() {
    			return {
    				title: 'Hello'
    			}
    		},
    		onLoad() {
    
    		},
    		methods: {
    
    		}
    	}
    </script>
    
    <style>
    	.index-list {
    		padding: 20upx;
    		border-bottom: 1upx solid #EEEEEE;
    	}
    	
    	.index-list1>view:first-child {
    		color: #999999;
    	}
    	
    	.index-list1>view:first-child image {
    		width: 90upx;
    		height: 90upx;
    		border-radius: 50%;
    		margin-right: 10upx;
    	}
    	
    	.index-list1>view:last-child {		
    		background-color: #F4F4F4;
    		border-radius: 5upx;
    		padding: 0 10upx;
    	}
    	
    	.index-list2 {
    		padding-top: 15upx;
    		font-size: 32upx;
    	}
    
    	.index-list3 {
    		position: relative;
    		padding-top: 15upx;
    	}
    
    	.index-list3>image {
    		width: 100%;
    		border-radius: 20upx;
    	}
    
    	.index-list4 {
    		padding: 15upx 0;
    	}
    	
    	.index-list4>view {
    		color: #999999;
    	}
    	
    	.index-list4>view>view:first-child, .index-list4>view>view>view {
    		margin-right: 10upx;
    	}
    	
    	.index-list-play {
    		position: absolute;
    		font-size: 140upx;
    		color: #FFFFFF;
    	}
    	
    	.index-list-playinfo {
    		position: absolute;
    		background-color: rgba(51, 51, 51, 0.62);
    		color: #FFFFFF;
    		bottom: 8upx;
    		right: 8upx;
    		border-radius: 40upx;
    		font-size: 22upx;
    		padding: 0 12upx;
    	}
    </style>
    
  • 其他文件

    和上一小节相同,不再重复

  • 效果图

    2

【027】封装列表样式组件

数据存储

script脚本的data()中,用数组将页面中出现的数据封装成一个个对象

<script>
	export default {
		data() {
			return {
				list:[
					{
						// 用户头像
						userpic: "../../static/demo/userpic/12.jpg",
						// 用户名
						username: "昵称",
						// 关注情况
						isguanzhu: false,
						// 标题
						title: "这是标题",
						// 类型(img-图文,video-视频)
						type: "img",
						// 封面图
						titlepic: "../../static/demo/datapic/11.jpg",
						// 赞、踩数,标记情况
						infonum: {
							index: 1,  // 0-无操作,1-顶了,2-踩了
							dingnum: 11,
							cainum: 11,
						},
						commentnum: 10,
						sharenum: 10
					},
					{
						userpic: "../../static/demo/userpic/12.jpg",
						username: "昵称",
						isguanzhu: true,
						title: "这是标题",
						type: "video",
						titlepic: "../../static/demo/datapic/11.jpg",
						// 播放次数
						playnum: "2w",
						long: "2:47",
						infonum: {
							index: 2,
							dingnum: 11,
							cainum: 11,
						},
						commentnum: 10,
						sharenum: 10
					},
				]
			}
		},
		onLoad() {

		},
		methods: {

		}
	}
</script>

因为有可能存在多个对象,所以需要列表渲染(循环),详细代码见下面一小段。

状态(关注、赞、踩)标识

“是否关注”这一状态可以完全放到list对象中一个对象的一个布尔变量来标识,用v-show进行条件渲染

“是否点赞、是否点踩”这些状态,和点赞数、点踩数一起放到list对象中一个对象的一个infonum里,状态用index来标识,值为0代表“未操作”,值为1代表“点了赞”,值为2代表“点了踩”。然后在:class属性中根据一个条件表达式选择判断是否获得点击后的类名active的样式。

<template>
	<view>
		<block v-for="(item, index) in list" :key="index">
			<view class="index-list">
				<view class="index-list1 u-f-ac u-f-jsb">
					<view class="u-f-ac">
						<image :src="item.userpic" mode="widthFix" lazy-load></image>
						{{item.username}}
					</view>
					<!-- v-if会导致一点布局异常,还是用v-show好一些 -->
					<view class="u-f-ac" v-show="item.isguanzhu">
						<view class="icon iconfont icon-zengjia"></view>关注
					</view>
				</view>
				<view class="index-list2">{{item.title}}</view>
				<view class="index-list3 u-f-ajc">
					<!-- 图片 -->
					<image :src="item.titlepic" mode="widthFix" lazy-load></image>
					<!-- 视频 -->
					<template v-if="item.type=='video'">
						<view class="index-list-play icon iconfont icon-bofang"></view>
						<view class="index-list-playinfo">
							{{item.playnum}}次播放 {{item.long}}
						</view>
					</template>
				</view>
				<view class="index-list4 u-f-ac u-f-jsb">
					<view class="u-f-ac">
						<view class="u-f-ac" :class="{'active':(item.infonum.index==1)}">
							<view class="icon iconfont icon-icon_xiaolian-mian u-f-ac"></view>
							{{item.infonum.dingnum}}
						</view>
						<view class="u-f-ac" :class="{'active':(item.infonum.index==2)}">
							<view class="icon iconfont icon-kulian u-f-ac"></view>
							{{item.infonum.cainum}}
						</view>
					</view>
					<view class="u-f-ac">
						<view class="u-f-ac">
							<view class="icon iconfont icon-pinglun1 u-f-ac"></view>
							{{item.commentnum}}
						</view>
						<view class="u-f-ac">
							<view class="icon iconfont icon-zhuanfa u-f-ac"></view>
							{{item.sharenum}}
						</view>
					</view>
				</view>
			</view>
		</block>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				list:[
					{
						// 用户头像
						userpic: "../../static/demo/userpic/12.jpg",
						// 用户名
						username: "昵称",
						// 关注情况
						isguanzhu: false,
						// 标题
						title: "这是标题",
						// 类型(img-图文,video-视频)
						type: "img",
						// 封面图
						titlepic: "../../static/demo/datapic/11.jpg",
						// 赞、踩数,标记情况
						infonum: {
							index: 1,  // 0-无操作,1-顶了,2-踩了
							dingnum: 11,
							cainum: 11,
						},
						commentnum: 10,
						sharenum: 10
					},
					{
						userpic: "../../static/demo/userpic/12.jpg",
						username: "昵称",
						isguanzhu: true,
						title: "这是标题",
						type: "video",
						titlepic: "../../static/demo/datapic/11.jpg",
						// 播放次数
						playnum: "2w",
						long: "2:47",
						infonum: {
							index: 2,
							dingnum: 11,
							cainum: 11,
						},
						commentnum: 10,
						sharenum: 10
					},
				]
			}
		},
		onLoad() {

		},
		methods: {

		}
	}
</script>

<style>
	.index-list {
		padding: 20upx;
		border-bottom: 1upx solid #EEEEEE;
	}
	
	.index-list1>view:first-child {
		color: #999999;
	}
	
	.index-list1>view:first-child image {
		width: 90upx;
		height: 90upx;
		border-radius: 50%;
		margin-right: 10upx;
	}
	
	.index-list1>view:last-child {		
		background-color: #F4F4F4;
		border-radius: 5upx;
		padding: 0 10upx;
	}
	
	.index-list2 {
		padding-top: 15upx;
		font-size: 32upx;
	}

	.index-list3 {
		position: relative;
		padding-top: 15upx;
	}

	.index-list3>image {
		width: 100%;
		border-radius: 20upx;
	}

	.index-list4 {
		padding: 15upx 0;
	}
	
	.index-list4>view {
		color: #999999;
	}
	
	.index-list4>view>view:first-child, .index-list4>view>view>view {
		margin-right: 10upx;
	}
	
	.index-list-play {
		position: absolute;
		font-size: 140upx;
		color: #FFFFFF;
	}
	
	.index-list-playinfo {
		position: absolute;
		background-color: rgba(51, 51, 51, 0.62);
		color: #FFFFFF;
		bottom: 8upx;
		right: 8upx;
		border-radius: 40upx;
		font-size: 22upx;
		padding: 0 12upx;
	}
	
	.index-list4 .active, .index-list4 .active > view{
		color: #C5F61C;
	}
	
</style>

效果图

3

封装组件

像是上面我们做好的一个list样式,就可以封装起来。

封装的步骤如下:

  1. 创建好一个components文件夹,然后右键新建组件,在components文件夹下再创建一个index文件夹,把之前新建好的组件文件index-list.vue文件放到index文件夹

  2. index.vue文件block标签下的所有标签剪切,放到index-list.vue文件中对应位置

  3. index.vue文件style 下的所有样式剪切,放到index-list.vue文件中对应位置。

    注:最好给里面的style加上一个属性scoped,避免在引入组件样式后污染原本设置好的其他样式

  4. index-list.vue文件script下的props中,定义需要传入的变量及其类型,像是这里就需要将循环中的itemindex传进来,形式为变量名: 类型

  5. index.vue文件scriptexport default前,将组件文件引入进来,形如:

    import indexList from "../../components/index/index-list.vue";
    

    注:将中划线命名改写为小驼峰命名

  6. index.vue文件scriptcomponents中,注册相应的组件

  7. 以标签形式将组件进行引入,在属性中传入需要的参数,形如:

    <block v-for="(item, index) in list" :key="index">
        <index-list :item="item" :index="index"></index-list>
    </block>
    

封装后的项目代码文件如下:

  • index.vue文件

    <template>
    	<view>
    		<block v-for="(item, index) in list" :key="index">
    			<index-list :item="item" :index="index"></index-list>
    		</block>
    	</view>
    </template>
    
    <script>
    	import indexList from "../../components/index/index-list.vue";
    	export default {
    		components: {
    			indexList
    		},
    		data() {
    			return {
    				list:[
    					{
    						// 用户头像
    						userpic: "../../static/demo/userpic/12.jpg",
    						// 用户名
    						username: "昵称",
    						// 关注情况
    						isguanzhu: false,
    						// 标题
    						title: "这是标题",
    						// 类型(img-图文,video-视频)
    						type: "img",
    						// 封面图
    						titlepic: "../../static/demo/datapic/11.jpg",
    						// 赞、踩数,标记情况
    						infonum: {
    							index: 1,  // 0-无操作,1-顶了,2-踩了
    							dingnum: 11,
    							cainum: 11,
    						},
    						commentnum: 10,
    						sharenum: 10
    					},
    					{
    						userpic: "../../static/demo/userpic/12.jpg",
    						username: "昵称",
    						isguanzhu: true,
    						title: "这是标题",
    						type: "video",
    						titlepic: "../../static/demo/datapic/11.jpg",
    						// 播放次数
    						playnum: "2w",
    						long: "2:47",
    						infonum: {
    							index: 2,
    							dingnum: 11,
    							cainum: 11,
    						},
    						commentnum: 10,
    						sharenum: 10
    					},
    				]
    			}
    		},
    		onLoad() {
    
    		},
    		methods: {
    
    		}
    	}
    </script>
    
    <style>
    	
    </style>
    
  • index-list.vue文件

    <template>
    	<view class="index-list">
    		<view class="index-list1 u-f-ac u-f-jsb">
    			<view class="u-f-ac">
    				<image :src="item.userpic" mode="widthFix" lazy-load></image>
    				{{item.username}}
    			</view>
    			<!-- v-if会导致一点布局异常,还是用v-show好一些 -->
    			<view class="u-f-ac" v-show="item.isguanzhu">
    				<view class="icon iconfont icon-zengjia"></view>关注
    			</view>
    		</view>
    		<view class="index-list2">{{item.title}}</view>
    		<view class="index-list3 u-f-ajc">
    			<!-- 图片 -->
    			<image :src="item.titlepic" mode="widthFix" lazy-load></image>
    			<!-- 视频 -->
    			<template v-if="item.type=='video'">
    				<view class="index-list-play icon iconfont icon-bofang"></view>
    				<view class="index-list-playinfo">
    					{{item.playnum}}次播放 {{item.long}}
    				</view>
    			</template>
    		</view>
    		<view class="index-list4 u-f-ac u-f-jsb">
    			<view class="u-f-ac">
    				<view class="u-f-ac" :class="{'active':(item.infonum.index==1)}">
    					<view class="icon iconfont icon-icon_xiaolian-mian u-f-ac"></view>
    					{{item.infonum.dingnum}}
    				</view>
    				<view class="u-f-ac" :class="{'active':(item.infonum.index==2)}">
    					<view class="icon iconfont icon-kulian u-f-ac"></view>
    					{{item.infonum.cainum}}
    				</view>
    			</view>
    			<view class="u-f-ac">
    				<view class="u-f-ac">
    					<view class="icon iconfont icon-pinglun1 u-f-ac"></view>
    					{{item.commentnum}}
    				</view>
    				<view class="u-f-ac">
    					<view class="icon iconfont icon-zhuanfa u-f-ac"></view>
    					{{item.sharenum}}
    				</view>
    			</view>
    		</view>
    	</view>
    </template>
    
    <script>
    	export default {
    		props: {
    			item: Object,
    			index: Number
    		}
    	}
    </script>
    
    <style scoped>
    	.index-list {
    		padding: 20upx;
    		border-bottom: 1upx solid #EEEEEE;
    	}
    	
    	.index-list1>view:first-child {
    		color: #999999;
    	}
    	
    	.index-list1>view:first-child image {
    		width: 90upx;
    		height: 90upx;
    		border-radius: 50%;
    		margin-right: 10upx;
    	}
    	
    	.index-list1>view:last-child {		
    		background-color: #F4F4F4;
    		border-radius: 5upx;
    		padding: 0 10upx;
    	}
    	
    	.index-list2 {
    		padding-top: 15upx;
    		font-size: 32upx;
    	}
    
    	.index-list3 {
    		position: relative;
    		padding-top: 15upx;
    	}
    
    	.index-list3>image {
    		width: 100%;
    		border-radius: 20upx;
    	}
    
    	.index-list4 {
    		padding: 15upx 0;
    	}
    	
    	.index-list4>view {
    		color: #999999;
    	}
    	
    	.index-list4>view>view:first-child, .index-list4>view>view>view {
    		margin-right: 10upx;
    	}
    	
    	.index-list-play {
    		position: absolute;
    		font-size: 140upx;
    		color: #FFFFFF;
    	}
    	
    	.index-list-playinfo {
    		position: absolute;
    		background-color: rgba(51, 51, 51, 0.62);
    		color: #FFFFFF;
    		bottom: 8upx;
    		right: 8upx;
    		border-radius: 40upx;
    		font-size: 22upx;
    		padding: 0 12upx;
    	}
    	
    	.index-list4 .active, .index-list4 .active > view{
    		color: #C5F61C;
    	}
    </style>
    
  • 其他文件

    和之前基本一样

  • 效果图

    和上一段展示的效果图一样

【028】滚动tab导航开发

操作步骤

根据uni-app-hello项目中的tabbar.vue文件,依次进行以下操作:

  1. uni-app-hello项目中的uni.css文件引入,方法可以参考【009】
  2. 将导航栏的文字内容以若干组{name: "??", id: "??"}的形式,写到data中的数组tabBars下。
  3. 在外层创建一个class="uni-tab-bar"view组件
  4. 在上述view组件下创建一个class="uni-swiper-tab" scroll-xscroll-view组件
  5. 在上述scroll-view组件下创建一个block组件,属性为v-for="(tab,index) in tabBars" :key="tab.id",列表渲染class="swiper-tab-list"view组件
  6. 每一个被列表渲染的view组件内容显示{{tab.name}}

其他注意点

有如下注意点:

  • 如果需要设置导航栏中当前选中项的样式,可以对被列表渲染的view组件设置:class="{'active': tabIndex==index}"
  • 如果需要设置导航栏中某一项被点击后成为当前选中项,可以先在data中设置tabIndex值(先设置为0代表初始选中第一个),然后在methods中设置一个处理函数tabtap(index),内容就是this.tabIndex=index;,最后放到被列表渲染的view组件上用@tap="tabtap(index)"绑定事件处理
  • 可以对.uni-swiper-tabscroll-view组件设置border-bottom属性,调整导航栏分隔线的样式
  • 可以对.swiper-tab-list的列表渲染view组件设置文字的样式
  • 可以对.uni-tab-bar下的.active的列表渲染view组件设置被选中后的文字样式
  • 如果要添加被选中后文字下方出现下划线的样式,可以在被列表渲染的view组件下再加一个class="swiper-tab-line"view组件,然后对.active下的.swiper-tab-line设置类似border-botommargin: 0 auto;border-radius等等样式

整体代码

以下仅展示index.vue文件的代码

<template>
	<view>
		<view class="uni-tab-bar">
			<scroll-view scroll-x class="uni-swiper-tab">
				<block v-for="(tab, index) in tabBars" :key="tab.id">
					<view class="swiper-tab-list" :class="{'active': tabIndex==index}" @tap="tabtap(index)">
						{{tab.name}}
						<view class="swiper-tab-line"></view>
					</view>
				</block>
			</scroll-view>
		</view>
		
		<!-- <block v-for="(item, index) in list" :key="index">
			<index-list :item="item" :index="index"></index-list>
		</block> -->
	</view>
</template>

<script>
	import indexList from "../../components/index/index-list.vue";
	export default {
		components: {
			indexList
		},
		data() {
			return {
				tabIndex: 0,
				tabBars: [
					{name: "关注", id: "guanzhu"},
					{name: "推荐", id: "tuijian"},
					{name: "体育", id: "tiyu"},
					{name: "热点", id: "redian"},
					{name: "财经", id: "caijing"},
					{name: "娱乐", id: "yule"}
				],
				list:[
					{
						// 用户头像
						userpic: "../../static/demo/userpic/12.jpg",
						// 用户名
						username: "昵称",
						// 关注情况
						isguanzhu: false,
						// 标题
						title: "这是标题",
						// 类型(img-图文,video-视频)
						type: "img",
						// 封面图
						titlepic: "../../static/demo/datapic/11.jpg",
						// 赞、踩数,标记情况
						infonum: {
							index: 1,  // 0-无操作,1-顶了,2-踩了
							dingnum: 11,
							cainum: 11,
						},
						commentnum: 10,
						sharenum: 10
					},
					{
						userpic: "../../static/demo/userpic/12.jpg",
						username: "昵称",
						isguanzhu: true,
						title: "这是标题",
						type: "video",
						titlepic: "../../static/demo/datapic/11.jpg",
						// 播放次数
						playnum: "2w",
						long: "2:47",
						infonum: {
							index: 2,
							dingnum: 11,
							cainum: 11,
						},
						commentnum: 10,
						sharenum: 10
					},
				]
			}
		},
		onLoad() {

		},
		methods: {
			tabtap(index){
				this.tabIndex=index;
			}
		}
	}
</script>

<style>
	.swiper-tab-list {
		color: #969696;
		font-weight: bold;
	}
	
	.uni-swiper-tab {
		border-bottom: 1upx solid #EEEEEE;
	}
	
	.uni-tab-bar .active {
		color: #343434;
	}
	
	/* 被选中才出现下划线 */
	.active .swiper-tab-line {
		border-bottom: 6upx solid #FEDE33;
		width: 70upx;
		margin: 0 auto;
		border-top: 6upx solid #FEDE33;
		border-radius: 20upx;
	}
</style>

效果图

4

【029】滚动tab导航开发(下)

swiper组件·官方文档 https://uniapp.dcloud.io/component/swiper

获取系统信息·官方文档 https://uniapp.dcloud.io/api/system/info

注意点

  1. 创建数组数据newslist,里面是6个list对象,分别与滚动栏上的6个种类对应
  2. 为了能够让能容横向滚动,和上一节类似地在class="uni-tab-bar"view组件中使用了class="swiper-box"swiper组件,在swiper组件下用swiper-item组件对数组newslist进行列表渲染,然后在swiper-item组件下用scroll-view组件创建滚动条,滚动条内将之前的内容block组件放入,大致就完成了
  3. 为了获取运行的系统的相关信息(如:系统的屏幕尺寸、显示尺寸……),可以在script下的onLoad()中用uni.getSystemInfo({ success:(res)=> { } })在函数体中用res.windowHeight获取显示高度(其他属性见上面给出的官方文档)
  4. 如果要调节自适应的大小,可以变量swiperheight存储大小对应的px值,然后给swiper组件设置相应尺寸的style(因为upx不支持在style中动态绑定)。swiperheight的计算应该放到onLoad()中的uni.getSystemInfo里,然后把结果传入这个变量值中。由于在uin.css文件中,.uni-tab-bar.swiper-boxheight被计算为calc(100% - 100upx),我们可以用类似的方法,计算出this.swiperheight=res.windowHeight-uni.upx2px(100);,这样的高度是差不多就是可以自适应的。
  5. swiper组件设置:current:"tabIndex";可以让横向滚动时,显示出对应的列表内容。
  6. swiper组件设置@change="tabChange",然后定义好函数tabChange,里面有默认参数event(调用时不用加上括号和参数列表),函数的内容定义this.tabIndex=e.detail.current;,这样可以设置横向滚动时,让导航栏也一起随之变化

详细代码

<template>
	<view>
		<view class="uni-tab-bar">
			<scroll-view scroll-x class="uni-swiper-tab">
				<block v-for="(tab, index) in tabBars" :key="tab.id">
					<view class="swiper-tab-list" :class="{'active': tabIndex==index}" @tap="tabtap(index)">
						{{tab.name}}
						<view class="swiper-tab-line"></view>
					</view>
				</block>
			</scroll-view>
		</view>
		
		<view class="uni-tab-bar">
			<swiper class="swiper-box" :style="{height: swiperheight+'px'}" :current="tabIndex" @change="tabChange">
				<swiper-item v-for="(items, index) in newslist" :key="index">
					<scroll-view scroll-y class="list">
						<block v-for="(item, index1) in items.list" :key="index1">
							<index-list :item="item" :index="index1"></index-list>
						</block>
					</scroll-view>
				</swiper-item>
			</swiper>
		</view>
	</view>
</template>

<script>
	import indexList from "../../components/index/index-list.vue";
	export default {
		components: {
			indexList
		},
		data() {
			return {
				swiperheight: 500,
				tabIndex: 0,
				tabBars: [
					{name: "关注", id: "guanzhu"},
					{name: "推荐", id: "tuijian"},
					{name: "体育", id: "tiyu"},
					{name: "热点", id: "redian"},
					{name: "财经", id: "caijing"},
					{name: "娱乐", id: "yule"}
				],
				newslist: [
					{
						list:[
							{
								// 用户头像
								userpic: "../../static/demo/userpic/12.jpg",
								// 用户名
								username: "昵称",
								// 关注情况
								isguanzhu: false,
								// 标题
								title: "这是标题",
								// 类型(img-图文,video-视频)
								type: "img",
								// 封面图
								titlepic: "../../static/demo/datapic/11.jpg",
								// 赞、踩数,标记情况
								infonum: {
									index: 1,  // 0-无操作,1-顶了,2-踩了
									dingnum: 11,
									cainum: 11,
								},
								commentnum: 10,
								sharenum: 10
							},
							{
								userpic: "../../static/demo/userpic/12.jpg",
								username: "昵称",
								isguanzhu: true,
								title: "这是标题",
								type: "video",
								titlepic: "../../static/demo/datapic/11.jpg",
								// 播放次数
								playnum: "2w",
								long: "2:47",
								infonum: {
									index: 2,
									dingnum: 11,
									cainum: 11,
								},
								commentnum: 10,
								sharenum: 10
							},
						]
					},
					{
						list:[
							{
								// 用户头像
								userpic: "../../static/demo/userpic/12.jpg",
								// 用户名
								username: "昵称",
								// 关注情况
								isguanzhu: false,
								// 标题
								title: "这是标题",
								// 类型(img-图文,video-视频)
								type: "img",
								// 封面图
								titlepic: "../../static/demo/datapic/11.jpg",
								// 赞、踩数,标记情况
								infonum: {
									index: 1,  // 0-无操作,1-顶了,2-踩了
									dingnum: 11,
									cainum: 11,
								},
								commentnum: 10,
								sharenum: 10
							},
							{
								userpic: "../../static/demo/userpic/12.jpg",
								username: "昵称",
								isguanzhu: true,
								title: "这是标题",
								type: "video",
								titlepic: "../../static/demo/datapic/11.jpg",
								// 播放次数
								playnum: "2w",
								long: "2:47",
								infonum: {
									index: 2,
									dingnum: 11,
									cainum: 11,
								},
								commentnum: 10,
								sharenum: 10
							},
							{
								// 用户头像
								userpic: "../../static/demo/userpic/12.jpg",
								// 用户名
								username: "昵称",
								// 关注情况
								isguanzhu: false,
								// 标题
								title: "这是标题",
								// 类型(img-图文,video-视频)
								type: "img",
								// 封面图
								titlepic: "../../static/demo/datapic/11.jpg",
								// 赞、踩数,标记情况
								infonum: {
									index: 1,  // 0-无操作,1-顶了,2-踩了
									dingnum: 11,
									cainum: 11,
								},
								commentnum: 10,
								sharenum: 10
							},
							{
								userpic: "../../static/demo/userpic/12.jpg",
								username: "昵称",
								isguanzhu: true,
								title: "这是标题",
								type: "video",
								titlepic: "../../static/demo/datapic/11.jpg",
								// 播放次数
								playnum: "2w",
								long: "2:47",
								infonum: {
									index: 2,
									dingnum: 11,
									cainum: 11,
								},
								commentnum: 10,
								sharenum: 10
							},
						]
					},
					{
						list:[
						
							{
								// 用户头像
								userpic: "../../static/demo/userpic/12.jpg",
								// 用户名
								username: "昵称",
								// 关注情况
								isguanzhu: false,
								// 标题
								title: "这是标题",
								// 类型(img-图文,video-视频)
								type: "img",
								// 封面图
								titlepic: "../../static/demo/datapic/11.jpg",
								// 赞、踩数,标记情况
								infonum: {
									index: 1,  // 0-无操作,1-顶了,2-踩了
									dingnum: 11,
									cainum: 11,
								},
								commentnum: 10,
								sharenum: 10
							},
							{
								userpic: "../../static/demo/userpic/12.jpg",
								username: "昵称",
								isguanzhu: true,
								title: "这是标题",
								type: "video",
								titlepic: "../../static/demo/datapic/11.jpg",
								// 播放次数
								playnum: "2w",
								long: "2:47",
								infonum: {
									index: 2,
									dingnum: 11,
									cainum: 11,
								},
								commentnum: 10,
								sharenum: 10
							},
						]
					},
					{
						list:[]
					},
					{
						list:[]
					},
					{
						list:[]
					}
				]
			}
		},
		onLoad() {
			uni.getSystemInfo({
			    success:(res)=> {
					let height = res.windowHeight-uni.upx2px(100);
					this.swiperheight=height;
			    }
			});
		},
		methods: {
			// tabBar点击事件
			tabtap(index) {
				this.tabIndex=index;
			},
			// 滑动联动切换导航栏
			tabChange(e) {
				// console.log(JSON.stringify(e.detail));
				this.tabIndex=e.detail.current;
			}
		}
	}
</script>

<style>
	.swiper-tab-list {
		color: #969696;
		font-weight: bold;
	}
	
	.uni-swiper-tab {
		border-bottom: 1upx solid #EEEEEE;
	}
	
	.uni-tab-bar .active {
		color: #343434;
	}
	
	/* 被选中才出现下划线 */
	.active .swiper-tab-line {
		border-bottom: 6upx solid #FEDE33;
		width: 70upx;
		margin: 0 auto;
		border-top: 6upx solid #FEDE33;
		border-radius: 20upx;
	}
</style>

【030】封装滚动tab导航组件

步骤总结

步骤如下:

  1. 首先还是和以前一样,在components文件夹下的index文件夹下,新建swiper-tab-head.vue文件,将导航栏部分代码剪切过来,将样式部分代码剪切过来,将点击处理的方法剪切过来,在swiper-tab-head.vue文件props中定义好要使用到的变量,在index.vue文件中用自定义的swiper-tab-head组件将导航栏引入,然后以:tabBars="tabBars" :tabIndex="tabIndex"的方式传入相关变量
  2. 但是仅仅是上面这样还不够,因为点击事件的方法调用在子组件里,没有修改到父组件里面的变量值,因此要在子组件里将点击事件的处理改成this.$emit('tabtap', index);,意思是监听一个自定义的名为'tabtap'的事件、然后把index传过去,然后在父组件里通过设置属性@tabtap="tabtap",意思是当触发了tabtap事件后、将子组件中通过tabtap事件传入的index作为参数、传入父组件的函数tabtap中、进行事件处理,从而达到父子组件通信的效果。

详细代码

  • index.vue文件

    <template>
    	<view>
    		<swiper-tab-head :tabBars="tabBars" :tabIndex="tabIndex" @tabtap="tabtap"></swiper-tab-head>
    		
    		<view class="uni-tab-bar">
    			<swiper class="swiper-box" :style="{height: swiperheight+'px'}" :current="tabIndex" @change="tabChange">
    				<swiper-item v-for="(items, index) in newslist" :key="index">
    					<scroll-view scroll-y class="list">
    						<block v-for="(item, index1) in items.list" :key="index1">
    							<index-list :item="item" :index="index1"></index-list>
    						</block>
    					</scroll-view>
    				</swiper-item>
    			</swiper>
    		</view>
    	</view>
    </template>
    
    <script>
    	import indexList from "../../components/index/index-list.vue";
    	import swiperTabHead from "../../components/index/swiper-tab-head.vue";
    	export default {
    		// 注册组件
    		components: {
    			indexList,
    			swiperTabHead
    		},
    		data() {
    			return {
    				swiperheight: 500,
    				tabIndex: 0,
    				tabBars: [
    					{name: "关注", id: "guanzhu"},
    					{name: "推荐", id: "tuijian"},
    					{name: "体育", id: "tiyu"},
    					{name: "热点", id: "redian"},
    					{name: "财经", id: "caijing"},
    					{name: "娱乐", id: "yule"}
    				],
    				newslist: [
    					{
    						list:[
    							{
    								// 用户头像
    								userpic: "../../static/demo/userpic/12.jpg",
    								// 用户名
    								username: "昵称",
    								// 关注情况
    								isguanzhu: false,
    								// 标题
    								title: "这是标题",
    								// 类型(img-图文,video-视频)
    								type: "img",
    								// 封面图
    								titlepic: "../../static/demo/datapic/11.jpg",
    								// 赞、踩数,标记情况
    								infonum: {
    									index: 1,  // 0-无操作,1-顶了,2-踩了
    									dingnum: 11,
    									cainum: 11,
    								},
    								commentnum: 10,
    								sharenum: 10
    							},
    							{
    								userpic: "../../static/demo/userpic/12.jpg",
    								username: "昵称",
    								isguanzhu: true,
    								title: "这是标题",
    								type: "video",
    								titlepic: "../../static/demo/datapic/11.jpg",
    								// 播放次数
    								playnum: "2w",
    								long: "2:47",
    								infonum: {
    									index: 2,
    									dingnum: 11,
    									cainum: 11,
    								},
    								commentnum: 10,
    								sharenum: 10
    							},
    						]
    					},
    					{
    						list:[
    							{
    								// 用户头像
    								userpic: "../../static/demo/userpic/12.jpg",
    								// 用户名
    								username: "昵称",
    								// 关注情况
    								isguanzhu: false,
    								// 标题
    								title: "这是标题",
    								// 类型(img-图文,video-视频)
    								type: "img",
    								// 封面图
    								titlepic: "../../static/demo/datapic/11.jpg",
    								// 赞、踩数,标记情况
    								infonum: {
    									index: 1,  // 0-无操作,1-顶了,2-踩了
    									dingnum: 11,
    									cainum: 11,
    								},
    								commentnum: 10,
    								sharenum: 10
    							},
    							{
    								userpic: "../../static/demo/userpic/12.jpg",
    								username: "昵称",
    								isguanzhu: true,
    								title: "这是标题",
    								type: "video",
    								titlepic: "../../static/demo/datapic/11.jpg",
    								// 播放次数
    								playnum: "2w",
    								long: "2:47",
    								infonum: {
    									index: 2,
    									dingnum: 11,
    									cainum: 11,
    								},
    								commentnum: 10,
    								sharenum: 10
    							},
    							{
    								// 用户头像
    								userpic: "../../static/demo/userpic/12.jpg",
    								// 用户名
    								username: "昵称",
    								// 关注情况
    								isguanzhu: false,
    								// 标题
    								title: "这是标题",
    								// 类型(img-图文,video-视频)
    								type: "img",
    								// 封面图
    								titlepic: "../../static/demo/datapic/11.jpg",
    								// 赞、踩数,标记情况
    								infonum: {
    									index: 1,  // 0-无操作,1-顶了,2-踩了
    									dingnum: 11,
    									cainum: 11,
    								},
    								commentnum: 10,
    								sharenum: 10
    							},
    							{
    								userpic: "../../static/demo/userpic/12.jpg",
    								username: "昵称",
    								isguanzhu: true,
    								title: "这是标题",
    								type: "video",
    								titlepic: "../../static/demo/datapic/11.jpg",
    								// 播放次数
    								playnum: "2w",
    								long: "2:47",
    								infonum: {
    									index: 2,
    									dingnum: 11,
    									cainum: 11,
    								},
    								commentnum: 10,
    								sharenum: 10
    							},
    						]
    					},
    					{
    						list:[
    						
    							{
    								// 用户头像
    								userpic: "../../static/demo/userpic/12.jpg",
    								// 用户名
    								username: "昵称",
    								// 关注情况
    								isguanzhu: false,
    								// 标题
    								title: "这是标题",
    								// 类型(img-图文,video-视频)
    								type: "img",
    								// 封面图
    								titlepic: "../../static/demo/datapic/11.jpg",
    								// 赞、踩数,标记情况
    								infonum: {
    									index: 1,  // 0-无操作,1-顶了,2-踩了
    									dingnum: 11,
    									cainum: 11,
    								},
    								commentnum: 10,
    								sharenum: 10
    							},
    							{
    								userpic: "../../static/demo/userpic/12.jpg",
    								username: "昵称",
    								isguanzhu: true,
    								title: "这是标题",
    								type: "video",
    								titlepic: "../../static/demo/datapic/11.jpg",
    								// 播放次数
    								playnum: "2w",
    								long: "2:47",
    								infonum: {
    									index: 2,
    									dingnum: 11,
    									cainum: 11,
    								},
    								commentnum: 10,
    								sharenum: 10
    							},
    						]
    					},
    					{
    						list:[]
    					},
    					{
    						list:[]
    					},
    					{
    						list:[]
    					}
    				]
    			}
    		},
    		onLoad() {
    			uni.getSystemInfo({
    			    success:(res)=> {
    					let height = res.windowHeight-uni.upx2px(100);
    					this.swiperheight=height;
    			    }
    			});
    		},
    		methods: {
    			// tabBar点击事件
    			tabtap(index) {
    				this.tabIndex=index;
    			},
    			// 滑动联动切换导航栏
    			tabChange(e) {
    				// console.log(JSON.stringify(e.detail));
    				this.tabIndex=e.detail.current;
    			}
    		}
    	}
    </script>
    
    <style>
    	
    </style>
    
  • swiper-tab-head文件

    <template>
    	<view class="uni-tab-bar">
    		<scroll-view scroll-x class="uni-swiper-tab">
    			<block v-for="(tab, index) in tabBars" :key="tab.id">
    				<view class="swiper-tab-list" :class="{'active': tabIndex==index}" @tap="tabtap(index)">
    					{{tab.name}}
    					<view class="swiper-tab-line"></view>
    				</view>
    			</block>
    		</scroll-view>
    	</view>
    </template>
    
    <script>
    	export default {
    		props: {
    			tabBars: Array,
    			tabIndex: Number
    		},
    		methods: {
    			// tabBar点击事件
    			tabtap(index) {
    				this.$emit('tabtap', index);
    			},
    		}
    	}
    </script>
    
    <style>
    	.swiper-tab-list {
    		color: #969696;
    		font-weight: bold;
    	}
    	
    	.uni-swiper-tab {
    		border-bottom: 1upx solid #EEEEEE;
    	}
    	
    	.uni-tab-bar .active {
    		color: #343434;
    	}
    	
    	/* 被选中才出现下划线 */
    	.active .swiper-tab-line {
    		border-bottom: 6upx solid #FEDE33;
    		width: 70upx;
    		margin: 0 auto;
    		border-top: 6upx solid #FEDE33;
    		border-radius: 20upx;
    	}
    </style>
    
  • 其余文件

    其余文件和之前的项目文件大致相同

【031】上拉加载组件开发

流程简述

  1. swiper组件下的swiper-item组件下的scroll-view组件下增加一个view组件,用于上拉加载
  2. swiper组件下的swiper-item组件下的scroll-view组件的scrolltolower事件绑定一个自定义函数loadmore(index)
  3. loadmore函数中,先根据newslist[index].loadtext的内容判断加载状态,如果不是待加载状态,就不进行加载
  4. 加载前将状态调整至加载中,加载到的数据追加到newslist[index].list中,然后再把加载状态调整至待加载
  5. 没有更多数据的状态以后再讨论

核心代码

<template>
	<view>
		<!-- ...... -->		
		<view class="uni-tab-bar">
			<swiper class="swiper-box" :style="{height: swiperheight+'px'}" :current="tabIndex" @change="tabChange">
				<swiper-item v-for="(items, index) in newslist" :key="index">
					<scroll-view scroll-y class="list" @scrolltolower="loadmore(index)">
						<!-- 图文列表 -->
						<block v-for="(item, index1) in items.list" :key="index1">
							<index-list :item="item" :index="index1"></index-list>
						</block>
						<!-- 上拉加载 -->
						<view class="load-more">{{items.loadtext}}</view>
					</scroll-view>
				</swiper-item>
			</swiper>
		</view>
	</view>
</template>

<script>
	import indexList from "../../components/index/index-list.vue";
	import swiperTabHead from "../../components/index/swiper-tab-head.vue";
	export default {
		// 注册组件
		components: {
			indexList,
			swiperTabHead
		},
		data() {
			return {
				//......
				newslist: [
					{
						loadtext: "上拉加载更多",
						list:[
							{
								//......
							},
							{
								//......
							},
						]
					},
					{
						loadtext: "上拉加载更多",
						list:[
							{
								//......
							},
							{
								//......
							},
							{
								//......
							},
							{
								//......
							},
						]
					},
					{
						loadtext: "上拉加载更多",
						list:[
							{
								//......
							},
							{
								//......
							},
						]
					},
					{
						loadtext: "上拉加载更多",
						list:[]
					},
					{
						loadtext: "上拉加载更多",
						list:[]
					},
					{
						loadtext: "上拉加载更多",
						list:[]
					}
				]
			}
		},
		onLoad() {
			//......
		},
		methods: {
			//......
			// 上拉加载状态
			loadmore(index) {
				// 三种状态
				// this.newslist[index].loadtext='上拉加载更多';
				// this.newslist[index].loadtext='加载中';
				// this.newslist[index].loadtext='没有更多数据了';
				
				// 正在加载中或者没有更多数据的时候不会向服务器发送请求
				if (this.newslist[index].loadtext!=='上拉加载更多') {
					return;
				}
				// 模拟请求数据
				this.newslist[index].loadtext='加载中';  // 修改状态
				setTimeout(()=> {
					// 获取完成
					let obj = {
						// 用户头像
						userpic: "../../static/demo/userpic/12.jpg",
						// 用户名
						username: "昵称",
						// 关注情况
						isguanzhu: false,
						// 标题
						title: "这是标题",
						// 类型(img-图文,video-视频)
						type: "img",
						// 封面图
						titlepic: "../../static/demo/datapic/11.jpg",
						// 赞、踩数,标记情况
						infonum: {
							index: 1,  // 0-无操作,1-顶了,2-踩了
							dingnum: 11,
							cainum: 11,
						},
						commentnum: 10,
						sharenum: 10
					};
					this.newslist[index].list.push(obj);  // 加入数组
					this.newslist[index].loadtext='上拉加载更多';  // 修改状态
				}, 1000);
				
			},
			//......
	}
</script>

<style>
	.load-more {
		text-align: center;
		color: #AAAAAA;
		padding: 15upx 0;
	}
</style>

效果图

5

【032】封装上拉加载组件

流程简述

之前其实也描述过了封装的一般流程 点这里

这里再来描述一下:

  1. components文件夹下新建common文件夹代表这个组件是多页面通用的
  2. common文件夹下新建一个页面(这里就是load-more.vue
  3. 将要封装的部分(这里就是<view class="load-more">{{items.loadtext}}</view>),剪切粘贴到刚才新建的页面中
  4. 将对应的样式(这里就是.load-more的样式)剪切粘贴到刚才新建的页面中
  5. 将刚刚剪切的组件中要用到的数据在props中注册,然后再把组件中使用的变量换成相应的变量名
  6. 在原来的页面中通过import 小驼峰名 from ".vue文件路径"
  7. 在原来的页面中通过commponents注册相应的组件
  8. 在原来的页面中原来的组件的位置,使用自定义的组件,如果要传参数可以用:变量名="具体变量"的形式传入

核心代码

  • index.vue文件

    <template>
    	<view>
    		<!-- ...... -->
    		
    		<view class="uni-tab-bar">
    			<!-- ...... -->
    				<!-- ...... -->
    					<!-- ...... -->
    						<!-- 上拉加载 -->
    						<load-more :loadtext="items.loadtext"></load-more>
    					<!-- ...... -->
    				<!-- ...... -->
    			<!-- ...... -->
    		</view>
    	</view>
    </template>
    
    <script>
    	//......
    	import loadMore from "../../components/common/load-more.vue";
    	export default {
    		// 注册组件
    		components: {
    			//......
    			loadMore
    		},
    		data() {
    			//......
    		},
    		onLoad() {
    			//......
    		},
    		methods: {
    			// 上拉加载状态
    			loadmore(index) {
    				//......
    			},
    </script>
    
    <style>
    	
    </style>
    
  • load-more.vue文件

    <template>
    	<view class="load-more">{{loadtext}}</view>
    </template>
    
    <script>
    	export default {
    		props: {
    			loadtext: String
    		}
    	}
    </script>
    
    <style scoped>
    	.load-more {
    		text-align: center;
    		color: #AAAAAA;
    		padding: 15upx 0;
    	}
    </style>
    

【033】优化图文列表组件

具体优化

  1. 点击【关注】之后将不再出现【关注】按钮(个人感觉这个可以优化为已关注,方便快速取关)
  2. 点击【顶】、【踩】之后,相应的数据会进行修改,相关的状态会进行调整
  3. 点击【文章标题】、【文章图片】之后,会跳转到相应的详情页(这里先写一个接口,只打印一下提示,以后再做具体实现)

组件代码

(index-list组件)

<template>
	<view class="index-list animated rollIn">
		<view class="index-list1 u-f-ac u-f-jsb">
			<view class="u-f-ac">
				<image :src="item.userpic" mode="widthFix" lazy-load></image>
				{{item.username}}
			</view>
			<!-- v-if会导致一点布局异常,还是用v-show好一些 -->
			<view class="u-f-ac" v-show="!item.isguanzhu" @tap="guanzhu">
				<view class="icon iconfont icon-zengjia"></view>关注
			</view>
		</view>
		<view class="index-list2" @tap="opendetail">{{item.title}}</view>
		<view class="index-list3 u-f-ajc" @tap="opendetail">
			<!-- 图片 -->
			<image :src="item.titlepic" mode="widthFix" lazy-load></image>
			<!-- 视频 -->
			<template v-if="item.type=='video'">
				<view class="index-list-play icon iconfont icon-bofang"></view>
				<view class="index-list-playinfo">
					{{item.playnum}}次播放 {{item.long}}
				</view>
			</template>
		</view>
		<view class="index-list4 u-f-ac u-f-jsb">
			<view class="u-f-ac">
				<view class="u-f-ac" :class="{'active':(item.infonum.index==1)}" @tap="caozuo('ding')">
					<view class="icon iconfont icon-icon_xiaolian-mian u-f-ac"></view>
					{{item.infonum.dingnum}}
				</view>
				<view class="u-f-ac" :class="{'active':(item.infonum.index==2)}" @tap="caozuo('cai')">
					<view class="icon iconfont icon-kulian u-f-ac"></view>
					{{item.infonum.cainum}}
				</view>
			</view>
			<view class="u-f-ac">
				<view class="u-f-ac">
					<view class="icon iconfont icon-pinglun1 u-f-ac"></view>
					{{item.commentnum}}
				</view>
				<view class="u-f-ac">
					<view class="icon iconfont icon-zhuanfa u-f-ac"></view>
					{{item.sharenum}}
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	export default {
		props: {
			item: Object,
			index: Number
		},
		methods: {
			// 关注
			guanzhu() {
				this.item.isguanzhu = true;
				uni.showToast({
					title: "关注成功"
				});
			},
			// 顶踩
			caozuo(type) {
				switch(type) {
					case 'ding':
						if (this.item.infonum.index === 1) {  // 已经顶了(取消顶)
							--this.item.infonum.dingnum;
							this.item.infonum.index = 0;
						} else if (this.item.infonum.index === 2) {  // 已经踩了(取消踩,顶)
							++this.item.infonum.dingnum;
							--this.item.infonum.cainum;
							this.item.infonum.index = 1;
						} else {  // 未操作(顶)
							++this.item.infonum.dingnum;
							this.item.infonum.index = 1;
						}
						break;
					case 'cai':
						if (this.item.infonum.index === 2) {  // 已经踩了(取消踩)
							--this.item.infonum.cainum;
							this.item.infonum.index = 0;
						} else if (this.item.infonum.index === 1) {  // 已经顶了(取消顶,踩)
							++this.item.infonum.cainum;
							--this.item.infonum.dingnum;
							this.item.infonum.index = 2;
						} else {  // 未操作(踩)
							++this.item.infonum.cainum;
							this.item.infonum.index = 2;
						}
						break;
				}
			},
			// 进入详情页
			opendetail() {
				// 暂时留一个接口,先不做具体实现
				console.log("进入详情页");
			}
		},
	}
</script>

<style scoped>
	.index-list {
		padding: 20upx;
		border-bottom: 1upx solid #EEEEEE;
	}
	
	.index-list1>view:first-child {
		color: #999999;
	}
	
	.index-list1>view:first-child image {
		width: 90upx;
		height: 90upx;
		border-radius: 50%;
		margin-right: 10upx;
	}
	
	.index-list1>view:last-child {		
		background-color: #F4F4F4;
		border-radius: 5upx;
		padding: 0 10upx;
	}
	
	.index-list2 {
		padding-top: 15upx;
		font-size: 32upx;
	}

	.index-list3 {
		position: relative;
		padding-top: 15upx;
	}

	.index-list3>image {
		width: 100%;
		border-radius: 20upx;
	}

	.index-list4 {
		padding: 15upx 0;
	}
	
	.index-list4>view {
		color: #999999;
	}
	
	.index-list4>view>view:first-child, .index-list4>view>view>view {
		margin-right: 10upx;
	}
	
	.index-list-play {
		position: absolute;
		font-size: 140upx;
		color: #FFFFFF;
	}
	
	.index-list-playinfo {
		position: absolute;
		background-color: rgba(51, 51, 51, 0.62);
		color: #FFFFFF;
		bottom: 8upx;
		right: 8upx;
		border-radius: 40upx;
		font-size: 22upx;
		padding: 0 12upx;
	}
	
	.index-list4 .active, .index-list4 .active > view{
		color: #C5F61C;
	}
</style>

【034】封装无数据默认组件

具体优化

对于无数据的页面,优化了展示的效果,不再是几乎一片空白,并将组件进行了封装。

核心代码

  • index.vue文件

    <template>
    	<view>
    		<swiper-tab-head :tabBars="tabBars" :tabIndex="tabIndex" @tabtap="tabtap"></swiper-tab-head>
    		
    		<view class="uni-tab-bar">
    			<!-- ...... -->
    				<!-- ...... -->
    					<!-- ...... -->
    						<template v-if="items.list.length > 0">
    							<!-- 图文列表 -->
    							<block v-for="(item, index1) in items.list" :key="index1">
    								<index-list :item="item" :index="index1"></index-list>
    							</block>
    							<!-- 上拉加载 -->
    							<load-more :loadtext="items.loadtext"></load-more>
    						</template>
    						<template v-else>
    							<!-- 无内容默认 -->
    							<nothing></nothing>
    						</template>
    					<!-- ...... -->
    				<!-- ...... -->
    			<!-- ...... -->
    		</view>
    	</view>
    </template>
    
    <script>
    	//......
    	import nothing from "../../components/common/nothing.vue";
    	export default {
    		// 注册组件
    		components: {
    			//......
    			nothing
    		},
    		data() {
    			return {
    			//......
    			}
    		},
    		onLoad() {
    			//......
    		},
    		methods: {
    			//......
    		}
    	}
    </script>
    
    <style>
    	
    </style>
    
    
  • nothing.vue文件

    <template>
    	<view class="nothing u-f-ajc animated fadeIn">
    		<image src="../../static/common/nothing.png" mode="widthFix"></image>
    	</view>
    </template>
    
    <script>
    </script>
    
    <style>
    	.nothing {
    		position: absolute;
    		left: 0;
    		right: 0;
    		top: 0;
    		bottom: 0;
    	}
    	
    	.nothing > image {
    		width: 50%;
    	}
    </style>
    

效果图

6
发布了49 篇原创文章 · 获赞 9 · 访问量 3121

猜你喜欢

转载自blog.csdn.net/qq_44220418/article/details/105313884