提交 917843da 编写于 作者: I iotjin

update UI

上级 0c83f72c
//刷新组件
var HTTP = require('../../../JhHttpUtils/JhHttpUtils.js');
let currentPage = 0;
Component({
/**
* 组件的属性列表
*/
properties: {
height: {
type: String,
value: '100vh'
},
width: {
type: String,
value: '100vw'
},
background: {
type: String,
value: 'white'
},
timeout: {
type: Number,
value: 1000
},
//是否开启上拉加载更多,默认开启
enablemore: {
type: Boolean,
value: true
},
url: {
type: String,
value: ''
},
limit: {
type: Number,
value: 100
},
},
options: {
virtualHost: true,
multipleSlots: true // 在组件定义时的选项中启用slot支持
},
/**
* 组件的初始数据
*/
data: {
isRefreshing: false, //正在刷新中
dataArr: [],
},
// 以下是旧式的定义方式,可以保持对 <2.2.3 版本基础库的兼容
attached: function () {
// console.log('attached')
this.onRefresh()
},
// 在组件实例被从页面节点树移除时执行
detached: function () {
// console.log('detached')
this.endFresh()
},
/**
* 组件的方法列表
*/
methods: {
//拖拽下拉回调函数
onPulling(e) {},
//刷新
onRefresh(e) {
this.handleMultipleTriggers()
},
//刷新重置
onRestore(e) {
this.triggerEvent("onRestore")
},
//刷新中断
onAbort(e) {
this.triggerEvent("onAbort")
},
//刷新结束
endRefresh() {
setTimeout(() => {
this.setData({
isRefreshing: false,
})
this.triggerEvent("onRefreshEnd")
}, this.properties.timeout)
},
//上拉更多
onLoadMore(e) {
if (!this.properties.enablemore) {
return
}
this.handleMultipleTriggers(true)
},
handleMultipleTriggers(isLoadMore) {
if (this.data.isRefreshing) return
this.setData({
isRefreshing: true
})
if (isLoadMore) {
this.triggerEvent("onLoadMore")
this.requestData(isLoadMore);
} else {
this.triggerEvent("onRefresh")
this.requestData();
}
},
//请求数据
requestData: function (isLoadMore) {
let url = this.properties.url
if (!url.length) {
wx.showToast({
title: '请求地址为空!',
icon: 'none',
})
return
}
var that = this
if (isLoadMore) {
currentPage++;
} else {
currentPage = 0;
this.setData({
dataArr: [],
})
}
var params = {
page: currentPage,
limit: this.properties.limit,
}
wx.showNavigationBarLoading()
HTTP.post(url, params).then(res => {
wx.hideNavigationBarLoading()
that.endRefresh()
if (res.code == 200) {
var data = res.data
if (!data.length) {
wx.showToast({
title: '暂无更多数据',
icon: 'none',
})
return
}
if (isLoadMore) {
that.setData({
dataArr: that.data.dataArr.concat(data),
})
} else {
that.setData({
dataArr: data,
})
}
that.onReturnData(that.data.dataArr)
} else {
currentPage--
currentPage = currentPage < 0 ? 0 : currentPage
}
}).catch(error => {
wx.hideNavigationBarLoading()
that.endRefresh()
currentPage--
currentPage = currentPage < 0 ? 0 : currentPage
});
},
//传出的数据
onReturnData(data) {
this.triggerEvent("onReturnData", data)
},
}
})
\ No newline at end of file
<scroll-view class="scroll-view" scroll-y style="width: {{width}}; height: {{height}};background:{{background}};"
refresher-enabled="{{true}}" refresher-default-style="black" refresher-triggered="{{isRefreshing}}"
bindrefresherpulling="onPulling" bindrefresherrefresh="onRefresh" bindscrolltolower='onLoadMore'
bindrefresherrestore="onRestore" bindrefresherabort="onAbort" scroll-anchoring="true">
<!--这里用slot节点占位,可以替换任意布局-->
<view style="height:auto;">
<slot></slot>
</view>
</scroll-view>
\ No newline at end of file
page {
/* width: 100%; */
/* height: 100%; */
/* overflow: hidden; */
}
.scroll-view{
white-space:nowrap;
}
\ No newline at end of file
//刷新组件
Component({
/**
* 组件的属性列表
*/
properties: {
height: {
type: String,
value: '100vh'
},
width: {
type: String,
value: '100vw'
},
background: {
type: String,
value: 'white'
},
timeout: {
type: Number,
value: 4000
},
//是否开启上拉加载更多,默认开启
enablemore: {
type: Boolean,
value: true
}
},
options: {
multipleSlots: true // 在组件定义时的选项中启用slot支持
},
/**
* 组件的初始数据
*/
data: {
isRefreshing: false //正在刷新中
},
// 以下是旧式的定义方式,可以保持对 <2.2.3 版本基础库的兼容
attached: function () {
// console.log('attached')
},
// 在组件实例被从页面节点树移除时执行
detached: function () {
// console.log('detached')
this.endFresh()
},
/**
* 组件的方法列表
*/
methods: {
//拖拽下拉回调函数
onPulling(e) {},
//刷新
onRefresh(e) {
this.handleMultipleTriggers()
},
//刷新重置
onRestore(e) {
this.triggerEvent("onRestore")
},
//刷新中断
onAbort(e) {
this.triggerEvent("onAbort")
},
//刷新结束
endRefresh() {
this.setData({
isRefreshing: false,
})
this.triggerEvent("onRefreshEnd")
},
//上拉更多
onLoadMore(e) {
if (!this.properties.enablemore) {
return
}
this.handleMultipleTriggers(true)
},
handleMultipleTriggers(isLoadMore) {
if (this.data.isRefreshing) return
this.setData({
isRefreshing: true
})
let that = this
setTimeout(() => {
that.endRefresh()
}, this.properties.timeout)
if (isLoadMore) {
this.triggerEvent("onLoadMore")
} else {
this.triggerEvent("onRefresh")
}
}
}
})
\ No newline at end of file
<scroll-view scroll-y style="width: {{width}}; height: {{height}};background:{{background}};"
refresher-enabled="{{true}}" refresher-default-style="black" refresher-triggered="{{isRefreshing}}"
bindrefresherpulling="onPulling" bindrefresherrefresh="onRefresh" bindscrolltolower='onLoadMore'
bindrefresherrestore="onRestore" bindrefresherabort="onAbort">
<!--这里用slot节点占位,可以替换任意布局-->
<view style="height:auto;">
<slot></slot>
</view>
</scroll-view>
\ No newline at end of file
scroll-view {
/* display: flex;
flex-wrap: wrap;
height: 100vh; */
background: gainsboro;
}
\ No newline at end of file
Component({
properties: {
// 加载中
requesting: {
type: Boolean,
value: false,
observer: 'requestingEnd',
},
// 加载完毕
end: {
type: Boolean,
value: false,
},
// 控制空状态的显示
emptyShow: {
type: Boolean,
value: false,
},
// 当前列表长度
listCount: {
type: Number,
value: 0,
},
// 空状态的图片
emptyUrl: {
type: String,
value: "/assets/image/empty/empty.png"
},
// 空状态的文字提示
emptyText: {
type: String,
value: "未找到数据"
},
// 下拉刷新的高度
refreshSize: {
type: Number,
value: 90,
observer: 'refreshChange'
},
// 顶部高度
topSize: {
type: Number,
value: 0,
},
// 底部高度
bottomSize: {
type: Number,
value: 0,
},
// 颜色
color: {
type: String,
value: ""
},
// iOS点击顶部状态栏、安卓双击标题栏时,滚动条返回顶部,只支持竖向
enableBackToTop: {
type: Boolean,
value: false
}
},
data: {
/* 未渲染数据 */
mode: 'refresh', // refresh 和 more 两种模式
successShow: false, // 显示success
successTran: false, // 过度success
refreshStatus: 1, // 1: 下拉刷新, 2: 松开更新, 3: 加载中, 4: 加载完成
move: -65, // movable-view 偏移量
scrollHeight1: 0, // refresh view 高度负值
scrollHeight2: 0, // refresh view - success view 高度负值
timer: null,
/* 渲染数据 */
scrollTop: 0,
overOnePage: false
},
methods: {
/**
* 处理 bindscrolltolower 失效情况
*/
scroll(e) {
// 可以触发滚动表示超过一屏
this.setData({
overOnePage: true
});
clearTimeout(this.data.timer);
this.setData({
timer: setTimeout(() => {
this.setData({
scrollTop: e.detail.scrollTop
})
}, 100)
});
},
/**
* movable-view 滚动监听
*/
change(e) {
let refreshStatus = this.data.refreshStatus,
diff = e.detail.y;
if (refreshStatus >= 3) return;
if (diff > -10) {
this.setData({
refreshStatus: 2
});
} else {
this.setData({
refreshStatus: 1
});
}
},
/**
* movable-view 触摸结束事件
*/
touchend() {
let refreshStatus = this.data.refreshStatus;
if (refreshStatus >= 3) return;
if (refreshStatus === 2) {
wx.vibrateShort();
this.setData({
refreshStatus: 3,
move: 0,
mode: 'refresh'
});
this.triggerEvent('refresh');
} else if (refreshStatus === 1) {
this.setData({
move: this.data.scrollHeight1
});
}
},
/**
* 加载更多
*/
more() {
if (!this.properties.end) {
this.setData({
mode: 'more'
});
this.triggerEvent('more');
}
},
/**
* 监听 requesting 字段变化, 来处理下拉刷新对应的状态变化
*/
requestingEnd(newVal, oldVal) {
if (this.data.mode === 'more') return;
if (oldVal === true && newVal === false) {
setTimeout(() => {
this.setData({
successShow: true,
refreshStatus: 4,
move: this.data.scrollHeight2
});
setTimeout(() => {
this.setData({
successTran: true,
move: this.data.scrollHeight1
});
setTimeout(() => {
this.setData({
refreshStatus: 1,
successShow: false,
successTran: false,
move: this.data.scrollHeight1
});
}, 350)
}, 1500)
}, 600)
} else {
if (this.data.refreshStatus !== 3) {
this.setData({
refreshStatus: 3,
move: 0
});
}
}
},
/**
* 监听下拉刷新高度变化, 如果改变重新初始化参数, 最小高度80rpx
*/
refreshChange(newVal, oldVal) {
if (newVal <= 80) {
this.setData({
refreshSize: 80
});
}
// 异步加载数据时候, 延迟执行 init 方法, 防止基础库 2.7.1 版本及以下无法正确获取 dom 信息
setTimeout(() => this.init(), 10);
},
/**
* 初始化scroll组件参数, 动态获取 下拉刷新区域 和 success 的高度
*/
init() {
let {
windowWidth
} = wx.getSystemInfoSync();
let successHeight = (windowWidth || 375) / 750 * 70;
this.createSelectorQuery().select("#refresh").boundingClientRect((res) => {
this.setData({
scrollHeight1: -res.height,
scrollHeight2: successHeight - res.height
});
}).exec();
},
},
ready() {
this.init();
}
});
\ No newline at end of file
{
"component": true,
"usingComponents": {}
}
\ No newline at end of file
<view>
<view id="success" class="success {{successShow ? 'success--show' : ''}} {{successTran ? 'success--tran' : ''}}"
style="top: {{topSize}}rpx;color: {{color}}">
<view class="info">刷新成功</view>
</view>
<movable-area class="movable-area">
<movable-view class="scroll" style="height: calc(100vh + 40rpx + {{refreshSize}}rpx)" bind:change="change"
bind:touchend="touchend" direction="vertical" disabled="{{refreshStatus >= 3}}" y='{{move}}'>
<scroll-view class="scroll__view" style="padding-bottom: {{bottomSize}}rpx;padding-top: {{topSize}}rpx;"
scroll-y="{{refreshStatus == 1}}" bindscroll="scroll" scroll-top="{{scrollTop}}"
enable-back-to-top="{{enableBackToTop}}" lower-threshold="{{80}}rpx" bindscrolltolower="more">
<view id="refresh" class="scroll__refresh {{successShow ? 'scroll__refresh--hidden' : ''}}"
style="height: {{refreshSize}}rpx;padding: 20rpx 0;">
<view class="scroll__loading">
<view wx:if="{{refreshStatus == 1 || refreshStatus == 2}}"
class="{{refreshStatus == 2 ? 'rotate' : ''}} arrow"></view>
<view wx:if="{{refreshStatus == 3}}" class="loading">
<view class="loading__item"></view>
<view class="loading__item"></view>
<view class="loading__item"></view>
<view class="loading__item"></view>
<view class="loading__item"></view>
<view class="loading__item"></view>
<view class="loading__item"></view>
<view class="loading__item"></view>
<view class="loading__item"></view>
<view class="loading__item"></view>
<view class="loading__item"></view>
<view class="loading__item"></view>
</view>
<view class="text" wx:if="{{refreshStatus == 1}}">下拉刷新</view>
<view class="text" wx:elif="{{refreshStatus == 2}}">松开更新</view>
<view class="text" wx:elif="{{refreshStatus == 3}}">加载中...</view>
</view>
</view>
<slot></slot>
<view wx:if="{{listCount === 0 && emptyShow}}" class="empty">
<image class="empty__image" src="{{emptyUrl}}"></image>
<view class="empty__text">{{emptyText}}</view>
</view>