<template name="custom-scroll-view">
<!-- 1.ref绑定数据,可以操作this.$refs操作dom,实例的方法等
2.refresher-enabled用来开启下拉刷新
3.style用来定义样式
4.refresher-threshold用来定义下拉阈值
5.refresher-triggered设置当前下拉刷新状态,true 表示下拉刷新已经被触发,false 表示下拉刷新未被触发
6.refresher-default-style自定义下拉刷新
7.refresherBackground下拉框背景颜色
8.bounces控制下拉是否回弹
9.show-scrollbar控制是否显示滚动条
10.@refresherpulling下拉刷新控件被下拉-->
<list-view v-if="listIs === 'list-view'" ref="csmList" :id="listId" refresher-enabled="true" :style="[pagingStyle]"
refresher-threshold="10" :refresher-triggered="refresherTriggered" refresher-default-style="none"
:refresherBackground="refresherBackground" bounces="false" show-scrollbar="false" @refresherpulling="_onRefresherpulling"
@refresherrefresh="_onRefresherrefresh" @refresherrestore="_onRefresherrestore" :scroll-top="scrollTop"
@scrolltolower="_onScrolltolower" @scroll="_onScroll">
<list-item slot="refresher">
<view ref="customRefresher" class="zpx-list-refresher" >
<custom-refresher ref="commonRefresher" :default-text="$t('refresh.pullDown')"
:pulling-text="$t('refresh.refresh')" :refreshing-text="$t('refresh.loading')"
:status="refresherStatus" :refreshDateText="$t('refresh.refreshTimeText')" />
</view>
</list-item>
<slot name="slot1"></slot>
<slot name="slot2"></slot>
<slot name="slot3"></slot>
<slot name="slot4"></slot>
<slot name="slot5"></slot>
<slot name="slot6"></slot>
<slot name="slot7"></slot>
<slot name="slot8"></slot>
<slot name="slot9"></slot>
<slot name="slot10"></slot>
<slot name="dataList"></slot>
<list-item>
<template v-if="showLoadMore">
<custom-load-more :status="loadMoreStatus" :default-text="loadMoreDefaultText"
:loading-text="$t('loadMore.loadingText')" :no-more-text="$t('loadMore.noMoreText')"
:fail-text="loadMoreFailText" />
</template>
</list-item>
</list-view>
<scroll-view v-else ref="csmList" :id="listId" refresher-enabled="true" :style="[pagingStyle]"
refresher-threshold="60" :refresher-triggered="refresherTriggered" refresher-default-style="none"
refresherBackground="#fff" bounces="false" show-scrollbar="false" @refresherpulling="_onRefresherpulling"
@refresherrefresh="_onRefresherrefresh" @refresherrestore="_onRefresherrestore" :scroll-top="scrollTop"
@scrolltolower="_onScrolltolower" @scroll="_onScroll">
<view slot="refresher">
<view ref="zpxListRefresher" class="zpx-list-refresher" >
<custom-refresher ref="commonRefresher" :default-text="$t('refresh.pullDown')"
:pulling-text="$t('refresh.refresh')" :refreshing-text="$t('refresh.loading')"
:status="refresherStatus" :refreshDateText="$t('refresh.refreshTimeText')" />
</view>
</view>
<slot name="slot1"></slot>
<slot name="slot2"></slot>
<slot name="slot3"></slot>
<slot name="slot4"></slot>
<slot name="slot5"></slot>
<slot name="slot6"></slot>
<slot name="slot7"></slot>
<slot name="slot8"></slot>
<slot name="slot9"></slot>
<slot name="slot10"></slot>
<slot name="dataList"></slot>
<view>
<template v-if="showLoadMore">
<custom-load-more :status="loadMoreStatus" :default-text="loadMoreDefaultText"
:loading-text="$t('loadMore.loadingText')" :no-more-text="$t('loadMore.noMoreText')"
:fail-text="loadMoreFailText" />
</template>
</view>
</scroll-view>
</template>
<script lang="uts">
import { gc } from './config/index.uts'
import Enum from './enums/index.uts'
import customRefresher from './components/custom-refresher.uvue'
import customLoadMore from './components/custom-load-more.uvue'
import { getTime } from './utils/index.uts'
export default {
components: { customRefresher, customLoadMore },
data() {
return {
// 设置当前下拉刷新状态,true 表示下拉刷新已经被触发,false 表示下拉刷新未被触发
refresherTriggered: false,
// refresher节点高度
refresherNodeHeight: 0 as number,
// z-paging-x中list-view或scroll-view的节点
$csmList: null as null | UniElement,
// 当前页
pageNo: 1,
// 竖向滚动条位置
scrollTop: 0,
oldScrollTop: 0,
// 下拉刷新状态
refresherStatus: Enum.Refresher.Default,
// 下拉刷新最后更新时间更新的时间戳
refresherTimeTextTimestamp: 0,
// 是否是加载中状态
isLoading: true,
isFlag: true,
// 底部加载更多状态
loadMoreStatus: Enum.More.Default,
customNoMore: -1,
//第一个插槽数据
slot1: [] as any[],
//第二个插槽数据
slot2: [] as any[],
//第三个插槽数据
slot3: [] as any[],
slot4: [] as any[],
slot5: [] as any[],
slot6: [] as any[],
slot7: [] as any[],
slot8: [] as any[],
slot9: [] as any[],
slot10: [] as any[],
dataList: [] as any[],
// 上次下拉刷新时间戳(用于防抖)
lastRefreshTime: 0 as number
}
},
props: {
// 自定义初始的pageNo,默认为1
defaultPageNo: {
type: Number,
default: gc<number>('default-page-no', 1)
},
// 自定义pageSize,默认为10
defaultPageSize: {
type: Number,
default: gc<number>('default-page-size', 10)
},
// 设置组件的style
pagingStyle: {
type: Object,
default: gc<object>('paging-style', {})
},
// list的类型:list-view或scroll-view,默认为list-view
listIs: {
type: String,
default: gc<string>('list-is', 'list-view'),
},
// 下拉刷新区域背景颜色
refresherBackground: {
type: String,
default: gc<string>('refresher-background', '#FFF')
},
// 列表刷新时自动显示下拉刷新view,默认为否
showRefresherWhenReload: {
type: Boolean,
default: gc<boolean>('show-refresher-when-reload', false)
},
// 是否显示最后更新时间,默认为否
showRefresherUpdateTime: {
type: Boolean,
default: gc<boolean>('show-refresher-update-time', false)
},
// 如果需要区别不同页面的最后更新时间,请为不同页面的z-paging-x的`refresher-update-time-key`设置不同的字符串
refresherUpdateTimeKey: {
type: String,
default: gc<string>('refresher-update-time-key', 'default')
},
// 是否启用加载更多数据(含滑动到底部加载更多数据和点击加载更多数据),默认为是
loadMoreEnabled: {
type: Boolean,
default: gc<boolean>('load-more-enabled', true)
},
// 滑动到底部"默认"文字,默认:点击加载更多
loadMoreDefaultText: {
type: String,
default: gc<string>('load-more-default-text', '点击加载更多')
},
// 滑动到底部"加载中"文字,默认:正在加载...
loadMoreLoadingText: {
type: String,
default: gc<string>('load-more-loading-text', '正在加载...')
},
// 滑动到底部"没有更多"文字,默认:没有更多了
loadMoreNoMoreText: {
type: String,
default: gc<string>('load-more-no-more-text', '没有更多了')
},
// 滑动到底部"加载失败"文字,默认:加载失败,点击重新加载
loadMoreFailText: {
type: String,
default: gc<string>('load-more-fail-text', '加载失败,点击重新加载')
},
// mounted后自动调用reload方法(mounted后自动调用接口),默认为是
auto: {
type: Boolean,
default: gc<boolean>('auto', true)
},
// reload时自动滚动到顶部,默认为是
scrollToTopWhenReload: {
type: Boolean,
default: gc<boolean>('scrollToTopWhenReload', true)
},
// reload时立即自动清空原list,默认为是,若立即自动清空,则在reload之后、请求回调之前页面是空白的
cleanListWhenReload: {
type: Boolean,
default: gc<boolean>('cleanListWhenReload', true)
},
// 空数据描述文字
emptyText: {
type: String,
default: gc<string>('empty-text', '没有数据哦~')
},
// 空数据加载失败文字
emptyErrorText: {
type: String,
default: gc<string>('empty-error-text', '很抱歉,加载失败')
},
// 空数据图片
emptyImg: {
type: String,
default: gc<string>('empty-img', '')
},
// 空数据加载失败图片
emptyErrorImg: {
type: String,
default: gc<string>('empty-error-img', '')
},
//自动显示点击返回顶部按钮,默认为否
showBackToTop: {
type: Boolean,
default: gc<boolean>('show-back-to-top', false)
},
//点击返回顶部按钮显示/隐藏的阈值(滚动距离),单位为px,默认为300px
backToTopThreshold: {
type: Number,
default: gc<number>('back-to-top-threshold', 300)
},
//点击返回顶部按钮的自定义图片地址,默认使用z-paging内置的图片
backToTopImg: {
type: String,
default: gc<string>('back-to-top-img', '')
},
// 点击返回顶部按钮的style
backToTopStyle: {
type: Object,
default: gc<object>('back-to-top-style', {}),
},
// list的类型:list-view或scroll-view,默认为list-view
listIs: {
type: String,
default: gc<string>('list-is', 'list-view'),
},
// list的id
listId: {
type: String,
default: gc<string>('list-id', ''),
},
// 下拉刷新默认文字
refresherDefaultText: {
type: String,
default: gc<string>('refresher-default-text', '下拉刷新')
},
// 下拉刷新下拉中文字
refresherPullingText: {
type: String,
default: gc<string>('refresher-pulling-text', '松开立即刷新')
},
// 下拉刷新刷新中文字
refresherRefreshingText: {
type: String,
default: gc<string>('refresher-refreshing-text', '正在刷新...')
},
data2: { // 自定义属性名(如 `data`)
type: Object,
default: () => ({})
},
// 是否启用滚动到底部加载更多,默认为true
enableScrollToLower: {
type: Boolean,
default: gc<boolean>('enable-scroll-to-lower', true)
},
},
mounted() {
//this.$csmList = this.$refs['csmList'] as UniElement;
this.pageNo = this.defaultPageNo;
if (this.auto) {
this.reload();
}
this.$nextTick(() => {
const refresherEle = this.$refs["zpxListRefresher"] as UniElement | null;
if (refresherEle !== null) {
refresherEle.getBoundingClientRectAsync()!.then((rect : DOMRect) => {
this.refresherNodeHeight = rect.height;
})
}
})
},
//计算属性
computed: {
isFirstPage() : boolean {
return this.pageNo === this.defaultPageNo;
},
showLoadMore() : boolean {
// console.log("testetete");
// console.log(this.loadMoreEnabled);
// console.log(!this.isLoading);
// console.log(this.dataList.length);
// console.log(this.loadMoreEnabled && (!this.isLoading || this.dataList.length > 0));
return this.loadMoreEnabled && (!this.isLoading || this.dataList.length > 0);
},
},
//监听数据变化
watch: {
slot1(newVal : any[]) {
this.$emit('update:data1', newVal);
},
slot2(newVal : any[]) {
this.$emit('update:data2', newVal);
},
slot3(newVal : any[]) {
this.$emit('update:data3', newVal);
},
slot4(newVal : any[]) {
this.$emit('update:data4', newVal);
},
slot5(newVal : any[]) {
this.$emit('update:data5', newVal);
},
slot6(newVal : any[]) {
this.$emit('update:data6', newVal);
},
slot7(newVal : any[]) {
this.$emit('update:data7', newVal);
},
slot8(newVal : any[]) {
this.$emit('update:data8', newVal);
},
slot9(newVal : any[]) {
this.$emit('update:data9', newVal);
},
slot10(newVal : any[]) {
this.$emit('update:data10', newVal);
},
dataList(newVal : any[]) {
this.$emit('update:dataList', newVal);
},
refresherStatus(newVal : number) {
this.$emit('refresherStatusChange', newVal);
},
loadMoreStatus(newVal : number) {
this.$emit('loadMoreStatusChange', newVal);
},
},
methods: {
// 下拉刷新控件被下拉事件
_onRefresherpulling(e : RefresherEvent) {
this.refresherStatus = e.detail.dy < 60 ? Enum.Refresher.Default : Enum.Refresher.ReleaseToRefresh;
},
// 下拉刷新被触发事件
_onRefresherrefresh(e : RefresherEvent) {
this._handleRefresh();
},
// 处理用户下拉刷新
_handleRefresh() {
this.refresherStatus = Enum.Refresher.Loading;
this.refresherTriggered = true;
this.pageNo = this.defaultPageNo;
this.isFlag = true;
this.loadMoreStatus = Enum.More.Default;
this._emitQuery(this.pageNo, this.defaultPageSize);
},
// emit query事件
_emitQuery(pageNo : number, pageSize : number) {
this.isLoading = true;
const now = Date.now();
//防抖10s最多刷新一次
if (now - this.lastRefreshTime < 200) {
// 10秒内不允许再次刷新
setTimeout(() => {
this.endRefresh()
}, 100)
return;
}
this.lastRefreshTime = now;
this.$emit('query', pageNo, pageSize, this.isFlag);
//console.log("调用");
setTimeout(() => {
this.endRefresh()
}, 1000)
},
// 下拉刷新被复位事件
_onRefresherrestore(e : RefresherEvent) {
//console.log("下拉事件被结束")
},
// 处理加载更多数据
_handleLoadMore() {
if (!this.loadMoreEnabled || this.isLoading || this.loadMoreStatus === Enum.More.NoMore) {
return;
}
this.loadMoreStatus = Enum.More.Loading;
this.isFlag = false;
this.pageNo++;
this._emitQuery(this.pageNo, this.defaultPageSize);
},
// 直接结束下拉刷新状态
endRefresh() {
// 设置下拉刷新状态为结束
this.refresherTriggered = false;
this.refresherStatus = Enum.Refresher.Default;
this.isLoading = false;
},
// 滚动到底部事件
_onScrolltolower(e : ScrollToLowerEvent) {
if (!this.enableScrollToLower) return;
this._handleLoadMore();
},
// 监听滚动事件
_onScroll(e: ScrollEvent) {
this.oldScrollTop = e.detail.scrollTop;
},
// 请求结束(成功)调用此方法,将请求的结果数组传递给z-paging-x处理
complete(data: null | any[], type: string | null) {
if (type == null) {
const finalData: any[] = data === null ? [] : data;
this.endRefresh();
const currentData: any[] = [...finalData];
// customNoMore:-1代表交由z-paging-x自行判断;1代表没有更多了;0代表还有更多数据
if (this.customNoMore != -1) {
if (this.customNoMore == 1 || (this.customNoMore != 0 && finalData.length == 0)) {
this.loadMoreStatus = Enum.More.NoMore;
}
} else {
if (finalData.length == 0 || (finalData.length > 0 && finalData.length < this.defaultPageSize)) {
this.loadMoreStatus = Enum.More.NoMore;
} else {
this.loadMoreStatus = Enum.More.Default;
}
}
// 如果是第一页,则覆盖当前数据;如果是加载更多,则拼接数据
if (this.isFirstPage) {
// 使用临时变量保存旧数据
// 先设置新数据
this.dataList = currentData;
// 在下一个tick恢复滚动位置
this.$nextTick(() => {
this.scrollToY(0);
});
} else {
// 加载更多时直接拼接数据
this.dataList = this.dataList.concat(currentData);
}
} else {
this.swichSlot(type, data)
}
},
//【通过total判断是否有更多数据】请求成功调用此方法,将请求的结果传递给z-paging-x处理,第一个参数为请求结果数组,第二个参数为total(列表总数)
completeByTotal(data : null | any[], total : number) {
const finalData : any[] = data === null ? [] : data;
this.$nextTick(() => {
// console.log("total=" + finalData.length);
// console.log("total=" + this.isFirstPage);
// console.log("total="+this.dataList.length);
let nomore = false;
const realTotalDataCount = this.isFirstPage ? 0 : this.dataList.length;
const dataLength = finalData.length;
let exceedCount = realTotalDataCount + dataLength - total;
if (exceedCount >= 0) {
nomore = true;
// 仅截取total内部分的数据
exceedCount = this.defaultPageSize - exceedCount;
if (exceedCount > 0 && exceedCount < finalData.length) {
data = finalData.splice(0, exceedCount);
}
}
this.completeByNoMore(data, nomore);
})
},
scrollToY(y: number) {
// 强制重置scrollTop
this.scrollTop = -1;
// 使用nextTick确保DOM更新后再设置新的scrollTop
this.$nextTick(() => {
this.scrollTop = y;
});
},
//【自行判断是否有更多数据】请求成功调用此方法,将请求的结果传递给z-paging-x处理,第一个参数为请求结果数组,第二个参数为是否没有更多数据
completeByNoMore(data : null | any[], nomore : boolean) {
this.customNoMore = nomore == true ? 1 : 0;
this.complete(data, null);
},
// 刷新列表数据
reload() {
// 重置页码
this.pageNo = this.defaultPageNo;
// 重置加载更多状态
this.loadMoreStatus = Enum.More.Loading
// 先滚动到顶部
this.scrollToY(0);
// 发起查询
this.$nextTick(() => {
this._emitQuery(this.pageNo, this.defaultPageSize);
});
},
swichSlot(type : string, newValue : any[] | null) {
if (newValue == null) return;
switch (type) {
case 'slot1':
this.slot1 = newValue as any[];
break;
case 'slot2':
this.slot2 = newValue as any[];
break;
case 'slot3':
this.slot3 = newValue as any[];
break;
case 'slot4':
this.slot4 = newValue as any[];
break;
case 'slot5':
this.slot5 = newValue as any[];
break;
case 'slot6':
this.slot6 = newValue as any[];
break;
case 'slot7':
this.slot7 = newValue as any[];
break;
case 'slot8':
this.slot8 = newValue as any[];
break;
case 'slot9':
this.slot9 = newValue as any[];
break;
case 'slot10':
this.slot10 = newValue as any[];
break;
case 'dataList':
this.dataList = newValue as any[];
break;
}
},
}
}
</script>
<style lang="scss">
@import "./css/z-paging-main.css";
</style>
2 个回复
1***@qq.com (作者)
我已经试过了,HbuilderX 4.6.4版本没问题,4.7.6就回出问题
1***@qq.com (作者)
官方赶紧解决或者给解决方案啊