本节主要讲解利用 swiper 组件滚动展示信息,利用 flexbox 瀑布流布局实现浏览卡片式产品。

# 页面主体布局

img

当前页面的布局沿用在上一节中提到的布局。如上图所示分为两部分:头部标题栏 + 滚动浏览区域。头部标题栏 fixed 固定,内容区用 scroll-view 组件撑开整个页面。

相关代码:

<view>
	<!-- 头部 -->
	<uni-nav-bar fixed :status-bar="true">
		头部内容
	</uni-nav-bar>
	<!-- 滚动区域 -->
	<view class="page-content">
		<mescroll-uni ref="mescroll" :fixed="false" :down="downOption" :up="upOption" @down="downCallback" @up="upCallback">
			滚动区域内容
		</mescroll-uni>
	</view>
</view>
.page-content {
	position: fixed;
	top: 64px;
	left: 0;
	right: 0;
	bottom: 0px;
	/* #ifdef H5 */
	top:44px;  // h5 无状态栏
	/* #endif */
}

在样式方面需要注意 .page-content 向下偏移一个头部标题栏的高度才可实现内容区铺满。由于不同端屏幕展示起点不同,需要做样式的调整,先看一下头部标题栏组成:

头部标题栏固定高度(64px) = 状态栏/电池栏(20px) + 标题栏(44px)

H5 的渲染起点并没有状态栏,样式需要条件编译,H5 中页面实际的标题高度展示为 44px ,因此 page-content 内容区需向下偏移 44px ,而不是 64px。

image-20210215154852615

H5 未进行条件编译的状态

/* #ifdef H5 */
top:44px;  // h5 无状态栏
/* #endif */

添加条件编译后,page-content 内容区偏移程度与其他端保持一致(页面正常)。里面的长列表用 mescroll-uni 上拉加载组件解决浏览交互。

# swiper 组件展示滚动信息

image-20210215154913770

关于这样的信息滚动展示的功能,可能会一大波小伙伴感觉有点吃力。其实分析这一块滚动的特性,可以联想到使用 swiper 组件便能轻松实现这样的一个小功能。

相关代码:

<!-- 日期信息bar -->
<view class="date-bar flex-box">
	<view class="date-bar-left">
		云村热评墙 <text class="iconfont">&#xe605;</text>
		<swiper class="date-bar-swiper" :autoplay="true" :duration="500" :circular="true" :vertical="true">
			<swiper-item v-for="(item, index) in dateMsg.msgList" :key="index">
				{{item.name}}
			</swiper-item>
		</swiper>
	</view>
	<view>
		<view>{{dateMsg.curDate[1]}}.</view>
		<view class="date-bar-num">{{dateMsg.curDate[2]}}</view>
	</view>
</view>
dateMsg: {
	curDate: String(new Date()).split(' '),
	msgList: [
		{ name: '他是我见过最年少有为的人', id: ''},
		{ name: '因为一个人而失眠,这真的好吗', id: ''},
		{ name: '花开花落,没有悲愁怎么是少年?', id: ''},
	],
},
.date-bar-swiper{
	width:430rpx;
	height:40rpx;
	line-height: 40rpx;
	color:#d0d2d3;
	font-size: 24rpx;
}

这个功能对 swiper 属性进行设置 :autoplay="true" :duration="500" :circular="true" :vertical="true",自动滚动,滑动动画时长500毫秒,采用衔接滑动,滑动方向为纵向。即可实现滚动信息展示。

# flexbox 瀑布流布局实现浏览卡片式产品

瀑布流又称瀑布流式布局,是一种比较流行的页面布局方式。与传统的分页显示不同,视觉表现为参差不齐的多栏布局。即多行等宽元素排列,后面的元素依次添加到其后,等宽不等高,根据图片原比例缩放直至宽度达到我们的要求,依次按照规则放入指定位置。

瀑布流式布局的优点:

  1. 有效的降低了界面复杂度,节省了空间,不再需要臃肿复杂的页码导航链接或按钮;
  2. 通过向上滑动浏览,对于触屏设备非常友好,基本上所有移动设备上的信息展示都是采用这种方式,特别是购物网站;
  3. 滚动预加载,用户浏览时的观赏和思维不容易被打断,更高的参与度,留存更容易。

img

可以看上图的展示的瀑布流效果,flexbox 布局可以轻松实现,而不用使用 js 计算排版高度再插入内容等复杂的操作。我们可以把上图以 html 结构设计成:

<!-- flex 盒 -->
<view class="list-content">
	<!-- 左边/第一列 -->
	<view class="video-list">
		<view class="video-item" v-for="(item, index) in showList.colList1"></view>
	</view>
	<!-- 右边/第二列 -->
	<view class="video-list">
		<view class="video-item" v-for="(item, index) in showList.colList2"></view>
	</view>
</view>
.list-content{
 	display: flex;
	flex-direction: row; // 水平方向排版
}
.video-list{
 	display: flex;
	flex-direction: column; // 垂直方向排版
}

相当于 list-content 包含多列从左至右显示内容(当前为两列),单独的一列以从上到下进行排列显示。单独每一列的具体数据:

let i = 0,
	list1 = [], // 左边/第一列
    list2 = [], // 右边/第二列

    // 如果有第三列
    // list3 = [], // 第三列

// allDate 为后台获取的所有数据
while (i < allDate.length) {
    list1.push(allDate[i++]);
    if (i < allDate.length) {
        list2.push(allDate[i++]);
    }

	// 如果有第三列
    if (i < allDate.length) {
        list3.push(allDate[i++]);
    }
}
return {
    list1, // 第一列
    list2, // 第二列

    // 如果有第三列
    data3 // 第三列
};

如果使用三列的方式:

根据上面代码可以改造为多列布局,这些讲解的瀑布流布局方案,可以说是竖向瀑布流,利用 flexbox 的布局再结合下拉更新上拉加载的功能,即可实现可简单实现瀑布流布局的浏览方式。

# 底部导航栏红点与角标的设置

image-20210215154950380

作为一款应用,应用内的信息提示一般会展现在底部导航栏上,Uniapp 支持设置 TabBar 上的元素以及角标等信息,统一了 h5,小程序,app 的设置角标 API。

img

uni.setTabBarBadge 这个 API 在 非tabbar 页面上调用会失效,因此我们需要在 common/js/util.js 封装一个方法由几个 tabbar 页面上调用。结合 Vuex 的状态管理全局管理角标信息。

相关代码:

// store/index.js
const store = new Vuex.Store({
	state: {
		message: {}  // 角标信息
	},
	mutations: {
		storeMessage (state, payload) {   // 角标信息
			state.message = {...state.message, ...payload}
		}
	}
})

export default store

封装公用方法,先读取存储的信息,再根据信息设置 tabbar 上的角标与文本。

// common/js/util.js
// 设置角标
setTabBarBadge (page) {
	// 设置 store 红点信息
	const accountMsg = store.state.message.account
	const newMsg = store.state.message.newMsg || []

	newMsg[page] = 0

	const TempMsg = {
		account: page == 4 ? 0 : accountMsg,
		newMsg
	}
	store.commit('storeMessage', TempMsg)

	// 获取 store 红点信息
	const accountMsgNew = store.state.message.account
	const newMsgNew = store.state.message.newMsg || []

	if (accountMsgNew > 0) { // 如果有账号信息
		setTimeout(() => {
			// uni.setTabBarBadge 这个 API 在非tabbar页面上调用会失效。
			uni.setTabBarBadge({   // 设置角标
				index: 4,
				text: String(accountMsgNew)
			})
		})
	} else {
		setTimeout(() => {
			// 删除角标
			uni.removeTabBarBadge({
			   index: 0,
			})
		})
	}

	newMsgNew.forEach((item, index) => {  // 设置红点
		if (item > 0) {
			uni.showTabBarRedDot({
				index
			})
		} else {
			uni.hideTabBarRedDot({
				index
			})
		}
	})
}

在页面上调用,0 代表 tabbar 页面索引页面

onLoad() {
	// 公共设置图标
	this.$pubFuc.setTabBarBadge(0)
}

在进入应用的时候可以看见红点与文本的信息,并在进入当前 tabbar 页面的时候清除红点、角标,表示用户已查看提示的信息。

# 小结

  1. 滑动的展示都可以考虑使用 swiper 组件完成,利用好组件的功能可以达到事半功倍的的效果;
  2. flexbox 很容易实现瀑布流,做瀑布流需要考虑几方面的因素:图片大小,图片质量,加载速度,如果这些不能同时满足,会大大降低用户体验;
  3. 角标信息的设置需要在 tabbar 页面上调用。
  4. 本章代码 uni-course-实战开发云村页 (opens new window)。
阅读全文