329 lines
12 KiB
JavaScript
329 lines
12 KiB
JavaScript
// [z-paging]滚动到底部加载更多模块
|
||
import u from '.././z-paging-utils'
|
||
import Enum from '.././z-paging-enum'
|
||
|
||
const ZPLoadMore = {
|
||
props: {
|
||
//自定义底部加载更多样式
|
||
loadingMoreCustomStyle: {
|
||
type: Object,
|
||
default: function() {
|
||
return u.gc('loadingMoreCustomStyle', {});
|
||
}
|
||
},
|
||
//自定义底部加载更多文字样式
|
||
loadingMoreTitleCustomStyle: {
|
||
type: Object,
|
||
default: function() {
|
||
return u.gc('loadingMoreTitleCustomStyle', {});
|
||
}
|
||
},
|
||
//自定义底部加载更多加载中动画样式
|
||
loadingMoreLoadingIconCustomStyle: {
|
||
type: Object,
|
||
default: function() {
|
||
return u.gc('loadingMoreLoadingIconCustomStyle', {});
|
||
}
|
||
},
|
||
//自定义底部加载更多加载中动画图标类型,可选flower或circle,默认为flower
|
||
loadingMoreLoadingIconType: {
|
||
type: String,
|
||
default: u.gc('loadingMoreLoadingIconType', 'flower')
|
||
},
|
||
//自定义底部加载更多加载中动画图标图片
|
||
loadingMoreLoadingIconCustomImage: {
|
||
type: String,
|
||
default: u.gc('loadingMoreLoadingIconCustomImage', '')
|
||
},
|
||
//底部加载更多加载中view是否展示旋转动画,默认为是
|
||
loadingMoreLoadingAnimated: {
|
||
type: Boolean,
|
||
default: u.gc('loadingMoreLoadingAnimated', true)
|
||
},
|
||
//是否启用加载更多数据(含滑动到底部加载更多数据和点击加载更多数据),默认为是
|
||
loadingMoreEnabled: {
|
||
type: Boolean,
|
||
default: u.gc('loadingMoreEnabled', true)
|
||
},
|
||
//是否启用滑动到底部加载更多数据,默认为是
|
||
toBottomLoadingMoreEnabled: {
|
||
type: Boolean,
|
||
default: u.gc('toBottomLoadingMoreEnabled', true)
|
||
},
|
||
//滑动到底部状态为默认状态时,以加载中的状态展示,默认为否。若设置为是,可避免滚动到底部看到默认状态然后立刻变为加载中状态的问题,但分页数量未超过一屏时,不会显示【点击加载更多】
|
||
loadingMoreDefaultAsLoading: {
|
||
type: [Boolean],
|
||
default: u.gc('loadingMoreDefaultAsLoading', false)
|
||
},
|
||
//滑动到底部"默认"文字,默认为【点击加载更多】
|
||
loadingMoreDefaultText: {
|
||
type: [String, Object],
|
||
default: u.gc('loadingMoreDefaultText', null)
|
||
},
|
||
//滑动到底部"加载中"文字,默认为【正在加载...】
|
||
loadingMoreLoadingText: {
|
||
type: [String, Object],
|
||
default: u.gc('loadingMoreLoadingText', null)
|
||
},
|
||
//滑动到底部"没有更多"文字,默认为【没有更多了】
|
||
loadingMoreNoMoreText: {
|
||
type: [String, Object],
|
||
default: u.gc('loadingMoreNoMoreText', null)
|
||
},
|
||
//滑动到底部"加载失败"文字,默认为【加载失败,点击重新加载】
|
||
loadingMoreFailText: {
|
||
type: [String, Object],
|
||
default: u.gc('loadingMoreFailText', null)
|
||
},
|
||
//当没有更多数据且分页内容未超出z-paging时是否隐藏没有更多数据的view,默认为否
|
||
hideLoadingMoreWhenNoMoreAndInsideOfPaging: {
|
||
type: Boolean,
|
||
default: u.gc('hideLoadingMoreWhenNoMoreAndInsideOfPaging', false)
|
||
},
|
||
//当没有更多数据且分页数组长度少于这个值时,隐藏没有更多数据的view,默认为0,代表不限制。
|
||
hideLoadingMoreWhenNoMoreByLimit: {
|
||
type: Number,
|
||
default: u.gc('hideLoadingMoreWhenNoMoreByLimit', 0)
|
||
},
|
||
//是否显示默认的加载更多text,默认为是
|
||
showDefaultLoadingMoreText: {
|
||
type: Boolean,
|
||
default: u.gc('showDefaultLoadingMoreText', true)
|
||
},
|
||
//是否显示没有更多数据的view
|
||
showLoadingMoreNoMoreView: {
|
||
type: Boolean,
|
||
default: u.gc('showLoadingMoreNoMoreView', true)
|
||
},
|
||
//是否显示没有更多数据的分割线,默认为是
|
||
showLoadingMoreNoMoreLine: {
|
||
type: Boolean,
|
||
default: u.gc('showLoadingMoreNoMoreLine', true)
|
||
},
|
||
//自定义底部没有更多数据的分割线样式
|
||
loadingMoreNoMoreLineCustomStyle: {
|
||
type: Object,
|
||
default: function() {
|
||
return u.gc('loadingMoreNoMoreLineCustomStyle', {});
|
||
},
|
||
},
|
||
//距底部/右边多远时(单位px),触发 scrolltolower 事件,默认为100rpx
|
||
lowerThreshold: {
|
||
type: [Number, String],
|
||
default: u.gc('lowerThreshold', '100rpx')
|
||
},
|
||
},
|
||
data() {
|
||
return {
|
||
//底部加载更多状态
|
||
loadingStatus: Enum.More.Default,
|
||
loadingStatusAfterRender: Enum.More.Default,
|
||
loadingMoreTimeStamp: 0,
|
||
loadingMoreDefaultSlot: null,
|
||
showLoadingMore: false,
|
||
customNoMore: -1,
|
||
}
|
||
},
|
||
computed: {
|
||
zPagingLoadMoreConfig() {
|
||
return {
|
||
status: this.loadingStatusAfterRender,
|
||
defaultAsLoading: this.loadingMoreDefaultAsLoading,
|
||
defaultThemeStyle: this.finalLoadingMoreThemeStyle,
|
||
customStyle: this.loadingMoreCustomStyle,
|
||
titleCustomStyle: this.loadingMoreTitleCustomStyle,
|
||
iconCustomStyle: this.loadingMoreLoadingIconCustomStyle,
|
||
loadingIconType: this.loadingMoreLoadingIconType,
|
||
loadingIconCustomImage: this.loadingMoreLoadingIconCustomImage,
|
||
loadingAnimated: this.loadingMoreLoadingAnimated,
|
||
showNoMoreLine: this.showLoadingMoreNoMoreLine,
|
||
noMoreLineCustomStyle: this.loadingMoreNoMoreLineCustomStyle,
|
||
defaultText: this.finalLoadingMoreDefaultText,
|
||
loadingText: this.finalLoadingMoreLoadingText,
|
||
noMoreText: this.finalLoadingMoreNoMoreText,
|
||
failText: this.finalLoadingMoreFailText,
|
||
hideContent: !this.loadingMoreDefaultAsLoading && this.listRendering
|
||
};
|
||
},
|
||
finalLoadingMoreThemeStyle() {
|
||
return this.loadingMoreThemeStyle.length ? this.loadingMoreThemeStyle : this.defaultThemeStyle;
|
||
},
|
||
showLoadingMoreDefault() {
|
||
return this._showLoadingMore('Default');
|
||
},
|
||
showLoadingMoreLoading() {
|
||
return this._showLoadingMore('Loading');
|
||
},
|
||
showLoadingMoreNoMore() {
|
||
return this._showLoadingMore('NoMore');
|
||
},
|
||
showLoadingMoreFail() {
|
||
return this._showLoadingMore('Fail');
|
||
},
|
||
showLoadingMoreCustom() {
|
||
return this._showLoadingMore('Custom');
|
||
}
|
||
},
|
||
methods: {
|
||
//手动触发上拉加载更多(非必须,可依据具体需求使用)
|
||
doLoadMore(type) {
|
||
this._onLoadingMore(type);
|
||
},
|
||
//通过@scroll事件检测是否滚动到了底部
|
||
_checkScrolledToBottom(scrollDiff, checked = false) {
|
||
if (this.checkScrolledToBottomTimeOut) {
|
||
clearTimeout(this.checkScrolledToBottomTimeOut);
|
||
this.checkScrolledToBottomTimeOut = null;
|
||
}
|
||
if (this.cacheScrollNodeHeight === -1) {
|
||
this._getNodeClientRect('.zp-scroll-view').then((res) => {
|
||
if (res) {
|
||
let pageScrollNodeHeight = res[0].height;
|
||
this.cacheScrollNodeHeight = pageScrollNodeHeight;
|
||
if (scrollDiff - pageScrollNodeHeight <= this.finalLowerThreshold) {
|
||
this._onLoadingMore('toBottom');
|
||
}
|
||
}
|
||
});
|
||
} else {
|
||
if (scrollDiff - this.cacheScrollNodeHeight <= this.finalLowerThreshold) {
|
||
this._onLoadingMore('toBottom');
|
||
} else if (scrollDiff - this.cacheScrollNodeHeight <= 500 && !checked) {
|
||
this.checkScrolledToBottomTimeOut = setTimeout(() => {
|
||
this._getNodeClientRect('.zp-scroll-view', true, true).then((res) => {
|
||
this.oldScrollTop = res[0].scrollTop;
|
||
const newScrollDiff = res[0].scrollHeight - this.oldScrollTop;
|
||
this._checkScrolledToBottom(newScrollDiff, true);
|
||
})
|
||
}, 150)
|
||
}
|
||
}
|
||
},
|
||
//触发加载更多时调用,from:0-滑动到底部触发;1-点击加载更多触发
|
||
_onLoadingMore(from = 'click') {
|
||
if (from === 'toBottom') {
|
||
if (!this.scrollToBottomBounceEnabled) {
|
||
if (this.scrollEnable) {
|
||
this.scrollEnable = false;
|
||
this.$nextTick(() => {
|
||
this.scrollEnable = true;
|
||
})
|
||
}
|
||
}
|
||
//#ifdef APP-VUE || H5
|
||
if (this.isIos) {
|
||
this.renderPropUsePageScroll = -1;
|
||
this.$nextTick(() => {
|
||
this.renderPropUsePageScroll = this.usePageScroll;
|
||
})
|
||
}
|
||
//#endif
|
||
}
|
||
this.$emit('scrolltolower', from);
|
||
if (from === 'toBottom' && (!this.toBottomLoadingMoreEnabled || this.useChatRecordMode)) return;
|
||
if (this.refresherOnly || !this.loadingMoreEnabled || !(this.loadingStatus === Enum.More.Default || this.loadingStatus === Enum.More.Fail) || this.loading) return;
|
||
// #ifdef MP-WEIXIN
|
||
if (!this.isIos && !this.refresherOnly && !this.usePageScroll) {
|
||
const currentTimestamp = u.getTime();
|
||
if (this.loadingMoreTimeStamp > 0 && currentTimestamp - this.loadingMoreTimeStamp < 100) {
|
||
this.loadingMoreTimeStamp = 0;
|
||
return;
|
||
}
|
||
}
|
||
// #endif
|
||
this._doLoadingMore();
|
||
},
|
||
//处理开始加载更多
|
||
_doLoadingMore() {
|
||
if (this.pageNo >= this.defaultPageNo && this.loadingStatus !== Enum.More.NoMore) {
|
||
this.pageNo++;
|
||
this._startLoading(false);
|
||
if (this.isLocalPaging) {
|
||
this._localPagingQueryList(this.pageNo, this.defaultPageSize, this.localPagingLoadingTime, (res) => {
|
||
this.addData(res);
|
||
})
|
||
} else {
|
||
this._emitQuery(this.pageNo, this.defaultPageSize, Enum.QueryFrom.LoadingMore);
|
||
this._callMyParentQuery();
|
||
}
|
||
this.loadingType = Enum.LoadingType.LoadingMore;
|
||
}
|
||
},
|
||
//(预处理)判断当没有更多数据且分页内容未超出z-paging时是否显示没有更多数据的view
|
||
_preCheckShowLoadingMoreWhenNoMoreAndInsideOfPaging(newVal, scrollViewNode, pagingContainerNode) {
|
||
if (this.loadingStatus === Enum.More.NoMore && this.hideLoadingMoreWhenNoMoreByLimit > 0 && newVal.length) {
|
||
this.showLoadingMore = newVal.length > this.hideLoadingMoreWhenNoMoreByLimit;
|
||
} else if ((this.loadingStatus === Enum.More.NoMore && this.hideLoadingMoreWhenNoMoreAndInsideOfPaging && newVal.length) || (this.insideMore && this.insideOfPaging !== false && newVal.length)) {
|
||
this.$nextTick(() => {
|
||
this._checkShowLoadingMoreWhenNoMoreAndInsideOfPaging(newVal, scrollViewNode, pagingContainerNode);
|
||
})
|
||
if (this.insideMore && this.insideOfPaging !== false && newVal.length) {
|
||
this.showLoadingMore = newVal.length;
|
||
}
|
||
} else {
|
||
this.showLoadingMore = newVal.length;
|
||
}
|
||
},
|
||
//判断当没有更多数据且分页内容未超出z-paging时是否显示没有更多数据的view
|
||
async _checkShowLoadingMoreWhenNoMoreAndInsideOfPaging(totalData, oldScrollViewNode, oldPagingContainerNode) {
|
||
try {
|
||
const scrollViewNode = oldScrollViewNode || await this._getNodeClientRect('.zp-scroll-view');
|
||
if (this.usePageScroll) {
|
||
if (scrollViewNode) {
|
||
const scrollViewTotalH = scrollViewNode[0].top + scrollViewNode[0].height;
|
||
this.insideOfPaging = scrollViewTotalH < this.windowHeight;
|
||
if (this.hideLoadingMoreWhenNoMoreAndInsideOfPaging) {
|
||
this.showLoadingMore = !this.insideOfPaging;
|
||
}
|
||
this._updateInsideOfPaging();
|
||
}
|
||
} else {
|
||
let pagingContainerH = 0;
|
||
let scrollViewH = 0;
|
||
const pagingContainerNode = oldPagingContainerNode || await this._getNodeClientRect('.zp-paging-container-content');
|
||
if (pagingContainerNode) {
|
||
pagingContainerH = pagingContainerNode[0].height;
|
||
}
|
||
if (scrollViewNode) {
|
||
scrollViewH = scrollViewNode[0].height;
|
||
}
|
||
this.insideOfPaging = pagingContainerH < scrollViewH;
|
||
if (this.hideLoadingMoreWhenNoMoreAndInsideOfPaging) {
|
||
this.showLoadingMore = !this.insideOfPaging;
|
||
}
|
||
this._updateInsideOfPaging();
|
||
}
|
||
} catch (e) {
|
||
this.insideOfPaging = !totalData.length;
|
||
if (this.hideLoadingMoreWhenNoMoreAndInsideOfPaging) {
|
||
this.showLoadingMore = !this.insideOfPaging;
|
||
}
|
||
this._updateInsideOfPaging();
|
||
}
|
||
},
|
||
//是否要展示上拉加载更多view
|
||
_showLoadingMore(type) {
|
||
if (!(this.loadingStatus === Enum.More.Default ? this.nShowBottom : true) || !this.totalData.length) return false;
|
||
if (((!this.showLoadingMoreWhenReload || this.isUserPullDown || this.loadingStatus !== Enum.More.Loading) && !this.showLoadingMore) ||
|
||
(!this.loadingMoreEnabled && (!this.showLoadingMoreWhenReload || this.isUserPullDown || this.loadingStatus !== Enum.More.Loading)) ||
|
||
this.refresherOnly) return false;
|
||
if (this.useChatRecordMode && type !== 'Loading') return false;
|
||
if (!this.$slots) return false;
|
||
if (type === 'Custom') {
|
||
return this.showDefaultLoadingMoreText && !(this.loadingStatus === Enum.More.NoMore && !this.showLoadingMoreNoMoreView);
|
||
}
|
||
const res = this.loadingStatus === Enum.More[type] && this.$slots[`loadingMore${type}`] && (type === 'NoMore' ? this.showLoadingMoreNoMoreView : true);
|
||
if (res) {
|
||
// #ifdef APP-NVUE
|
||
if (!this.isIos) {
|
||
this.nLoadingMoreFixedHeight = false;
|
||
}
|
||
// #endif
|
||
}
|
||
return res;
|
||
},
|
||
}
|
||
}
|
||
|
||
export default ZPLoadMore;
|