update:z-paging from 2.7.11 => 2.8.6

This commit is contained in:
YunaiV
2025-04-29 11:53:42 +08:00
parent c7d101cd05
commit 68ed6e1810
33 changed files with 3021 additions and 933 deletions
@@ -18,6 +18,14 @@
</template>
<script>
/**
* z-paging-cell 组件
* @description 用于兼容 nvue 和 vue 中的 cell 渲染。因为在 nvue 中 z-paging 内置的是 list,因此列表 item 必须使用 cell 包住;在 vue 中不能使用 cell,否则会报组件找不到的错误。此子组件为了兼容这两种情况,内部作了条件编译处理。
* @tutorial https://z-paging.zxlee.cn/api/sub-components/main.html#z-paging-cell配置
* @notice 以下为 z-paging-cell 的配置项
* @property {Object} cellStyle cell 样式,默认为 {}
* @example <z-paging-cell :cellStyle="{ backgroundColor: '#f0f0f0' }"></z-paging-cell>
*/
export default {
name: "z-paging-cell",
props: {
@@ -17,6 +17,26 @@
<script>
import zStatic from '../z-paging/js/z-paging-static'
/**
* z-paging-empty-view 空数据组件
* @description 通用的 z-paging 空数据组件
* @tutorial https://z-paging.zxlee.cn/api/sub-components/main.html#z-paging-empty-view配置
* @property {Boolean} emptyViewFixed 空数据图片是否铺满 z-paging,默认为 false。若设置为 true,则为填充满 z-paging 的剩余部分
* @property {String} emptyViewText 空数据图描述文字,默认为 '没有数据哦~'
* @property {String} emptyViewImg 空数据图图片,默认使用 z-paging 内置的图片 (建议使用绝对路径,开头不要添加 "@",请以 "/" 开头)
* @property {String} emptyViewReloadText 空数据图点击重新加载文字,默认为 '重新加载'
* @property {Object} emptyViewStyle 空数据图样式,可设置空数据 view 的 top 等,如: empty-view-style="{'top':'100rpx'}" (如果空数据图不是 fixed 布局,则此处是 margin-top),默认为 {}
* @property {Object} emptyViewImgStyle 空数据图 img 样式,默认为 {}
* @property {Object} emptyViewTitleStyle 空数据图描述文字样式,默认为 {}
* @property {Object} emptyViewReloadStyle 空数据图重新加载按钮样式,默认为 {}
* @property {Boolean} showEmptyViewReload 是否显示空数据图重新加载按钮(无数据时),默认为 false
* @property {Boolean} isLoadFailed 是否是加载失败,默认为 false
* @property {String} unit 空数据图中布局的单位,默认为 'rpx'
* @event {Function} reload 点击了重新加载按钮
* @event {Function} viewClick 点击了空数据图 view
* @example <z-paging-empty-view empty-view-text="暂无数据" />
*/
export default {
name: "z-paging-empty-view",
data() {
@@ -26,6 +26,23 @@
<script>
import zPaging from '../z-paging/z-paging'
/**
* z-paging-swiper-item 组件
* @description swiper+list极简写法中使用到,实际上就是对普通的swiper+list中swiper-item的包装封装,用以简化写法,但个性化配置局限较多
* @tutorial https://z-paging.zxlee.cn/api/sub-components/main.html#z-paging-swiper-item配置
* @notice 以下为 z-paging-swiper-item 的配置项
* @property {Number} tabIndex 当前组件的 index,也就是当前组件是 swiper 中的第几个,默认为 0
* @property {Number} currentIndex 当前 swiper 切换到第几个 index,默认为 0
* @property {Boolean} useVirtualList 是否使用虚拟列表,默认为 false
* @property {Boolean} useInnerList 是否在 z-paging 内部循环渲染列表(内置列表),默认为 false。若 useVirtualList 为 true,则此项恒为 true
* @property {String} cellKeyName 内置列表 cell 的 key 名称,仅 nvue 有效,在 nvue 中开启 useInnerList 时必须填此项,默认为 ''
* @property {Object} innerListStyle innerList 样式,默认为 {}
* @property {Number|String} preloadPage 预加载的列表可视范围(列表高度)页数,默认为 12。此数值越大,则虚拟列表中加载的 dom 越多,内存消耗越大(会维持在一个稳定值),但增加预加载页面数量可缓解快速滚动短暂白屏问题
* @property {String} cellHeightMode 虚拟列表 cell 高度模式,默认为 'fixed',也就是每个 cell 高度完全相同,将以第一个 cell 高度为准进行计算。可选值【dynamic】,即代表高度是动态非固定的,【dynamic】性能低于【fixed】
* @property {Number|String} virtualListCol 虚拟列表列数,默认为 1。常用于每行有多列的情况,例如每行有 2 列数据,需要将此值设置为 2
* @property {Number|String} virtualScrollFps 虚拟列表 scroll 取样帧率,默认为 60,过高可能出现卡顿等问题
* @example <z-paging-swiper-item ref="swiperItem" :tabIndex="index" :currentIndex="current" @query="queryList" @updateList="updateList"></z-paging-swiper-item>
*/
export default {
name: "z-paging-swiper-item",
components: { zPaging },
@@ -28,6 +28,15 @@
<script>
import commonLayoutModule from '../z-paging/js/modules/common-layout'
/**
* z-paging-swiper 组件
* @description 在 swiper 中使用 z-paging 时(左右滑动切换列表),在根节点使用 z-paging-swiper,其相当于一个 view 容器,默认铺满全屏,可免计算高度直接插入 swiper 的视图容器。
* @tutorial https://z-paging.zxlee.cn/api/sub-components/main.html#z-paging-swiper配置
* @property {Boolean} fixed 是否使用 fixed 布局,默认为 true
* @property {Boolean} safeAreaInsetBottom 是否开启底部安全区域适配,默认为 false
* @property {Object} swiperStyle z-paging-swiper 样式,默认为 {}
* @example <z-paging-swiper :safeAreaInsetBottom="true"></z-paging-swiper>
*/
export default {
name: "z-paging-swiper",
mixins: [commonLayoutModule],
@@ -57,7 +66,7 @@
},
mounted() {
this.$nextTick(() => {
this.systemInfo = uni.getSystemInfoSync();
this.systemInfo = this._getSystemInfoSync();
setTimeout(this.updateFixedLayout, 100)
})
// #ifndef APP-PLUS
@@ -55,8 +55,12 @@
},
// 底部加载更多文字
ownLoadingMoreText() {
const statusTextArr = [this.c.defaultText,this.c.loadingText,this.c.noMoreText,this.c.failText];
return statusTextArr[this.finalStatus];
return {
[this.M.Default]: this.c.defaultText,
[this.M.Loading]: this.c.loadingText,
[this.M.NoMore]: this.c.noMoreText,
[this.M.Fail]: this.c.failText,
}[this.finalStatus];
},
// 底部加载更多状态
finalStatus() {
@@ -39,7 +39,6 @@
data() {
return {
R: Enum.Refresher,
isIos: uni.getSystemInfoSync().platform === 'ios',
refresherTimeText: '',
zTheme: {
title: { white: '#efefef', black: '#555555' },
@@ -51,20 +50,27 @@
};
},
props: ['status', 'defaultThemeStyle', 'defaultText', 'pullingText', 'refreshingText', 'completeText', 'goF2Text', 'defaultImg', 'pullingImg',
'refreshingImg', 'completeImg', 'refreshingAnimated', 'showUpdateTime', 'updateTimeKey', 'imgStyle', 'titleStyle', 'updateTimeStyle', 'updateTimeTextMap', 'unit'
'refreshingImg', 'completeImg', 'refreshingAnimated', 'showUpdateTime', 'updateTimeKey', 'imgStyle', 'titleStyle', 'updateTimeStyle', 'updateTimeTextMap', 'unit', 'isIos'
],
computed: {
ts() {
return this.defaultThemeStyle;
},
// 当前状态数组
statusTextArr() {
// 当前状态Map
statusTextMap() {
this.updateTime();
return [this.defaultText, this.pullingText, this.refreshingText, this.completeText, this.goF2Text];
const { R, defaultText, pullingText, refreshingText, completeText, goF2Text } = this;
return {
[R.Default]: defaultText,
[R.ReleaseToRefresh]: pullingText,
[R.Loading]: refreshingText,
[R.Complete]: completeText,
[R.GoF2]: goF2Text,
};
},
// 当前状态文字
currentTitle() {
return this.statusTextArr[this.status] || this.defaultText;
return this.statusTextMap[this.status] || this.defaultText;
},
// 左侧图片class
leftImageClass() {
@@ -193,6 +193,10 @@
z-index: 999;
}
.zp-back-to-top-img-inversion {
transform: rotate(180deg);
}
.zp-empty-view {
/* #ifdef APP-NVUE */
height: 100%;
@@ -89,10 +89,10 @@ export default {
!callbacked && this._handleToTop();
})
},
// 处理滚动到顶部
// 处理滚动到顶部(聊天记录模式中为滚动到底部)
_handleToTop() {
!this.backToTopWithAnimate && this._checkShouldShowBackToTop(0);
this.scrollToTop(this.backToTopWithAnimate);
!this.useChatRecordMode ? this.scrollToTop(this.backToTopWithAnimate) : this.scrollToBottom(this.backToTopWithAnimate);
},
// 判断是否要显示返回顶部按钮
_checkShouldShowBackToTop(scrollTop) {
@@ -1,4 +1,5 @@
// [z-paging]通用布局相关模块
import u from '.././z-paging-utils'
// #ifdef APP-NVUE
const weexDom = weex.requireModule('dom');
@@ -40,7 +41,7 @@ export default {
isOldWebView() {
// #ifndef APP-NVUE || MP-KUAISHOU
try {
const systemInfos = uni.getSystemInfoSync().system.split(' ');
const systemInfos = u.getSystemInfoSync(true).system.split(' ');
const deviceType = systemInfos[0];
const version = parseInt(systemInfos[1]);
if ((deviceType === 'iOS' && version <= 10) || (deviceType === 'Android' && version <= 6)) {
@@ -78,7 +79,7 @@ export default {
// 更新fixed模式下z-paging的布局
updateFixedLayout() {
this.fixed && this.$nextTick(() => {
this.systemInfo = uni.getSystemInfoSync();
this.systemInfo = u.getSystemInfoSync();
})
},
// 获取节点尺寸
@@ -106,6 +107,12 @@ export default {
//#ifdef MP-ALIPAY
inDom = false;
//#endif
/*
inDom可能是true、false,也可能是具体的dom节点
如果inDom不为false,则使用uni.createSelectorQuery().in()进行查询,如果inDom为true,则in中的是this,否则in中的为具体的dom
如果inDom为false,则使用uni.createSelectorQuery()进行查询
*/
let res = !!inDom ? uni.createSelectorQuery().in(inDom === true ? this : inDom) : uni.createSelectorQuery();
scrollOffset ? res.select(select).scrollOffset() : res.select(select).boundingClientRect();
return new Promise((resolve, reject) => {
@@ -136,6 +143,10 @@ export default {
this.cssSafeAreaInsetBottom = res ? res[0].height : -1;
res && success && success();
});
},
// 同步获取系统信息,兼容不同平台(供z-paging-swiper使用)
_getSystemInfoSync(useCache = false) {
return u.getSystemInfoSync(useCache);
}
}
}
@@ -8,7 +8,7 @@ export default {
props: {
// 自定义初始的pageNo,默认为1
defaultPageNo: {
type: [Number, String],
type: Number,
default: u.gc('defaultPageNo', 1),
observer: function(newVal) {
this.pageNo = newVal;
@@ -16,7 +16,7 @@ export default {
},
// 自定义pageSize,默认为10
defaultPageSize: {
type: [Number, String],
type: Number,
default: u.gc('defaultPageSize', 10),
validator: (value) => {
if (value <= 0) u.consoleErr('default-page-size必须大于0');
@@ -473,14 +473,10 @@ export default {
if (!isLocal && tempIsUserPullDown && this.isFirstPage) {
this.isUserPullDown = false;
}
if (!this.isFirstPage) {
this.listRendering = true;
this.$nextTick(() => {
u.delay(() => this.listRendering = false);
})
} else {
this.listRendering = false;
}
this.listRendering = true;
this.$nextTick(() => {
u.delay(() => this.listRendering = false);
})
let dataTypeRes = this._checkDataType(data, success, isLocal);
data = dataTypeRes.data;
success = dataTypeRes.success;
@@ -511,7 +507,9 @@ export default {
const localPageNo = this.defaultPageNo;
const localPageSize = this.queryFrom !== Enum.QueryFrom.Refresh ? this.defaultPageSize : this.currentRefreshPageSize;
this._localPagingQueryList(localPageNo, localPageSize, 0, res => {
this.completeByTotal(res, this.totalLocalPagingList.length);
u.delay(() => {
this.completeByTotal(res, this.totalLocalPagingList.length);;
}, 0)
})
} else {
// 如果当前不是本地分页,则按照正常分页逻辑进行数据处理&emit数据
@@ -538,7 +536,7 @@ export default {
this._callDataPromise(false);
this.loadingStatus = Enum.More.Fail;
this.isHandlingRefreshToPage = false;
if (this.loadingType === Enum.LoadingType.LoadingMore) {
if (this.loadingType === Enum.LoadingType.LoadMore) {
this.pageNo --;
}
}
@@ -7,18 +7,12 @@ import u from '.././z-paging-utils'
import c from '.././z-paging-constant'
import interceptor from '../z-paging-interceptor'
const language = uni.getSystemInfoSync().language;
export default {
data() {
return {
language
}
},
computed: {
finalLanguage() {
try {
const local = uni.getLocale();
const language = this.language;
const language = this.systemInfo.appLanguage;
return local === 'auto' ? interceptor._handleLanguage2Local(language, this._language2Local(language)) : local;
} catch (e) {
// 如果获取系统本地语言异常,则默认返回中文,uni.getLocale在部分低版本HX或者cli中可能报找不到的问题
@@ -179,12 +179,16 @@ export default {
// 是否显示自定义状态下的底部加载更多
showLoadingMoreCustom() {
return this._showLoadingMore('Custom');
}
},
// 底部加载更多固定高度
loadingMoreFixedHeight() {
return u.addUnit('80rpx', this.unit);
},
},
methods: {
// 页面滚动到底部时通知z-paging进行进一步处理
pageReachBottom() {
!this.useChatRecordMode && this._onLoadingMore('toBottom');
!this.useChatRecordMode && this.toBottomLoadingMoreEnabled && this._onLoadingMore('toBottom');
},
// 手动触发上拉加载更多(非必须,可依据具体需求使用)
doLoadMore(type) {
@@ -240,7 +244,7 @@ export default {
}
}
},
// 触发加载更多时调用,from:toBottom-滑动到底部触发;1、click-点击加载更多触发
// 触发加载更多时调用,from:toBottom-滑动到底部触发;click-点击加载更多触发
_onLoadingMore(from = 'click') {
// 如果是ios并且是滚动到底部的,则在滚动到底部时候尝试将列表设置为禁止滚动然后设置为允许滚动,以禁止底部bounce的效果
if (this.isIos && from === 'toBottom' && !this.scrollToBottomBounceEnabled && this.scrollEnable) {
@@ -250,7 +254,7 @@ export default {
})
}
// emit scrolltolower
this.$emit('scrolltolower', from);
this._emitScrollEvent('scrolltolower');
// 如果是只使用下拉刷新 或者 禁用底部加载更多 或者 底部加载更多不是默认状态或加载失败状态 或者 是加载中状态 或者 空数据图已经展示了,则return,不触发内部加载更多逻辑
if (this.refresherOnly || !this.loadingMoreEnabled || !(this.loadingStatus === Enum.More.Default || this.loadingStatus === Enum.More.Fail) || this.loading || this.showEmpty) return;
// #ifdef MP-WEIXIN
@@ -275,15 +279,15 @@ export default {
// 如果是本地分页,则在组件内部对数据进行分页处理,不触发@query事件
this._localPagingQueryList(this.pageNo, this.defaultPageSize, this.localPagingLoadingTime, res => {
this.completeByTotal(res, this.totalLocalPagingList.length);
this.queryFrom = Enum.QueryFrom.LoadingMore;
this.queryFrom = Enum.QueryFrom.LoadMore;
})
} else {
// emit @query相关加载更多事件
this._emitQuery(this.pageNo, this.defaultPageSize, Enum.QueryFrom.LoadingMore);
this._emitQuery(this.pageNo, this.defaultPageSize, Enum.QueryFrom.LoadMore);
this._callMyParentQuery();
}
// 设置当前加载状态为底部加载更多状态
this.loadingType = Enum.LoadingType.LoadingMore;
this.loadingType = Enum.LoadingType.LoadMore;
}
},
// (预处理)判断当没有更多数据且分页内容未超出z-paging时是否显示没有更多数据的view
@@ -66,7 +66,7 @@ export default {
nLoadingMoreFixedHeight: false,
nShowRefresherRevealHeight: 0,
nOldShowRefresherRevealHeight: -1,
nRefresherWidth: uni.upx2px(750),
nRefresherWidth: u.rpx2px(750),
nF2Opacity: 0
}
},
@@ -138,6 +138,19 @@ export default {
// 列表滚动结束
_nOnScrollend(e) {
this.$emit('scrollend', e);
// 判断是否滚动到顶部了
if (e?.contentOffset?.y >= 0) {
this._emitScrollEvent('scrolltoupper');
}
// 判断是否滚动到底部了
this._getNodeClientRect('.zp-n-list').then(node => {
if (node) {
if (e?.contentSize?.height + e?.contentOffset?.y <= node[0].height) {
this._emitScrollEvent('scrolltolower');
}
}
})
},
// 下拉刷新刷新中
_nOnRrefresh() {
@@ -349,7 +349,7 @@ export default {
return this.refresherTriggered;
},
showRefresher() {
const showRefresher = this.finalRefresherEnabled && this.useCustomRefresher;
const showRefresher = this.finalRefresherEnabled || this.useCustomRefresher && !this.useChatRecordMode;
// #ifndef APP-NVUE
this.active && this.customRefresherHeight === -1 && showRefresher && this.updateCustomRefresherHeight();
// #endif
@@ -405,7 +405,7 @@ export default {
this.isUserReload = !isUserPullDown;
this._startLoading(true);
this.refresherTriggered = true;
if(this.reloadWhenRefresh && isUserPullDown){
if (this.reloadWhenRefresh && isUserPullDown) {
this.useChatRecordMode ? this._onLoadingMore('click') : this._reload(false, false, isUserPullDown);
}
},
@@ -439,7 +439,7 @@ export default {
this._cleanRefresherEndTimeout();
},
// 非appvue或微信小程序或QQ小程序或h5平台,使用js控制下拉刷新
// 非app-vue或微信小程序或QQ小程序或h5平台,使用js控制下拉刷新
// #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5
// touch中
_refresherTouchmove(e) {
@@ -615,7 +615,9 @@ export default {
// 下拉刷新结束
_refresherEnd(shouldEndLoadingDelay = true, fromAddData = false, isUserPullDown = false, setLoading = true) {
if (this.loadingType === Enum.LoadingType.Refresher) {
// 计算当前下拉刷新结束需要延迟的时间
const refresherCompleteDelay = (fromAddData && (isUserPullDown || this.showRefresherWhenReload)) ? this.refresherCompleteDelay : 0;
// 如果延迟时间大于0,则展示刷新结束状态,否则直接展示默认状态
const refresherStatus = refresherCompleteDelay > 0 ? Enum.Refresher.Complete : Enum.Refresher.Default;
if (this.finalShowRefresherWhenReload) {
const stackCount = this.refresherRevealStackCount;
@@ -624,7 +626,12 @@ export default {
}
this._cleanRefresherEndTimeout();
this.refresherEndTimeout = u.delay(() => {
// 更新下拉刷新状态
this.refresherStatus = refresherStatus;
// 如果当前下拉刷新状态不是刷新结束,则认为其不在刷新结束状态
if (refresherStatus !== Enum.Refresher.Complete) {
this.isRefresherInComplete = false;
}
}, this.refresherStatus !== Enum.Refresher.Default && refresherStatus === Enum.Refresher.Default ? this.refresherCompleteDuration : 0);
// #ifndef APP-NVUE
@@ -762,7 +769,7 @@ export default {
},
// 触发下拉刷新
_doRefresherLoad(isUserPullDown = true) {
this._onRefresh(false,isUserPullDown);
this._onRefresh(false, isUserPullDown);
this.loading = true;
},
// #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5
@@ -53,6 +53,8 @@ export default {
return {
scrollTop: 0,
oldScrollTop: 0,
scrollLeft: 0,
oldScrollLeft: 0,
scrollViewStyle: {},
scrollViewContainerStyle: {},
scrollViewInStyle: {},
@@ -166,17 +168,24 @@ export default {
this._scrollIntoViewByNodeTop(nodeTop, offset, animate);
})
},
// 滚动到指定位置(vue中有效)。y为与顶部的距离,单位为px;offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否
// y轴滚动到指定位置(vue中有效)。y为与顶部的距离,单位为px;offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否
scrollToY(y, offset, animate) {
this.scrollTop = this.oldScrollTop;
this.$nextTick(() => {
this._scrollToY(y, offset, animate);
})
},
// x轴滚动到指定位置(非页面滚动且在vue中有效)。x为与左侧的距离,单位为px;offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否
scrollToX(x, offset, animate) {
this.scrollLeft = this.oldScrollLeft;
this.$nextTick(() => {
this._scrollToX(x, offset, animate);
})
},
// 滚动到指定view(nvue中和虚拟列表中有效)。index为需要滚动的view的index(第几个,从0开始)offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否
scrollIntoViewByIndex(index, offset, animate) {
if (index >= this.realTotalData.length) {
u.consoleErr('当前滚动的index超出已渲染列表长度,请先通过refreshToPage加载到对应index页并等待渲染成功后再调用此方法!')
u.consoleErr('当前滚动的index超出已渲染列表长度,请先通过refreshToPage加载到对应index页并等待渲染成功后再调用此方法!');
return;
}
this.$nextTick(() => {
@@ -232,7 +241,7 @@ export default {
// 当滚动到顶部时
_onScrollToUpper() {
this.$emit('scrolltoupper');
this._emitScrollEvent('scrolltoupper');
this.$emit('scrollTopChange', 0);
this.$nextTick(() => {
this.oldScrollTop = 0;
@@ -240,7 +249,9 @@ export default {
},
// 当滚动到底部时
_onScrollToLower(e) {
(!e.detail || !e.detail.direction || e.detail.direction === 'bottom') && this._onLoadingMore(this.useChatRecordMode ? 'click' : 'toBottom')
(!e.detail || !e.detail.direction || e.detail.direction === 'bottom')
&& this.toBottomLoadingMoreEnabled
&& this._onLoadingMore(this.useChatRecordMode ? 'click' : 'toBottom')
},
// 滚动到顶部
_scrollToTop(animate = true, isPrivate = true) {
@@ -379,7 +390,7 @@ export default {
this._scrollToY(nodeTop, offset, animate, true);
}
},
// 滚动到指定位置
// y轴滚动到指定位置
_scrollToY(y, offset = 0, animate = false, addScrollTop = false) {
this._updatePrivateScrollWithAnimation(animate);
u.delay(() => {
@@ -400,19 +411,40 @@ export default {
}
}, 10)
},
// x轴滚动到指定位置
_scrollToX(x, offset = 0, animate = false) {
this._updatePrivateScrollWithAnimation(animate);
u.delay(() => {
if (!this.usePageScroll) {
this.scrollLeft = x - offset;
} else {
u.consoleErr('使用页面滚动时不支持scrollToX');
}
}, 10)
},
// scroll-view滚动中
_scroll(e) {
this.$emit('scroll', e);
const scrollTop = e.detail.scrollTop;
const { scrollTop, scrollLeft } = e.detail;
// #ifndef APP-NVUE
this.finalUseVirtualList && this._updateVirtualScroll(scrollTop, this.oldScrollTop - scrollTop);
// #endif
this.oldScrollTop = scrollTop;
this.oldScrollLeft = scrollLeft;
// 滚动区域内容的总高度 - 当前滚动的scrollTop = 当前滚动区域的顶部与内容底部的距离
const scrollDiff = e.detail.scrollHeight - this.oldScrollTop;
// 在非ios平台滚动中,再次验证一下是否滚动到了底部。因为在一些安卓设备中,有概率滚动到底部不触发@scrolltolower事件,因此添加双重检测逻辑
!this.isIos && this._checkScrolledToBottom(scrollDiff);
},
// emit scrolltolower/scrolltoupper事件
_emitScrollEvent(type) {
const reversedType = type === 'scrolltolower' ? 'scrolltoupper' : 'scrolltolower';
const eventType = this.useChatRecordMode && !this.isChatRecordModeAndNotInversion
? reversedType
: type;
this.$emit(eventType);
},
// 更新内置的scroll-view是否启用滚动动画
_updatePrivateScrollWithAnimation(animate) {
this.privateScrollWithAnimation = animate ? 1 : 0;
@@ -74,6 +74,17 @@ export default {
type: [Number, String],
default: u.gc('virtualScrollFps', 80)
},
// 虚拟列表cell id的前缀,适用于一个页面有多个虚拟列表的情况,用以区分不同虚拟列表cell的id,注意:请勿传数字或以数字开头的字符串。如设置为list1,则cell的id应为:list1-zp-id-${item.zp_index}
virtualCellIdPrefix: {
type: String,
default: u.gc('virtualCellIdPrefix', '')
},
// 虚拟列表是否使用swiper-item包裹,默认为否,此属性为了解决vue3+(微信小程序或QQ小程序)中,使用非内置列表写法时,若z-paging在swiper-item内存在无法获取slot插入的cell高度进而导致虚拟列表失败的问题
// 仅vue3+(微信小程序或QQ小程序)+非内置列表写法虚拟列表有效,其他情况此属性设置任何值都无效,所以如果您在swiper-item内使用z-paging的非内置虚拟列表写法,将此属性设置为true即可
virtualInSwiperSlot: {
type: Boolean,
default: false
},
},
data() {
return {
@@ -110,6 +121,10 @@ export default {
virtualList(newVal){
this.$emit('update:virtualList', newVal);
this.$emit('virtualListChange', newVal);
},
// 监听虚拟列表顶部占位高度改变并emit
virtualPlaceholderTopHeight(newVal) {
this.$emit('virtualTopHeightChange', newVal);
}
},
computed: {
@@ -139,17 +154,31 @@ export default {
finalFixedCellHeight() {
return u.convertToPx(this.fixedCellHeight);
},
fianlVirtualCellIdPrefix() {
const prefix = this.virtualCellIdPrefix ? this.virtualCellIdPrefix + '-' : '';
return prefix + 'zp-id';
},
finalPlaceholderTopHeightStyle() {
// #ifdef VUE2
return { transform: this.virtualPlaceholderTopHeight > 0 ? `translateY(${this.virtualPlaceholderTopHeight}px)` : 'none' };
// #endif
return {};
},
virtualRangePageHeight(){
return this.finalVirtualPageHeight * this.preloadPage;
},
virtualScrollDisTimeStamp() {
return 1000 / this.virtualScrollFps;
},
}
},
methods: {
// 在使用动态高度虚拟列表时,若在列表数组中需要插入某个item,需要调用此方法;item:需要插入的itemindex:插入的cell位置,若index为2,则插入的item在原list的index=1之后,index从0开始
doInsertVirtualListItem(item, index) {
if (this.cellHeightMode !== Enum.CellHeightMode.Dynamic) return;
this.realTotalData.splice(index, 0, item);
// #ifdef VUE3
this.realTotalData = [...this.realTotalData];
// #endif
this.virtualItemInsertedCount ++;
if (!item || Object.prototype.toString.call(item) !== '[object Object]') {
item = { item };
@@ -162,7 +191,7 @@ export default {
while (retryCount <= 10) {
await u.wait(c.delayTime);
const cellNode = await this._getNodeClientRect(`#zp-id-${item[cellIndexKey]}`, this.finalUseInnerList);
const cellNode = await this._getVirtualCellNodeByIndex(item[cellIndexKey]);
// 如果获取当前cell的节点信息失败,则重试(不超过10次)
if (!cellNode) {
retryCount ++;
@@ -191,12 +220,12 @@ export default {
}
})
},
// 在使用动态高度虚拟列表时,手动更新指定cell的缓存高度(当cell高度在初始化之后再次改变调用);index:需要更新的cell在列表中的位置,从0开始
// 在使用动态高度虚拟列表时,手动更新指定cell的缓存高度(当cell高度在初始化之后再次改变调用);index:需要更新的cell在列表中的位置,从0开始
didUpdateVirtualListCell(index) {
if (this.cellHeightMode !== Enum.CellHeightMode.Dynamic) return;
const currentNode = this.virtualHeightCacheList[index];
this.$nextTick(() => {
this._getNodeClientRect(`#zp-id-${index}`, this.finalUseInnerList).then(cellNode => {
this._getVirtualCellNodeByIndex(index).then(cellNode => {
// 更新当前cell的高度
const cellNodeHeight = cellNode ? cellNode[0].height : 0;
const heightDis = cellNodeHeight - currentNode.height;
@@ -261,7 +290,7 @@ export default {
if (!this.finalFixedCellHeight) {
this.$nextTick(() => {
u.delay(() => {
this._getNodeClientRect(`#zp-id-${0}`,this.finalUseInnerList).then(cellNode => {
this._getVirtualCellNodeByIndex(0).then(cellNode => {
if (!cellNode) {
if (this.getCellHeightRetryCount.fixed > 10) return;
this.getCellHeightRetryCount.fixed ++;
@@ -287,7 +316,7 @@ export default {
this.$nextTick(() => {
u.delay(async () => {
for (let i = 0; i < list.length; i++) {
const cellNode = await this._getNodeClientRect(`#zp-id-${list[i][this.virtualCellIndexKey]}`, this.finalUseInnerList);
const cellNode = await this._getVirtualCellNodeByIndex(list[i][this.virtualCellIndexKey]);
const currentHeight = cellNode ? cellNode[0].height : 0;
if (!cellNode) {
if (this.getCellHeightRetryCount.dynamic <= 10) {
@@ -328,8 +357,8 @@ export default {
_setCellIndex(list, dataFrom = 'bottom') {
let currentItemIndex = 0;
const cellIndexKey = this.virtualCellIndexKey;
([Enum.QueryFrom.Refresh, Enum.QueryFrom.Reload].indexOf(this.queryFrom) >= 0) && this._resetDynamicListState();
if (this.totalData.length) {
dataFrom === 'bottom' && ([Enum.QueryFrom.Refresh, Enum.QueryFrom.Reload].indexOf(this.queryFrom) >= 0) && this._resetDynamicListState();
if (this.totalData.length && this.queryFrom !== Enum.QueryFrom.Refresh) {
if (dataFrom === 'bottom') {
currentItemIndex = this.realTotalData.length;
const lastItem = this.realTotalData.length ? this.realTotalData.slice(-1)[0] : null;
@@ -504,6 +533,20 @@ export default {
})
}
},
// 获取对应index的虚拟列表cell节点信息
_getVirtualCellNodeByIndex(index) {
let inDom = this.finalUseInnerList;
// 在vue3+(微信小程序或QQ小程序)中,使用非内置列表写法时,若z-paging在swiper-item内存在无法获取slot插入的cell高度的问题
// 通过uni.createSelectorQuery().in(this.$parent)来解决此问题
// #ifdef VUE3
// #ifdef MP-WEIXIN || MP-QQ
if (this.forceCloseInnerList && this.virtualInSwiperSlot) {
inDom = this.$parent;
}
// #endif
// #endif
return this._getNodeClientRect(`#${this.fianlVirtualCellIdPrefix}-${index}`, inDom);
},
// 处理使用内置列表时点击了cell事件
_innerCellClick(item, index) {
this.$emit('innerCellClick', item, index);
@@ -2,7 +2,7 @@
export default {
// 当前版本号
version: '2.7.11',
version: '2.8.6',
// 延迟操作的通用时间
delayTime: 100,
// 请求失败时候全局emit使用的key
@@ -1,32 +1,32 @@
// [z-paging]枚举
export default {
// 当前加载类型 0.下拉刷新 1.上拉加载更多
// 当前加载类型 refresher:下拉刷新 load-more:上拉加载更多
LoadingType: {
Refresher: 0,
LoadingMore: 1
Refresher: 'refresher',
LoadMore: 'load-more'
},
// 下拉刷新状态 0.默认状态 1.松手立即刷新 2.刷新中 3.刷新结束 4.松手进入二楼
// 下拉刷新状态 default:默认状态 release-to-refresh:松手立即刷新 loading:刷新中 complete:刷新结束 go-f2:松手进入二楼
Refresher: {
Default: 0,
ReleaseToRefresh: 1,
Loading: 2,
Complete: 3,
GoF2: 4
Default: 'default',
ReleaseToRefresh: 'release-to-refresh',
Loading: 'loading',
Complete: 'complete',
GoF2: 'go-f2'
},
// 底部加载更多状态 0.默认状态 1.加载中 2.没有更多数据 3.加载失败
// 底部加载更多状态 default:默认状态 loading:加载中 no-more:没有更多数据 fail:加载失败
More: {
Default: 0,
Loading: 1,
NoMore: 2,
Fail: 3
Default: 'default',
Loading: 'loading',
NoMore: 'no-more',
Fail: 'fail'
},
// @query触发来源 0.用户主动下拉刷新 1.通过reload触发 2.通过refresh触发 3.通过滚动到底部加载更多或点击底部加载更多触发
// @query触发来源 user-pull-down:用户主动下拉刷新 reload:通过reload触发 refresh:通过refresh触发 load-more:通过滚动到底部加载更多或点击底部加载更多触发
QueryFrom: {
UserPullDown: 0,
Reload: 1,
Refresh: 2,
LoadingMore: 3
UserPullDown: 'user-pull-down',
Reload: 'reload',
Refresh: 'refresh',
LoadMore: 'load-more'
},
// 虚拟列表cell高度模式
CellHeightMode: {
@@ -24,8 +24,7 @@ import virtualListModule from './modules/virtual-list'
import Enum from './z-paging-enum'
const systemInfo = uni.getSystemInfoSync();
const systemInfo = u.getSystemInfoSync();
export default {
name: "z-paging",
components: {
@@ -50,8 +49,6 @@ export default {
data() {
return {
// --------------静态资源---------------
base64Arrow: zStatic.base64Arrow,
base64Flower: zStatic.base64Flower,
base64BackToTop: zStatic.base64BackToTop,
// -------------全局数据相关--------------
@@ -216,9 +213,12 @@ export default {
// #endif
this.$nextTick(() => {
// 初始化systemInfo
this.systemInfo = uni.getSystemInfoSync();
this.systemInfo = u.getSystemInfoSync();
// 初始化z-paging高度
!this.usePageScroll && this.autoHeight && this._setAutoHeight();
!this.usePageScroll && this.autoHeight && this._setAutoHeight();
// #ifdef MP-KUAISHOU
this._setFullScrollViewInHeight();
// #endif
this.loaded = true;
u.delay(() => {
// 更新fixed模式下z-paging的布局,主要是更新windowTop、windowBottom
@@ -408,10 +408,7 @@ export default {
},
// 设置z-paging高度
async _setAutoHeight(shouldFullHeight = true, scrollViewNode = null) {
let heightKey = 'min-height';
// #ifndef APP-NVUE
heightKey = 'min-height';
// #endif
const heightKey = 'min-height';
try {
if (shouldFullHeight) {
// 如果需要铺满全屏,则计算当前全屏可是区域的高度
@@ -422,7 +419,12 @@ export default {
let scrollViewHeight = this.windowHeight - scrollViewTop;
scrollViewHeight -= finalScrollBottomNode ? finalScrollBottomNode[0].height : 0;
const additionHeight = u.convertToPx(this.autoHeightAddition);
const finalHeight = scrollViewHeight + additionHeight - (this.insideMore ? 1 : 0) + 'px !important';
// 在支付宝小程序中,添加!important会导致min-height失效,因此在支付宝小程序中需要去掉
let importantSuffix = ' !important';
// #ifdef MP-ALIPAY
importantSuffix = '';
// #endif
const finalHeight = scrollViewHeight + additionHeight - (this.insideMore ? 1 : 0) + 'px' + importantSuffix;
this.$set(this.scrollViewStyle, heightKey, finalHeight);
this.$set(this.scrollViewInStyle, heightKey, finalHeight);
}
@@ -432,6 +434,16 @@ export default {
}
} catch (e) {}
},
// #ifdef MP-KUAISHOU
// 设置scroll-view内容器的最小高度等于scroll-view的高度(为了解决在快手小程序中内容较少时scroll-view内容器高度无法铺满scroll-view的问题)
async _setFullScrollViewInHeight() {
try {
// 如果需要铺满全屏,则计算当前全屏可是区域的高度
const scrollViewNode = await this._getNodeClientRect('.zp-scroll-view');
scrollViewNode && this.$set(this.scrollViewInStyle, 'min-height', scrollViewNode[0].height + 'px');
} catch (e) {}
},
// #endif
// 组件销毁后续处理
_handleUnmounted() {
this.active = false;
@@ -6,6 +6,7 @@ import c from './z-paging-constant'
const storageKey = 'Z-PAGING-REFRESHER-TIME-STORAGE-KEY';
let config = null;
let configLoaded = false;
let cachedSystemInfo = null;
const timeoutMap = {};
// 获取默认配置信息
@@ -119,12 +120,41 @@ function convertToPx(text) {
text = text.replace('px', '');
}
if (!isNaN(text)) {
if (isRpx) return Number(uni.upx2px(text));
if (isRpx) return Number(rpx2px(text));
return Number(text);
}
return 0;
}
// rpx => px,预留的兼容处理
function rpx2px(rpx) {
return uni.upx2px(rpx);
}
// 同步获取系统信息,兼容不同平台
function getSystemInfoSync(useCache = false) {
if (useCache && cachedSystemInfo) {
return cachedSystemInfo;
}
// 目前只用到了deviceInfo、appBaseInfo和windowInfo中的信息,因此仅整合这两个信息数据
const infoTypes = ['DeviceInfo', 'AppBaseInfo', 'WindowInfo'];
const { deviceInfo, appBaseInfo, windowInfo } = infoTypes.reduce((acc, key) => {
const method = `get${key}`;
if (uni[method] && uni.canIUse(method)) {
acc[key.charAt(0).toLowerCase() + key.slice(1)] = uni[method]();
}
return acc;
}, {});
// 如果deviceInfo、appBaseInfo和windowInfo都可以从各自专属的api中获取,则整合它们的数据
if (deviceInfo && appBaseInfo && windowInfo) {
cachedSystemInfo = { ...deviceInfo, ...appBaseInfo, ...windowInfo };
} else {
// 使用uni.getSystemInfoSync兜底,确保能获取到最终的系统信息
cachedSystemInfo = uni.getSystemInfoSync();
}
return cachedSystemInfo;
}
// 获取当前时间
function getTime() {
return (new Date()).getTime();
@@ -132,12 +162,12 @@ function getTime() {
// 获取z-paging实例id,随机生成10位数字+字母
function getInstanceId() {
const s = [];
const hexDigits = "0123456789abcdef";
for (let i = 0; i < 10; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
return s.join('') + getTime();
const s = [];
const hexDigits = "0123456789abcdef";
for (let i = 0; i < 10; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
return s.join('') + getTime();
}
// 等待一段时间
@@ -192,8 +222,8 @@ function _handleDefaultConfig() {
}
// 将config中的短横线写法全部转为驼峰写法,使得读取配置时可以直接通过key去匹配,而非读取每个配置时候再去转,减少不必要的性能开支
config = config ? Object.keys(config).reduce((result, key) => {
result[_toCamelCase(key)] = config[key];
return result;
result[_toCamelCase(key)] = config[key];
return result;
}, {}) : null;
configLoaded = true;
}
@@ -247,7 +277,7 @@ function _toKebab(value) {
// 短横线转驼峰
function _toCamelCase(value) {
return value.replace(/-([a-z])/g, (_, group1) => group1.toUpperCase());
return value.replace(/-([a-z])/g, (_, group1) => group1.toUpperCase());
}
@@ -266,5 +296,7 @@ export default {
wait,
isPromise,
addUnit,
deepCopy
deepCopy,
rpx2px,
getSystemInfoSync
};
@@ -4,13 +4,13 @@
/ /_____| |_) | (_| | (_| | | | | | (_| |
/___| | .__/ \__,_|\__, |_|_| |_|\__, |
|_| |___/ |___/
v2.7.11 (2024-06-28)
by ZXLee
v2.8.6 (2025-03-17)
@author ZXLee <admin@zxlee.cn>
-->
<!-- 文档地址:https://z-paging.zxlee.cn -->
<!-- github地址:https://github.com/SmileZXLee/uni-z-paging -->
<!-- dcloud地址:https://ext.dcloud.net.cn/plugin?id=3935 -->
<!-- 反馈QQ群:790460711(已满)、371624008 -->
<!-- 反馈QQ群:343409055 -->
<template name="z-paging">
<!-- #ifndef APP-NVUE -->
@@ -34,7 +34,7 @@ by ZXLee
<view :class="{'zp-scroll-view-container':true,'zp-absoulte':finalIsOldWebView}" :style="[scrollViewContainerStyle]">
<scroll-view
ref="zp-scroll-view" :class="{'zp-scroll-view':true,'zp-scroll-view-absolute':!usePageScroll,'zp-scroll-view-hide-scrollbar':!showScrollbar}" :style="[chatRecordRotateStyle]"
:scroll-top="scrollTop" :scroll-x="scrollX"
:scroll-top="scrollTop" :scroll-left="scrollLeft" :scroll-x="scrollX"
:scroll-y="finalScrollable" :enable-back-to-top="finalEnableBackToTop"
:show-scrollbar="showScrollbar" :scroll-with-animation="finalScrollWithAnimation"
:scroll-into-view="scrollIntoView" :lower-threshold="finalLowerThreshold" :upper-threshold="5"
@@ -77,7 +77,7 @@ by ZXLee
<slot v-if="zSlots.refresherComplete&&refresherStatus===R.Complete" name="refresherComplete" />
<slot v-else-if="zSlots.refresherF2&&refresherStatus===R.GoF2" name="refresherF2" />
<z-paging-refresh ref="refresh" v-else-if="!showCustomRefresher" class="zp-custom-refresher-refresh" :style="[{'height': `${finalRefresherThreshold - finalRefresherThresholdPlaceholder}px`}]" :status="refresherStatus"
:defaultThemeStyle="finalRefresherThemeStyle" :defaultText="finalRefresherDefaultText"
:defaultThemeStyle="finalRefresherThemeStyle" :defaultText="finalRefresherDefaultText" :isIos="isIos"
:pullingText="finalRefresherPullingText" :refreshingText="finalRefresherRefreshingText" :completeText="finalRefresherCompleteText" :goF2Text="finalRefresherGoF2Text"
:defaultImg="refresherDefaultImg" :pullingImg="refresherPullingImg" :refreshingImg="refresherRefreshingImg" :completeImg="refresherCompleteImg" :refreshingAnimated="refresherRefreshingAnimated"
:showUpdateTime="showRefresherUpdateTime" :updateTimeKey="refresherUpdateTimeKey" :updateTimeTextMap="finalRefresherUpdateTimeTextMap"
@@ -88,15 +88,19 @@ by ZXLee
<!-- 全屏Loading -->
<slot v-if="showLoading&&zSlots.loading&&!loadingFullFixed" name="loading" />
<!-- 主体内容 -->
<view class="zp-paging-container-content" :style="[{transform:virtualPlaceholderTopHeight>0?`translateY(${virtualPlaceholderTopHeight}px)`:'none'},finalPagingContentStyle]">
<view class="zp-paging-container-content" :style="[finalPlaceholderTopHeightStyle,finalPagingContentStyle]">
<!-- #ifdef VUE3 -->
<!-- 虚拟列表顶部占位view -->
<view v-if="useVirtualList" class="zp-virtual-placeholder" :style="[{height:virtualPlaceholderTopHeight+'px'}]"/>
<!-- #endif -->
<slot />
<!-- 内置列表&虚拟列表 -->
<template v-if="finalUseInnerList">
<slot name="header"/>
<view class="zp-list-container" :style="[innerListStyle]">
<template v-if="finalUseVirtualList">
<view class="zp-list-cell" :style="[innerCellStyle]" :id="`zp-id-${item[virtualCellIndexKey]}`" v-for="(item,index) in virtualList" :key="item['zp_unique_index']" @click="_innerCellClick(item,virtualTopRangeIndex+index)">
<view v-if="useCompatibilityMode">使用兼容模式请在组件源码z-paging.vue第99行中注释这一行,并打开下面一行注释</view>
<view class="zp-list-cell" :style="[innerCellStyle]" :id="`${fianlVirtualCellIdPrefix}-${item[virtualCellIndexKey]}`" v-for="(item,index) in virtualList" :key="item['zp_unique_index']" @click="_innerCellClick(item,virtualTopRangeIndex+index)">
<view v-if="useCompatibilityMode">使用兼容模式请在组件源码z-paging.vue第103行中注释这一行,并打开下面一行注释</view>
<!-- <zp-public-virtual-cell v-if="useCompatibilityMode" :extraData="extraData" :item="item" :index="virtualTopRangeIndex+index" /> -->
<slot v-else name="cell" :item="item" :index="virtualTopRangeIndex+index"/>
</view>
@@ -170,7 +174,7 @@ by ZXLee
<!-- 点击返回顶部view -->
<view v-if="showBackToTopClass" :class="finalBackToTopClass" :style="[finalBackToTopStyle]" @click.stop="_backToTopClick">
<slot v-if="zSlots.backToTop" name="backToTop" />
<image v-else class="zp-back-to-top-img" :src="backToTopImg.length?backToTopImg:base64BackToTop" />
<image v-else class="zp-back-to-top-img" :class="{'zp-back-to-top-img-inversion': useChatRecordMode&&!backToTopImg.length}" :src="backToTopImg.length?backToTopImg:base64BackToTop" />
</view>
<!-- 全屏Loading(铺满z-paging并固定) -->
<view v-if="showLoading&&zSlots.loading&&loadingFullFixed" class="zp-loading-fixed">
@@ -209,7 +213,7 @@ by ZXLee
<slot v-if="zSlots.refresherComplete&&refresherStatus===R.Complete" name="refresherComplete" />
<slot v-else-if="zSlots.refresherF2&&refresherStatus===R.GoF2" name="refresherF2" />
<slot v-else-if="(nScopedSlots?nScopedSlots:zSlots).refresher" :refresherStatus="refresherStatus" name="refresher" />
<z-paging-refresh ref="refresh" v-else :status="refresherStatus" :defaultThemeStyle="finalRefresherThemeStyle"
<z-paging-refresh ref="refresh" v-else :status="refresherStatus" :defaultThemeStyle="finalRefresherThemeStyle" :isIos="isIos"
:defaultText="finalRefresherDefaultText" :pullingText="finalRefresherPullingText" :refreshingText="finalRefresherRefreshingText" :completeText="finalRefresherCompleteText" :goF2Text="finalRefresherGoF2Text"
:defaultImg="refresherDefaultImg" :pullingImg="refresherPullingImg" :refreshingImg="refresherRefreshingImg" :completeImg="refresherCompleteImg" :refreshingAnimated="refresherRefreshingAnimated"
:showUpdateTime="showRefresherUpdateTime" :updateTimeKey="refresherUpdateTimeKey" :updateTimeTextMap="finalRefresherUpdateTimeTextMap"
@@ -223,7 +227,7 @@ by ZXLee
<slot v-if="zSlots.refresherComplete&&refresherStatus===R.Complete" name="refresherComplete" />
<slot v-else-if="zSlots.refresherF2&&refresherStatus===R.GoF2" name="refresherF2" />
<slot v-else-if="(nScopedSlots?nScopedSlots:$slots).refresher" :refresherStatus="R.Loading" name="refresher" />
<z-paging-refresh ref="refresh" v-else :status="R.Loading" :defaultThemeStyle="finalRefresherThemeStyle"
<z-paging-refresh ref="refresh" v-else :status="R.Loading" :defaultThemeStyle="finalRefresherThemeStyle" :isIos="isIos"
:defaultText="finalRefresherDefaultText" :pullingText="finalRefresherPullingText" :refreshingText="finalRefresherRefreshingText" :completeText="finalRefresherCompleteText" :goF2Text="finalRefresherGoF2Text"
:defaultImg="refresherDefaultImg" :pullingImg="refresherPullingImg" :refreshingImg="refresherRefreshingImg" :completeImg="refresherCompleteImg" :refreshingAnimated="refresherRefreshingAnimated"
:showUpdateTime="showRefresherUpdateTime" :updateTimeKey="refresherUpdateTimeKey" :updateTimeTextMap="finalRefresherUpdateTimeTextMap"
@@ -261,7 +265,7 @@ by ZXLee
</view>
</template>
<view :style="nLoadingMoreFixedHeight?{height:loadingMoreCustomStyle&&loadingMoreCustomStyle.height?loadingMoreCustomStyle.height:'80rpx'}:{}">
<view :style="nLoadingMoreFixedHeight?{height:loadingMoreCustomStyle&&loadingMoreCustomStyle.height?loadingMoreCustomStyle.height:loadingMoreFixedHeight}:{}">
<slot v-if="showLoadingMoreDefault" name="loadingMoreDefault" />
<slot v-else-if="showLoadingMoreLoading" name="loadingMoreLoading" />
<slot v-else-if="showLoadingMoreNoMore" name="loadingMoreNoMore" />
@@ -280,7 +284,7 @@ by ZXLee
@reload="_emptyViewReload" @viewClick="_emptyViewClick" />
</view>
</component>
<component is="header" v-if="!hideNvueBottomTag" ref="zp-n-list-bottom-tag" class="zp-n-list-bottom-tag"></component>
<component :is="nViewIs" v-if="!hideNvueBottomTag" ref="zp-n-list-bottom-tag" class="zp-n-list-bottom-tag"></component>
</component>
<view v-if="zSlots.right" class="zp-page-right">
<slot name="right" />
@@ -298,7 +302,7 @@ by ZXLee
<!-- 点击返回顶部view -->
<view v-if="showBackToTopClass" :class="finalBackToTopClass" :style="[finalBackToTopStyle]" @click.stop="_backToTopClick">
<slot v-if="zSlots.backToTop" name="backToTop" />
<image v-else class="zp-back-to-top-img" :src="backToTopImg.length?backToTopImg:base64BackToTop" />
<image v-else class="zp-back-to-top-img" :class="{'zp-back-to-top-img-inversion': useChatRecordMode&&!backToTopImg.length}" :src="backToTopImg.length?backToTopImg:base64BackToTop" />
</view>
<!-- 全屏Loading(铺满z-paging并固定) -->
<view v-if="showLoading&&zSlots.loading&&loadingFullFixed" class="zp-loading-fixed">
@@ -307,27 +311,211 @@ by ZXLee
</component>
<!-- #endif -->
</template>
<!-- #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5 -->
<script src="./wxs/z-paging-wxs.wxs" module="pagingWxs" lang="wxs"></script>
<!-- #endif -->
<script module="pagingRenderjs" lang="renderjs">
import pagingRenderjs from './wxs/z-paging-renderjs.js';
/**
* z-paging 分页组件
* @description 高性能,全平台兼容。支持虚拟列表,支持nvue、vue3
* @description z-paging 分页组件,高性能,全平台兼容。支持自定义下拉刷新、上拉加载更多、虚拟列表、下拉进入二楼、自动管理空数据图、全自动分页、无闪动聊天分页、本地分页等,也支持作为基本布局容器使用
* @tutorial https://z-paging.zxlee.cn
* @notice 以下仅为部分常用属性、方法和事件,完整文档请查阅z-paging官网
* @property {Number|String} default-page-no 自定义初始的pageNo,默认为1
* @property {Number|String} default-page-size 自定义pageSize,默认为10
* @property {Object} paging-style 设置z-paging的style,部分平台(如微信小程序)无法直接修改组件的style,可使用此属性代替
* @property {Array} value 父组件v-model所绑定的list的值,默认为[]
* @property {Number|String} defaultPageNo 自定义初始的pageNo,默认为1
* @property {Number|String} defaultPageSize 自定义pageSize(每页显示多少条),默认为10
* @property {Boolean} fixed z-paging是否使用fixed布局,默认为true
* @property {Boolean} safeAreaInsetBottom 是否开启底部安全区域适配,默认为false
* @property {Boolean} useSafeAreaPlaceholder 开启底部安全区域适配后,是否使用placeholder形式实现,默认为false
* @property {Boolean} usePageScroll 使用页面滚动,默认为false
* @property {Boolean} autoFullHeight 使用页面滚动时,是否在不满屏时自动填充满屏幕,默认为true
* @property {String} defaultThemeStyle loading(下拉刷新、上拉加载更多)的主题样式,支持black,white,默认为black
* @property {Object} pagingStyle 设置z-paging的style,部分平台(如微信小程序)无法直接修改组件的style,可使用此属性代替
* @property {String} height z-paging的高度,优先级低于pagingStyle中设置的height,传字符串,如100px、100rpx、100%
* @property {String} width z-paging的宽度,优先级低于pagingStyle中设置的width,传字符串,如100px、100rpx、100%
* @property {Boolean} use-page-scroll 使用页面滚动,默认为
* @property {Boolean} use-virtual-list 是否使用虚拟列表,默认为否
* @property {Boolean} fixed z-paging是否使用fixed布局,若使用fixed布局,则z-paging的父view无需固定高度,z-paging高度默认为100%,默认为是(当使用内置scroll-view滚动时有效)
* @property {Boolean} auto [z-paging]mounted后是否自动调用reload方法(mounted后自动调用接口),默认为
* @property {Boolean} use-chat-record-mode 使用聊天记录模式,默认为
* @property {String} maxWidth z-paging的最大宽度,优先级低于pagingStyle中设置的max-width,默认为
* @property {String} bgColor z-paging的背景色(为css中的background,因此也可以设置渐变,背景图片等),优先级低于pagingStyle中设置的background-color
* @property {Boolean} watchTouchDirectionChange 是否监听列表触摸方向改变,默认为false
* @property {Number|String} delay 调用complete后延迟处理的时间,单位为毫秒,优先级高于min-delay,默认为0
* @property {Number|String} minDelay 触发@query后最小延迟处理的时间,单位为毫秒,优先级低于delay,默认为0
* @property {Boolean} callNetworkReject 请求失败是否触发reject,默认为true
* @property {String} unit z-paging中默认布局的单位,默认为rpx
* @property {Boolean} concat 自动拼接complete中传过来的数组,默认为true
* @property {Number|String|Object} dataKey 为保证数据一致,设置当前tab切换时的标识key,并在complete中传递相同key,若二者不一致,则complete将不会生效
* @property {String} autowireListName 【极简写法】自动注入的list名,可自动修改父view(包含ref="paging")中对应name的list值
* @property {String} autowireQueryName 【极简写法】自动注入的query名,可自动调用父view(包含ref="paging")中的query方法
* @property {Function} fetch 【极简写法】获取分页数据Function,功能与@query类似。若设置了fetch则@query将不再触发
* @property {Object} fetchParams fetch的附加参数,fetch配置后有效
* @property {Boolean} auto [z-paging]mounted后是否自动调用reload方法(mounted后自动调用接口),默认为true
* @property {Boolean} autoScrollToTopWhenReload reload时自动滚动到顶部,默认为true
* @property {Boolean} autoCleanListWhenReload reload时立即自动清空原list,默认为true
* @property {Boolean} showRefresherWhenReload 列表刷新时自动显示下拉刷新view,默认为false
* @property {Boolean} showLoadingMoreWhenReload 列表刷新时自动显示加载更多view,且为加载中状态,默认为false
* @property {Boolean} createdReload 组件created时立即触发reload,默认为false
* @property {Boolean} refresherEnabled 是否开启下拉刷新,默认为true
* @property {Number|String} refresherThreshold 设置自定义下拉刷新阈值,默认单位为px,默认为80rpx
* @property {Boolean} useRefresherStatusBarPlaceholder 是否开启下拉刷新状态栏占位,默认为false
* @property {Boolean} refresherOnly 是否只使用下拉刷新,默认为false
* @property {Boolean} useCustomRefresher 是否使用自定义的下拉刷新,默认为true
* @property {Boolean} reloadWhenRefresh 用户下拉刷新时是否触发reload方法,默认为true
* @property {String} refresherThemeStyle 下拉刷新的主题样式,支持blackwhite,默认为black
* @property {Object} refresherImgStyle 自定义下拉刷新中左侧图标的样式
* @property {Object} refresherTitleStyle 自定义下拉刷新中右侧状态描述文字的样式
* @property {Object} refresherUpdateTimeStyle 自定义下拉刷新中右侧最后更新时间文字的样式
* @property {Boolean} watchRefresherTouchmove 是否实时监听下拉刷新中进度,并通过@refresherTouchmove传递给父组件,默认为false
* @property {Boolean} showRefresherUpdateTime 是否显示最后更新时间,默认为false
* @property {String|Object} refresherDefaultText 自定义下拉刷新默认状态下的文字
* @property {String|Object} refresherPullingText 自定义下拉刷新松手立即刷新状态下的文字
* @property {String|Object} refresherRefreshingText 自定义下拉刷新刷新中状态下的文字
* @property {String|Object} refresherCompleteText 自定义下拉刷新刷新结束状态下的文字
* @property {String} refresherDefaultImg 自定义下拉刷新默认状态下的图片
* @property {String} refresherPullingImg 自定义下拉刷新松手立即刷新状态下的图片
* @property {String} refresherRefreshingImg 自定义下拉刷新刷新中状态下的图片
* @property {String} refresherCompleteImg 自定义下拉刷新刷新结束状态下的图片
* @property {Boolean} refresherRefreshingAnimated 自定义下拉刷新刷新中状态下是否展示旋转动画,默认为true
* @property {Boolean} refresherEndBounceEnabled 是否开启自定义下拉刷新刷新结束回弹动画效果,默认为true
* @property {String} refresherDefaultStyle 设置系统下拉刷新默认样式,支持设置black,whitenone,默认为black
* @property {String} refresherBackground 设置自定义下拉刷新区域背景颜色,默认为#FFFFFF00
* @property {String} refresherFixedBackground 设置固定的自定义下拉刷新区域背景颜色,默认为#FFFFFF00
* @property {Number|String} refresherFixedBacHeight 设置固定的自定义下拉刷新区域高度,默认为0
* @property {Number|String} refresherDefaultDuration 设置自定义下拉刷新默认状态下回弹动画时间,单位为毫秒,默认为100
* @property {Number|String} refresherCompleteDelay 自定义下拉刷新结束以后延迟收回的时间,单位为毫秒,默认为0
* @property {Number|String} refresherCompleteDuration 自定义下拉刷新结束收回动画时间,单位为毫秒,默认为300
* @property {Boolean} refresherVibrate 下拉刷新时下拉到“松手立即刷新”状态时是否使手机短振动,默认为false
* @property {Boolean} refresherRefreshingScrollable 自定义下拉刷新刷新中状态是否允许列表滚动,默认为true
* @property {Boolean} refresherCompleteScrollable 自定义下拉刷新结束状态下是否允许列表滚动,默认为false
* @property {Number} refresherOutRate 设置自定义下拉刷新下拉超出阈值后继续下拉位移衰减的比例,默认为0.65
* @property {Boolean} refresherF2Enabled 是否开启下拉进入二楼功能,默认为false
* @property {Number|String} refresherF2Threshold 下拉进入二楼阈值,默认为200rpx
* @property {Number|String} refresherF2Duration 下拉进入二楼动画时间,单位为毫秒,默认为200
* @property {Boolean} showRefresherF2 下拉进入二楼状态松手后是否弹出二楼,默认为true
* @property {Number} refresherPullRate 设置自定义下拉刷新下拉时实际下拉位移与用户下拉距离的比值,默认为0.75
* @property {Number|String} refresherFps 自定义下拉刷新下拉帧率,默认为40
* @property {Number|String} refresherMaxAngle 自定义下拉刷新允许触发的最大下拉角度,默认为40度
* @property {Boolean} refresherAngleEnableChangeContinued 自定义下拉刷新的角度由未达到最大角度变到达到最大角度时,是否继续下拉刷新手势,默认为false
* @property {Boolean} refresherNoTransform 下拉刷新时是否禁止下拉刷新view跟随用户触摸竖直移动,默认为false
* @property {Boolean} loadingMoreEnabled 是否启用加载更多数据(含滑动到底部加载更多数据和点击加载更多数据),默认为true
* @property {Number|String} lowerThreshold 距底部/右边多远时,触发scrolltolower事件,默认单位为px,默认为100rpx
* @property {Boolean} toBottomLoadingMoreEnabled 是否启用滑动到底部加载更多数据,默认为true
* @property {String} loadingMoreThemeStyle 底部加载更多的主题样式,支持black,white,默认为black
* @property {Object} loadingMoreCustomStyle 自定义底部加载更多样式
* @property {Object} loadingMoreTitleCustomStyle 自定义底部加载更多文字样式
* @property {Object} loadingMoreLoadingIconCustomStyle 自定义底部加载更多加载中动画样式
* @property {String} loadingMoreLoadingIconType 自定义底部加载更多加载中动画图标类型,可选flower或circle,默认为flower
* @property {String} loadingMoreLoadingIconCustomImage 自定义底部加载更多加载中动画图标图片
* @property {Boolean} loadingMoreLoadingAnimated 底部加载更多加载中view是否展示旋转动画,默认为true
* @property {String|Object} loadingMoreDefaultText 滑动到底部"默认"文字
* @property {String|Object} loadingMoreLoadingText 滑动到底部"加载中"文字
* @property {String|Object} loadingMoreNoMoreText 滑动到底部"没有更多"文字
* @property {String|Object} loadingMoreFailText 滑动到底部"加载失败"文字
* @property {Boolean} hideNoMoreInside 当没有更多数据且分页内容未超出z-paging时是否隐藏没有更多数据的view,默认为false
* @property {Number} hideNoMoreByLimit 当没有更多数据且分页数组长度少于这个值时,隐藏没有更多数据的view,默认为0
* @property {Boolean} insideMore 当分页未满一屏时,是否自动加载更多,默认为false
* @property {Boolean} loadingMoreDefaultAsLoading 滑动到底部状态为默认状态时,以加载中的状态展示,默认为false
* @property {Boolean} showLoadingMoreNoMoreView 是否显示没有更多数据的view,默认为true
* @property {Boolean} showDefaultLoadingMoreText 是否显示默认的加载更多text,默认为true
* @property {Boolean} showLoadingMoreNoMoreLine 是否显示没有更多数据的分割线,默认为true
* @property {Object} loadingMoreNoMoreLineCustomStyle 自定义底部没有更多数据的分割线样式
* @property {Boolean} hideEmptyView 是否强制隐藏空数据图,默认为false
* @property {Boolean} emptyViewFixed 空数据图片是否铺满z-paging,默认为false
* @property {Boolean} emptyViewCenter 空数据图片是否垂直居中,默认为true
* @property {String|Object} emptyViewText 空数据图描述文字
* @property {String} emptyViewImg 空数据图图片
* @property {String} emptyViewErrorImg 空数据图“加载失败”图片
* @property {String|Object} emptyViewReloadText 空数据图点击重新加载文字
* @property {String|Object} emptyViewErrorText 空数据图“加载失败”描述文字
* @property {Object} emptyViewSuperStyle 空数据图父view样式
* @property {Object} emptyViewStyle 空数据图样式
* @property {Object} emptyViewImgStyle 空数据图img样式
* @property {Object} emptyViewTitleStyle 空数据图描述文字样式
* @property {Object} emptyViewReloadStyle 空数据图重新加载按钮样式
* @property {Boolean} showEmptyViewReload 是否显示空数据图重新加载按钮(无数据时),默认为false
* @property {Boolean} showEmptyViewReloadWhenError 加载失败时是否显示空数据图重新加载按钮,默认为true
* @property {Boolean} autoHideEmptyViewWhenLoading 加载中时是否自动隐藏空数据图,默认为true
* @property {Boolean} autoHideEmptyViewWhenPull 用户下拉列表触发下拉刷新加载中时是否自动隐藏空数据图,默认为true
* @property {Boolean} autoHideLoadingAfterFirstLoaded 第一次加载后自动隐藏loading slot,默认为true
* @property {Boolean} loadingFullFixed loading slot的父view是否铺满屏幕并固定,默认为false
* @property {Boolean} autoShowSystemLoading 是否自动显示系统Loading:即uni.showLoading,默认为false
* @property {String|Object} systemLoadingText 显示系统Loading时显示的文字
* @property {Boolean} systemLoadingMask 显示系统Loading时是否显示透明蒙层,防止触摸穿透,默认为true
* @property {Boolean} autoShowBackToTop 自动显示点击返回顶部按钮,默认为false
* @property {Number|String} backToTopThreshold 点击返回顶部按钮显示/隐藏的阈值(滚动距离),默认单位为px,默认为400rpx
* @property {String} backToTopImg 点击返回顶部按钮的自定义图片地址
* @property {Boolean} backToTopWithAnimate 点击返回顶部按钮返回到顶部时是否展示过渡动画,默认为true
* @property {Number|String} backToTopBottom 点击返回顶部按钮与底部的距离,默认单位为px,默认为160rpx
* @property {Object} backToTopStyle 点击返回顶部按钮的自定义样式
* @property {Boolean} useVirtualList 是否使用虚拟列表,默认为false
* @property {Boolean} useCompatibilityMode 在使用虚拟列表时,是否使用兼容模式,默认为false
* @property {Object} extraData 使用兼容模式时传递的附加数据
* @property {String} cellHeightMode 虚拟列表cell高度模式,默认为fixed
* @property {Number|String} preloadPage 预加载的列表可视范围(列表高度)页数,默认为12
* @property {Number|String} fixedCellHeight 固定的cell高度,`cell-height-mode=fixed`才有效,默认为空
* @property {Number|String} virtualListCol 虚拟列表列数,默认为1
* @property {Number|String} virtualScrollFps 虚拟列表scroll取样帧率,默认为80
* @property {String} virtualCellIdPrefix 虚拟列表cell id的前缀
* @property {Boolean} useInnerList 是否在z-paging内部循环渲染列表(使用内置列表),默认为false
* @property {Boolean} forceCloseInnerList 强制关闭inner-list,默认为false
* @property {Boolean} virtualInSwiperSlot 虚拟列表是否使用swiper-item包裹,默认为false
* @property {String} cellKeyName 内置列表cell的key名称(仅nvue有效)
* @property {Object} innerListStyle innerList样式
* @property {Object} innerCellStyle innerCell样式
* @property {Number|String} localPagingLoadingTime 本地分页时上拉加载更多延迟时间,单位为毫秒,默认为200
* @property {Boolean} useChatRecordMode 使用聊天记录模式,默认为false
* @property {Boolean} autoHideKeyboardWhenChat 使用聊天记录模式时是否自动隐藏键盘,默认为true
* @property {Boolean} autoAdjustPositionWhenChat 使用聊天记录模式中键盘弹出时是否自动调整slot="bottom"高度,默认为true
* @property {Boolean} autoToBottomWhenChat 使用聊天记录模式中键盘弹出时是否自动滚动到底部,默认为false
* @property {String} chatAdjustPositionOffset 使用聊天记录模式中键盘弹出时占位高度偏移距离,默认为0px
* @property {Boolean} showChatLoadingWhenReload 使用聊天记录模式中`reload`时是否显示`chatLoading`,默认为false
* @property {String} bottomBgColor `bottom`的背景色,默认透明
* @property {Boolean} chatLoadingMoreDefaultAsLoading 在聊天记录模式中滑动到顶部状态为默认状态时,是否以加载中的状态展示,默认为true
* @property {Boolean} showScrollbar 控制是否出现滚动条,默认为true
* @property {Boolean} scrollable 是否可以滚动,使用内置scroll-view和nvue时有效,默认为true
* @property {Boolean} scrollX 是否允许横向滚动,默认为false
* @property {Boolean} scrollToTopBounceEnabled iOS设备上滚动到顶部时是否允许回弹效果,默认为false
* @property {Boolean} scrollToBottomBounceEnabled iOS设备上滚动到底部时是否允许回弹效果,默认为true
* @property {Boolean} scrollWithAnimation 在设置滚动条位置时使用动画过渡,默认为false
* @property {String} scrollIntoView 值应为某子元素id(id不能以数字开头)。设置哪个方向可滚动,则在哪个方向滚动到该元素
* @property {Boolean} enableBackToTop iOS点击顶部状态栏、安卓双击标题栏时,滚动条返回顶部,默认为true
* @property {String} nvueListIs nvue中修改列表类型,默认为list
* @property {Object} nvueWaterfallConfig waterfall配置,仅在nvue中且nvueListIs=waterfall时有效
* @property {Boolean} nvueBounce nvue控制是否回弹效果,iOS不支持动态修改,默认为true
* @property {Boolean} nvueFastScroll nvue中通过代码滚动到顶部/底部时,是否加快动画效果,默认为false
* @property {String} nvueListId nvue中list的id
* @property {Boolean} hideNvueBottomTag 是否隐藏nvue列表底部的tagView,默认为false
* @property {Boolean} nvuePagingEnabled 设置nvue中是否按分页模式(类似竖向swiper)显示List,默认为false
* @property {Number} offsetAccuracy nvue中控制onscroll事件触发的频率,默认为空
* @property {Boolean} useCache 是否使用缓存,默认为false
* @property {String} cacheKey 使用缓存时缓存的key
* @property {String} cacheMode 缓存模式,默认为default
* @property {Number} topZIndex slot="top"的view的z-index,默认为99
* @property {Number} superContentZIndex z-paging内容容器父view的z-index,默认为1
* @property {Number} contentZIndex z-paging内容容器部分的z-index,默认为1
* @property {Number} emptyViewZIndex 空数据view的z-index,默认为9
* @property {Boolean} autoHeight z-paging是否自动高度,默认为false
* @property {Number|String} autoHeightAddition z-paging自动高度时的附加高度,默认为0px
* @event {Function} input 父组件v-model所绑定的list的值改变时触发此事件
* @event {Function} query 下拉刷新或滚动到底部时会自动触发此方法。z-paging加载时也会触发(若要禁止,请设置:auto="false")。pageNo和pageSize会自动计算好,直接传给服务器即可。
* @event {Function} listChange 分页渲染的数组改变时触发
* @event {Function} refresherStatusChange 自定义下拉刷新状态改变
* @event {Function} refresherTouchstart 自定义下拉刷新下拉开始
* @event {Function} refresherTouchmove 自定义下拉刷新下拉拖动中
* @event {Function} refresherTouchend 自定义下拉刷新下拉结束
* @event {Function} refresherF2Change 下拉进入二楼状态改变
* @event {Function} refresh 自定义下拉刷新被触发
* @event {Function} restore 自定义下拉刷新被复位
* @event {Function} loadingStatusChange 自定义下拉刷新状态改变
* @event {Function} emptyViewReload 点击了空数据图中的重新加载按钮
* @event {Function} emptyViewClick 点击了空数据图view
* @event {Function} isLoadFailedChange z-paging请求失败状态改变
* @event {Function} backToTopClick 点击了返回顶部按钮
* @event {Function} virtualListChange 虚拟列表当前渲染的数组改变时触发
* @event {Function} innerCellClick 使用虚拟列表或内置列表时点击了cell
* @event {Function} virtualPlaceholderTopHeight 虚拟列表顶部占位高度改变
* @event {Function} hidedKeyboard 在聊天记录模式下,触摸列表隐藏了键盘
* @event {Function} keyboardHeightChange 键盘高度改变
* @event {Function} scroll z-paging列表滚动时触发
* @event {Function} scrollTopChange scrollTop改变时触发
* @event {Function} scrolltolower z-paging内置的scroll-view/list-view/waterfall滚动底部时触发
* @event {Function} scrolltoupper z-paging内置的scroll-view/list-view/waterfall滚动顶部时触发
* @event {Function} scrollend z-paging内置的list滚动结束时触发
* @event {Function} contentHeightChanged z-paging中内容高度改变时触发
* @event {Function} touchDirectionChange 监听列表触摸方向改变
* @example <z-paging ref="paging" v-model="dataList" @query="queryList"></z-paging>
*/
export default {
@@ -337,7 +525,12 @@ by ZXLee
// #endif
}
</script>
<script src="./js/z-paging-main.js" />
<!-- #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5 -->
<script src="./wxs/z-paging-wxs.wxs" module="pagingWxs" lang="wxs"></script>
<!-- #endif -->
<style scoped>
@import "./css/z-paging-main.css";