微信小程序直播间实现下拉刷新
先上效果:
1.下拉距离一定时出现动画,保持下拉直到距离足够大时触发函数加载直播间列表,而且在足够大距离时会有振动反馈,增强用户体验
2.下拉小距离出现动画,此时释放不会触发函数加载直播间
3.左滑右滑触发函数加载直播间列表
4.点击tab对应分栏触发函数加载直播间列表
感谢两位博主对这篇文章代码的贡献
1.动画部分引用:《微信小程序中使用Animation实现简约Loading效果》链接在此
2.《微信小程序 监听手势滑动切换页面》
下面是具体实现方法:链接在此
1.index.wxml
<view class='main'>
<view class='tab'>
<view bindtap='tabFun' data-index="{{1}}">
<text class='{{tabIndex==1?"active":""}}'>直播中</text>
</view>
<view bindtap='tabFun' data-index="2">
<text class='{{tabIndex==2?"active":""}}'>未开始</text>
</view>
<view bindtap='tabFun' data-index="3">
<text class='{{tabIndex==3?"active":""}}'>已结束</text>
</view>
<view bindtap='tabFun' data-index="4">
<text class='{{tabIndex==4?"active":""}}'>其它</text>
</view>
</view>
<!-- 手指拖动的距离,实现scroll-view的拖拽效果 >
<view style="height:{{touchMoveHeight}}px;">
</view-->
<scroll-view class='list' scroll-y bindscroll="bindscroll" bindtouchstart="touchStart" bindtouchend="touchEnd" bindtouchmove="touchMove">
<!--view class="container" style="height:{{touchMoveHeight/2}}px;"-->
<view class="loading" wx:if="{{show}}">
<view class="dot" animation="{{alpha[0]}}"></view>
<view class="dot" animation="{{alpha[1]}}"></view>
<view class="dot" animation="{{alpha[2]}}"></view>
<view class="dot" animation="{{alpha[3]}}"></view>
<view class="dot" animation="{{alpha[4]}}"></view>
</view>
<!--/view-->
<view class='item' wx:if="{{!isEdit}}" wx:for="{{listcf[tabIndex-1]}}">
<navigator class='content' hover-class="none" url="plugin-private://wx2b03c6e691cd7370/pages/live-player-plugin?room_id={{item.roomid}}">
<view class='text' wx:if="{{item.start_YMD==item.end_YMD}}">
<view class='title'>{{item.start_YMD}}</view>
<view class='title'>{{item.start_hms}} - {{item.end_hms}}</view>
</view>
<view class='text' wx:else>
<view class='title'>{{item.start_YMD}}</view>
<view class='title'>{{item.start_hms}}</view>
<view class='title'>-</view>
<view class='title'>{{item.end_YMD}}</view>
<view class='title'>{{item.end_hms}}</view>
</view>
<image src='{{item.share_img}}' mode="aspectFill" class="share_img"></image>
<view class='text' >
<view class='name'>{{item.name}}</view>
<view class='spec'>{{item.creat_date}}</view>
<view class='roomid'>
<text>房间号 {{item.roomid}}</text>
</view>
<view class='anchor_name'>
<text>主播 {{item.anchor_name}}</text>
</view>
</view>
</navigator>
</view>
</scroll-view>
</view>
2.index.wxss
/* pages/live/index.wxss */
.main{
height: 100vh;
}
.tab{
height: 7vh;
display: flex;
line-height: 7vh;
}
.tab view{
flex: 1 0 auto;
font-size: 14px;
color: #333333;
text-align: center;
}
.tab .active{
color: #ff5f19;
border-bottom: 1px solid #ff5f19;
padding-bottom:1.8vh;
}
.list{
background-color: #fff;
height:93vh;
}
.list .item{
display: flex;
border-bottom: 1px solid #EDEDED;
padding: 0 16px;
height:120px;
align-items: center;
}
.list .label{
flex: 0 0 auto;
padding:10px 0;
}
.list .content{
flex-grow: 1;
display:flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.list .content image{
flex: 0 0 auto;
height: 76px;
width: 250rpx;
padding:20rpx;
}
.list .content .text{
flex-grow: 1;
font-size: 14px;
width:210rpx;
}
.list .content .name{
flex-grow: 1;
font-size: 16px;
font-weight: bold;
text-overflow: -o-ellipsis-lastline;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
align-content: center;
}
.list .content .title{
overflow: hidden;
text-align: center;
}
.list .content .spec{
font-size: 12px;
color: #333333;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
line-height: 20px;
max-height: 20px;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
}
.list .content .roomid,.list .content .anchor_name{
display: flex;
font-size: 13px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
line-height: 20px;
max-height: 20px;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
}
.list .content .roomid text:nth-child(1),.list .content .anchor_name text:nth-child(1){
color: #fbb8ac;
flex: 1 0 50%;
}
.list .content .price text:nth-child(2){
color: #999999;
flex: 1 0 50%;
text-align: right;
}
.data-loading {
height: 100rpx;
line-height: 100rpx;
background-color: #eee;
text-align: center;
font-size: 14px;
}
.container {
height:40rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
padding: 20rpx 0;
box-sizing: border-box;
}
/** loading.wxss **/
.loading {
width: 100%;
position: absolute;
/*bottom: 150rpx;*/
top:0 vh;
justify-content: center;
text-align: center;
}
.loading .dot{
background-color: rgb(172, 7, 7);
display: inline-block;
/**圆点大小在这里设置,高宽一致,圆角值为高宽的一半**/
width: 16rpx;
height: 16rpx;
border-radius: 8rpx;
margin: 0 10rpx;
opacity: 0;
}
3.index.js
// pages/coupon/index.js
const app = getApp();
var util = require("../../utils/util.js");
var touchDot = 0;//触摸时的原点
var time = 0;// 时间记录,用于滑动时且时间小于1s则执行左右滑动
var interval = "";// 记录/清理时间记录
Page({
/**
* 页面的初始数据
*/
data: {
tabIndex: 1,
list: [],
listcf:{},
/**
* 用于控制当 scroll-view 滚动到底部时,显示 “数据加载中...” 的提示
*/
hidden: true,
/**
* 用于显示文章的数组
*/
articles: [],
/**
* 数据是否正在加载中,避免用户瞬间多次下滑到底部,发生多次数据加载事件
*/
loadingData: false,
switchtab:false,
//是否触发下拉刷新
isTop: true,//是否在顶部
touchStartY: 0,//刚触碰屏幕时 距离顶部的距离
touchMoveHeight: 0, //触碰屏幕时 手指移动的距离
scrolltoupper: false,//判断是否正在下拉刷新
scrolltolower: false,//判断是否正在上拉加载
maxtouchMoveHeight:120,
refreshtext:"下拉刷新",
show:false,
alpha: [1,1,1,1,1],
timer:'',
Isdraged:false,
Isvibrate:false,
},
tabFun(e) {
var that=this;
that.setData({
tabIndex: e.currentTarget.dataset.index
})
wx.showLoading({
title: '加载中'
});
that.getList(() => {
that.setData({
scrolltoupper: false,
scrolltolower: false,
touchMoveHeight: 0,
})
wx.hideLoading();});
//console.log("test")
// this.getList()
},
getList:function(callback){
var that=this;
wx.request({
url:'https://vircom.top/api/getliverooms.php',//改成你自己的链接
header:{
'Content-Type':'application/x-www-form-urlencoded'
},
data:{
//id:app.globalData.openid,
},
method:'GET',
success:function(res){
//console.log(res.data);
that.setData({
list:res.data.liverooms,
});
var list=that.data.list;
var list1=[];
var list2=[];
var list3=[];
var list4=[];
var listcf={};
//console.log(list.length);
for(let i=0;i<list.length;i++){
//console.log(list[i].live_status);
list[i].start_YMD=util.formatTime(list[i].start_time,'Y/M/D');
list[i].start_hms=util.formatTime(list[i].start_time,'h:m');
list[i].end_YMD=util.formatTime(list[i].end_time,'Y/M/D');
list[i].end_hms=util.formatTime(list[i].end_time,'h:m');
switch(list[i].live_status){
case "101":{
list1.push(list[i]);
}break;
case "102":{
list2.push(list[i]);
}break;
case "103":{
list3.push(list[i]);
}break;
default:{
list4.push(list[i]);
}break;
}
}
listcf[0]=list1;
listcf[1]=list2;
listcf[2]=list3;
listcf[3]=list4;
that.setData({
listcf:listcf
})
if(callback){
callback();
}
},
fail:function(res){
console.log(res.data)
}
});
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.setData({
tabIndex: options.type||1
})
this.getList();
// let self = this;
//var sjc = 1592637818;
//console.log(util.formatTime(sjc,'Y/M/D h:m:s'));
// console.log(util.formatTime(sjc, 'h:m'));
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
},
upper:function(e){
console.log(e);
this.getList()
},
/**
* 上滑加载更多
*/
scrollToUpper: function(e) {
console.info('scrollToLower', e);
var hidden = this.data.hidden,
loadingData = this.data.loadingData,
that = this;
if (hidden) {
this.setData({
hidden: false
});
console.info(this.data.hidden);
}
if (loadingData) {
return;
}
this.setData({
loadingData: true
});
// 加载数据,模拟耗时操作
wx.showLoading({
title: '数据加载中...',
});
setTimeout(function() {
that.getList( () => {
that.setData({
hidden: true,
loadingData: false
});
wx.hideLoading();
});
console.info('上拉数据加载完成.');
}, 2000);
},
scrollToLower: function(e) {
wx.showToast({
title: '触顶了...',
})
},
bindscroll: function (e) {
//console.log(e)
let self = this;
self.setData({
isTop: false
})
},
// 触摸开始事件
touchStart: function (e) {
let self = this;
self.setData({
touchStartY: e.changedTouches[0].pageY,
isTop: true
});
touchDot = e.touches[0].pageX; // 获取触摸时的原点
// 使用js计时器记录时间
/* interval = setInterval(function () {
time++;
}, 100);*/
//console.log(e)
},
// 触摸移动事件
touchMove: function (e) {
var that=this;
let touchStartY = that.data.touchStartY;
let touchMoveY = e.changedTouches[0].pageY;
let touchMoveHeight=touchMoveY - touchStartY;
that.setData({
touchMoveHeight: touchMoveY - touchStartY
})
if ((touchMoveHeight>20)&& that.data.isTop&&(!that.data.Isdraged)){
that.anniu();
that.setData({
show:true,
})
}
if(touchMoveHeight<that.data.maxtouchMoveHeight){
that.setData({
Isvibrate:false
})
}
if ((touchMoveHeight>=that.data.maxtouchMoveHeight)&& that.data.isTop&&(!that.data.Isvibrate)) {
wx.vibrateShort({
complete: (res) => {
that.setData({
Isvibrate:true,
})
},
})
}
var touchMove = e.touches[0].pageX;
// console.log("touchMove:" + touchMove + " touchDot:" + touchDot + " diff:" + (touchMove - touchDot));
// 向左滑动
if (((touchMove - touchDot) <= -80) &&(!that.data.switchtab)) {
that.setData({
switchtab:true,
});
var tabIndex=that.data.tabIndex;
if(tabIndex<4){
tabIndex++;
that.setData({
tabIndex:tabIndex
})
}
wx.showLoading({
title: '加载中'
});
that.getList(() => {
that.setData({
scrolltoupper: false,
scrolltolower: false,
touchMoveHeight: 0,
})
wx.hideLoading();});
}
// 向右滑动
if (((touchMove - touchDot )>= 80)&& (!that.data.switchtab)) {
console.log('向右滑动');
that.setData({
switchtab:true
})
var tabIndex=that.data.tabIndex;
if(tabIndex>1){
tabIndex--;
that.setData({
tabIndex:tabIndex
})
}
wx.showLoading({
title: '加载中'
});
that.getList(() => {
that.setData({
scrolltoupper: false,
scrolltolower: false,
touchMoveHeight: 0,
})
wx.hideLoading();});
}
},
// 触摸结束事件
touchEnd: function (e) {
let self = this;
self.setData({
show:false,
Isdraged:false,
Isvibrate:false,
})
clearInterval(self.data.timer);
let isTop = self.data.isTop;
let touchStartY = self.data.touchStartY;
let touchEndY = e.changedTouches[0].pageY;
//console.log(isTop)
//console.log(touchStartY)
//console.log(touchEndY)
if (touchEndY > touchStartY && isTop&&(self.data.touchMoveHeight>=self.data.maxtouchMoveHeight)) {
self.setData({
scrolltoupper: true,
scrolltolower: true,
touchMoveHeight: 120
})
self.myPullDownRefresh();
}else{
self.setData({
touchMoveHeight:0
})
}
// clearInterval(interval); // 清除setInterval
time = 0;
self.setData(
{
switchtab:false,
}
)
},
myPullDownRefresh: function () {
let self = this;
//console.log("begin")
var scrolltoupper = self.data.scrolltoupper;
if (scrolltoupper){
wx.showLoading({
title: '加载中'
});
self.getList(() => {
self.setData({
scrolltoupper: false,
scrolltolower: false,
touchMoveHeight: 0,
})
wx.hideLoading();
/*wx.showToast({
title: '刷新成功',
icon:'success',
duration:2000
})*/
});
//定时器为了模仿实际开发中请求数据过程 使加载效果看起来好一些,
}
},
anniu: function (e) {
var self = this;
var _index = 0;
var _alpha = self.data.alpha;
var _speed = 500;
self.setData({
timer:setInterval(function () {
var an_show = wx.createAnimation({});
var an_hide = wx.createAnimation({});
an_show.opacity(1).step({ duration: _speed });
an_hide.opacity(0).step({ duration: _speed });
_alpha[_index] = an_show;
_alpha[_index == 0 ? 4 : _index - 1] = an_hide;
self.setData({
alpha: _alpha
})
_index = _index == 4 ? 0 : _index + 1;
}, _speed)
})
/*var timer = setInterval(function () {
var an_show = wx.createAnimation({});
var an_hide = wx.createAnimation({});
an_show.opacity(1).step({ duration: _speed });
an_hide.opacity(0).step({ duration: _speed });
_alpha[_index] = an_show;
_alpha[_index == 0 ? 4 : _index - 1] = an_hide;
self.setData({
alpha: _alpha
})
_index = _index == 4 ? 0 : _index + 1;
}, _speed);*/
},
})
4.index.json
{
"navigationBarTitleText": "直播间"
}
5.在utils文件夹中的util.js(用于直播间获取时间戳,在自己的项目中不用的话可以在index.js中删掉这句var util = require("…/…/utils/util.js");不引用即可)
//数据转化
function formatNumber(n) {
n = n.toString()
return n[1] ? n : '0' + n
}
/**
* 时间戳转化为年 月 日 时 分 秒
* number: 传入时间戳
* format:返回格式,支持自定义,但参数必须与formateArr里保持一致
*/
function formatTime(number,format) {
var formateArr = ['Y','M','D','h','m','s'];
var returnArr = [];
var date = new Date(number * 1000);
returnArr.push(date.getFullYear());
returnArr.push(parseInt(formatNumber(date.getMonth() + 1)));
returnArr.push(formatNumber(date.getDate()));
returnArr.push(formatNumber(date.getHours()));
returnArr.push(formatNumber(date.getMinutes()));
returnArr.push(formatNumber(date.getSeconds()));
for (var i in returnArr)
{
format = format.replace(formateArr[i], returnArr[i]);
}
return format;
}
module.exports = {
formatTime: formatTime
}