Commit 7399632e424ccf902533a6c2aafdf15a31bc8cff

Authored by guzijian
1 parent 6dcb91e5

feat: 新增订单样式

Showing 30 changed files with 4836 additions and 0 deletions

Too many changes to show.

To preserve performance only 30 of 51 files are displayed.

garbage-removal/src/components/z-paging-cell/z-paging-cell.vue 0 → 100644
  1 +<!-- z-paging -->
  2 +<!-- github地址:https://github.com/SmileZXLee/uni-z-paging -->
  3 +<!-- dcloud地址:https://ext.dcloud.net.cn/plugin?id=3935 -->
  4 +<!-- 反馈QQ群:790460711 -->
  5 +
  6 +<!-- z-paging-cell,用于在nvue中使用cell包裹,vue中使用view包裹 -->
  7 +<template>
  8 + <!-- #ifdef APP-NVUE -->
  9 + <cell :style="[cellStyle]">
  10 + <slot />
  11 + </cell>
  12 + <!-- #endif -->
  13 + <!-- #ifndef APP-NVUE -->
  14 + <view :style="[cellStyle]">
  15 + <slot />
  16 + </view>
  17 + <!-- #endif -->
  18 +</template>
  19 +
  20 +<script>
  21 + export default {
  22 + name: "z-paging-cell",
  23 + props: {
  24 + //cellStyle
  25 + cellStyle: {
  26 + type: Object,
  27 + default: function() {
  28 + return {}
  29 + }
  30 + }
  31 + }
  32 + }
  33 +</script>
  34 +
garbage-removal/src/components/z-paging-empty-view/z-paging-empty-view.vue 0 → 100644
  1 +<!-- z-paging -->
  2 +<!-- github地址:https://github.com/SmileZXLee/uni-z-paging -->
  3 +<!-- dcloud地址:https://ext.dcloud.net.cn/plugin?id=3935 -->
  4 +<!-- 反馈QQ群:790460711 -->
  5 +
  6 +<!-- 空数据占位view,此组件支持easycom规范,可以在项目中直接引用 -->
  7 +<template>
  8 + <view :class="{'zp-container':true,'zp-container-fixed':emptyViewFixed}" :style="[finalEmptyViewStyle]" @click="emptyViewClick">
  9 + <view class="zp-main">
  10 + <image v-if="!emptyViewImg.length" class="zp-main-image" :style="[emptyViewImgStyle]" :src="emptyImg" />
  11 + <image v-else class="zp-main-image" mode="aspectFit" :style="[emptyViewImgStyle]" :src="emptyViewImg" />
  12 + <text class="zp-main-title" :style="[emptyViewTitleStyle]">{{emptyViewText}}</text>
  13 + <text v-if="showEmptyViewReload" class="zp-main-error-btn" :style="[emptyViewReloadStyle]" @click.stop="reloadClick">{{emptyViewReloadText}}</text>
  14 + </view>
  15 + </view>
  16 +</template>
  17 +
  18 +<script>
  19 + import zStatic from '../z-paging/js/z-paging-static'
  20 + export default {
  21 + name: "z-paging-empty-view",
  22 + data() {
  23 + return {
  24 +
  25 + };
  26 + },
  27 + props: {
  28 + //空数据描述文字
  29 + emptyViewText: {
  30 + type: String,
  31 + default: '没有数据哦~'
  32 + },
  33 + //空数据图片
  34 + emptyViewImg: {
  35 + type: String,
  36 + default: ''
  37 + },
  38 + //是否显示空数据图重新加载按钮
  39 + showEmptyViewReload: {
  40 + type: Boolean,
  41 + default: false
  42 + },
  43 + //空数据点击重新加载文字
  44 + emptyViewReloadText: {
  45 + type: String,
  46 + default: '重新加载'
  47 + },
  48 + //是否是加载失败
  49 + isLoadFailed: {
  50 + type: Boolean,
  51 + default: false
  52 + },
  53 + //空数据图样式
  54 + emptyViewStyle: {
  55 + type: Object,
  56 + default: function() {
  57 + return {}
  58 + }
  59 + },
  60 + //空数据图img样式
  61 + emptyViewImgStyle: {
  62 + type: Object,
  63 + default: function() {
  64 + return {}
  65 + }
  66 + },
  67 + //空数据图描述文字样式
  68 + emptyViewTitleStyle: {
  69 + type: Object,
  70 + default: function() {
  71 + return {}
  72 + }
  73 + },
  74 + //空数据图重新加载按钮样式
  75 + emptyViewReloadStyle: {
  76 + type: Object,
  77 + default: function() {
  78 + return {}
  79 + }
  80 + },
  81 + //空数据图z-index
  82 + emptyViewZIndex: {
  83 + type: Number,
  84 + default: 9
  85 + },
  86 + //空数据图片是否使用fixed布局并铺满z-paging
  87 + emptyViewFixed: {
  88 + type: Boolean,
  89 + default: true
  90 + }
  91 + },
  92 + computed: {
  93 + emptyImg() {
  94 + return this.isLoadFailed ? zStatic.base64Error : zStatic.base64Empty;
  95 + },
  96 + finalEmptyViewStyle(){
  97 + this.emptyViewStyle['z-index'] = this.emptyViewZIndex;
  98 + return this.emptyViewStyle;
  99 + }
  100 + },
  101 + methods: {
  102 + reloadClick() {
  103 + this.$emit('reload');
  104 + },
  105 + emptyViewClick() {
  106 + this.$emit('viewClick');
  107 + }
  108 + }
  109 + }
  110 +</script>
  111 +
  112 +<style scoped>
  113 + .zp-container{
  114 + /* #ifndef APP-NVUE */
  115 + display: flex;
  116 + /* #endif */
  117 + align-items: center;
  118 + justify-content: center;
  119 + }
  120 + .zp-container-fixed {
  121 + /* #ifndef APP-NVUE */
  122 + position: absolute;
  123 + top: 0;
  124 + left: 0;
  125 + width: 100%;
  126 + height: 100%;
  127 + /* #endif */
  128 + /* #ifdef APP-NVUE */
  129 + flex: 1;
  130 + /* #endif */
  131 + }
  132 +
  133 + .zp-main{
  134 + /* #ifndef APP-NVUE */
  135 + display: flex;
  136 + /* #endif */
  137 + flex-direction: column;
  138 + align-items: center;
  139 + padding: 50rpx 0rpx;
  140 + }
  141 +
  142 + .zp-main-image {
  143 + width: 200rpx;
  144 + height: 200rpx;
  145 + }
  146 +
  147 + .zp-main-title {
  148 + font-size: 26rpx;
  149 + color: #aaaaaa;
  150 + text-align: center;
  151 + margin-top: 10rpx;
  152 + }
  153 +
  154 + .zp-main-error-btn {
  155 + font-size: 26rpx;
  156 + padding: 8rpx 24rpx;
  157 + border: solid 1px #dddddd;
  158 + border-radius: 6rpx;
  159 + color: #aaaaaa;
  160 + margin-top: 50rpx;
  161 + }
  162 +</style>
garbage-removal/src/components/z-paging-swiper-item/z-paging-swiper-item.vue 0 → 100644
  1 +<!-- z-paging -->
  2 +<!-- github地址:https://github.com/SmileZXLee/uni-z-paging -->
  3 +<!-- dcloud地址:https://ext.dcloud.net.cn/plugin?id=3935 -->
  4 +<!-- 反馈QQ群:790460711 -->
  5 +
  6 +<!-- 滑动切换选项卡swiper-item,此组件支持easycom规范,可以在项目中直接引用 -->
  7 +<template>
  8 + <view class="zp-swiper-item-container">
  9 + <z-paging ref="paging" :fixed="false"
  10 + :auto="false" :useVirtualList="useVirtualList" :useInnerList="useInnerList" :cellKeyName="cellKeyName" :innerListStyle="innerListStyle"
  11 + :preloadPage="preloadPage" :cellHeightMode="cellHeightMode" :virtualScrollFps="virtualScrollFps" :virtualListCol="virtualListCol"
  12 + @query="_queryList" @listChange="_updateList" style="height: 100%;">
  13 + <slot />
  14 + <template #header>
  15 + <slot name="header"/>
  16 + </template>
  17 + <template #cell="{item,index}">
  18 + <slot name="cell" :item="item" :index="index"/>
  19 + </template>
  20 + <template #footer>
  21 + <slot name="footer"/>
  22 + </template>
  23 + </z-paging>
  24 + </view>
  25 +</template>
  26 +
  27 +<script>
  28 + import zPaging from '../z-paging/z-paging'
  29 + export default {
  30 + name: "z-paging-swiper-item",
  31 + components: { zPaging },
  32 + data() {
  33 + return {
  34 + firstLoaded: false
  35 + }
  36 + },
  37 + props: {
  38 + //当前组件的index,也就是当前组件是swiper中的第几个
  39 + tabIndex: {
  40 + type: Number,
  41 + default: function() {
  42 + return 0
  43 + }
  44 + },
  45 + //当前swiper切换到第几个index
  46 + currentIndex: {
  47 + type: Number,
  48 + default: function() {
  49 + return 0
  50 + }
  51 + },
  52 + //是否使用虚拟列表,默认为否
  53 + useVirtualList: {
  54 + type: Boolean,
  55 + default: false
  56 + },
  57 + //是否在z-paging内部循环渲染列表(内置列表),默认为否。若use-virtual-list为true,则此项恒为true
  58 + useInnerList: {
  59 + type: Boolean,
  60 + default: false
  61 + },
  62 + //内置列表cell的key名称,仅nvue有效,在nvue中开启use-inner-list时必须填此项
  63 + cellKeyName: {
  64 + type: String,
  65 + default: ''
  66 + },
  67 + //innerList样式
  68 + innerListStyle: {
  69 + type: Object,
  70 + default: function() {
  71 + return {};
  72 + }
  73 + },
  74 + //预加载的列表可视范围(列表高度)页数,默认为12,即预加载当前页及上下各12页的cell。此数值越大,则虚拟列表中加载的dom越多,内存消耗越大(会维持在一个稳定值),但增加预加载页面数量可缓解快速滚动短暂白屏问题
  75 + preloadPage: {
  76 + type: [Number, String],
  77 + default: 12
  78 + },
  79 + //虚拟列表cell高度模式,默认为fixed,也就是每个cell高度完全相同,将以第一个cell高度为准进行计算。可选值【dynamic】,即代表高度是动态非固定的,【dynamic】性能低于【fixed】。
  80 + cellHeightMode: {
  81 + type: String,
  82 + default: 'fixed'
  83 + },
  84 + //虚拟列表列数,默认为1。常用于每行有多列的情况,例如每行有2列数据,需要将此值设置为2
  85 + virtualListCol: {
  86 + type: [Number, String],
  87 + default: 1
  88 + },
  89 + //虚拟列表scroll取样帧率,默认为60,过高可能出现卡顿等问题
  90 + virtualScrollFps: {
  91 + type: [Number, String],
  92 + default: 60
  93 + },
  94 + },
  95 + watch: {
  96 + currentIndex: {
  97 + handler(newVal, oldVal) {
  98 + if (newVal === this.tabIndex) {
  99 + //懒加载,当滑动到当前的item时,才去加载
  100 + if (!this.firstLoaded) {
  101 + this.$nextTick(()=>{
  102 + let delay = 5;
  103 + // #ifdef MP-TOUTIAO
  104 + delay = 100;
  105 + // #endif
  106 + setTimeout(() => {
  107 + this.$refs.paging.reload().catch(() => {});
  108 + }, delay);
  109 + })
  110 + }
  111 + }
  112 + },
  113 + immediate: true
  114 + }
  115 + },
  116 + methods: {
  117 + reload(data) {
  118 + return this.$refs.paging.reload(data);
  119 + },
  120 + complete(data) {
  121 + this.firstLoaded = true;
  122 + return this.$refs.paging.complete(data);
  123 + },
  124 + _queryList(pageNo, pageSize, from) {
  125 + this.$emit('query', pageNo, pageSize, from);
  126 + },
  127 + _updateList(list) {
  128 + this.$emit('updateList', list);
  129 + }
  130 + }
  131 + }
  132 +</script>
  133 +
  134 +<style scoped>
  135 + .zp-swiper-item-container {
  136 + /* #ifndef APP-NVUE */
  137 + height: 100%;
  138 + /* #endif */
  139 + /* #ifdef APP-NVUE */
  140 + flex: 1;
  141 + /* #endif */
  142 + }
  143 +</style>
garbage-removal/src/components/z-paging-swiper/z-paging-swiper.vue 0 → 100644
  1 +<!-- z-paging -->
  2 +<!-- github地址:https://github.com/SmileZXLee/uni-z-paging -->
  3 +<!-- dcloud地址:https://ext.dcloud.net.cn/plugin?id=3935 -->
  4 +<!-- 反馈QQ群:790460711 -->
  5 +
  6 +<!-- 滑动切换选项卡swiper容器,此组件支持easycom规范,可以在项目中直接引用 -->
  7 +<template>
  8 + <view :class="fixed?'zp-swiper-container zp-swiper-container-fixed':'zp-swiper-container'" :style="[finalSwiperStyle]">
  9 + <!-- #ifndef APP-PLUS -->
  10 + <view v-if="cssSafeAreaInsetBottom===-1" class="zp-safe-area-inset-bottom"></view>
  11 + <!-- #endif -->
  12 + <slot v-if="zSlots.top" name="top" />
  13 + <view class="zp-swiper-super">
  14 + <view v-if="zSlots.left" :class="{'zp-swiper-left':true,'zp-absoulte':isOldWebView}">
  15 + <slot name="left" />
  16 + </view>
  17 + <view :class="{'zp-swiper':true,'zp-absoulte':isOldWebView}" :style="[swiperContentStyle]">
  18 + <slot />
  19 + </view>
  20 + <view v-if="zSlots.right" :class="{'zp-swiper-right':true,'zp-absoulte zp-right':isOldWebView}">
  21 + <slot name="right" />
  22 + </view>
  23 + </view>
  24 + <slot v-if="zSlots.bottom" name="bottom" />
  25 + </view>
  26 +</template>
  27 +
  28 +<script>
  29 + import commonLayoutModule from '../z-paging/js/modules/common-layout'
  30 +
  31 + export default {
  32 + name: "z-paging-swiper",
  33 + mixins: [commonLayoutModule],
  34 + data() {
  35 + return {
  36 + swiperContentStyle: {}
  37 + };
  38 + },
  39 + props: {
  40 + //是否使用fixed布局,默认为是
  41 + fixed: {
  42 + type: Boolean,
  43 + default: true
  44 + },
  45 + //是否开启底部安全区域适配
  46 + safeAreaInsetBottom: {
  47 + type: Boolean,
  48 + default: false
  49 + },
  50 + //z-paging-swiper样式
  51 + swiperStyle: {
  52 + type: Object,
  53 + default: function() {
  54 + return {};
  55 + },
  56 + }
  57 + },
  58 + mounted() {
  59 + this.$nextTick(() => {
  60 + this.systemInfo = uni.getSystemInfoSync();
  61 + })
  62 + // #ifndef APP-PLUS
  63 + this._getCssSafeAreaInsetBottom();
  64 + // #endif
  65 + this.updateLeftAndRightWidth();
  66 +
  67 + this.swiperContentStyle = { 'flex': '1' };
  68 + // #ifndef APP-NVUE
  69 + this.swiperContentStyle = { width: '100%',height: '100%' };
  70 + // #endif
  71 + },
  72 + computed: {
  73 + finalSwiperStyle() {
  74 + const swiperStyle = this.swiperStyle;
  75 + if (!this.systemInfo) return swiperStyle;
  76 + const windowTop = this.windowTop;
  77 + const windowBottom = this.systemInfo.windowBottom;
  78 + if (this.fixed) {
  79 + if (windowTop && !swiperStyle.top) {
  80 + swiperStyle.top = windowTop + 'px';
  81 + }
  82 + if (!swiperStyle.bottom) {
  83 + let bottom = windowBottom || 0;
  84 + bottom += this.safeAreaInsetBottom ? this.safeAreaBottom : 0;
  85 + if (bottom > 0) {
  86 + swiperStyle.bottom = bottom + 'px';
  87 + }
  88 + }
  89 + }
  90 + return swiperStyle;
  91 + }
  92 + },
  93 + methods: {
  94 + //更新slot="left"和slot="right"宽度,当slot="left"或slot="right"宽度动态改变时调用
  95 + updateLeftAndRightWidth() {
  96 + if (!this.isOldWebView) return;
  97 + this.$nextTick(() => this._updateLeftAndRightWidth(this.swiperContentStyle, 'zp-swiper'));
  98 + }
  99 + }
  100 + }
  101 +</script>
  102 +
  103 +<style scoped>
  104 + .zp-swiper-container {
  105 + /* #ifndef APP-NVUE */
  106 + display: flex;
  107 + /* #endif */
  108 + flex-direction: column;
  109 + flex: 1;
  110 + }
  111 +
  112 + .zp-swiper-container-fixed {
  113 + position: fixed;
  114 + /* #ifndef APP-NVUE */
  115 + height: auto;
  116 + width: auto;
  117 + /* #endif */
  118 + top: 0;
  119 + left: 0;
  120 + bottom: 0;
  121 + right: 0;
  122 + }
  123 +
  124 + .zp-safe-area-inset-bottom {
  125 + position: absolute;
  126 + /* #ifndef APP-PLUS */
  127 + height: env(safe-area-inset-bottom);
  128 + /* #endif */
  129 + }
  130 +
  131 + .zp-swiper-super {
  132 + flex: 1;
  133 + overflow: hidden;
  134 + position: relative;
  135 + /* #ifndef APP-NVUE */
  136 + display: flex;
  137 + /* #endif */
  138 + flex-direction: row;
  139 + }
  140 +
  141 + .zp-swiper-left,.zp-swiper-right{
  142 + /* #ifndef APP-NVUE */
  143 + height: 100%;
  144 + /* #endif */
  145 + }
  146 +
  147 + .zp-swiper {
  148 + flex: 1;
  149 + /* #ifndef APP-NVUE */
  150 + height: 100%;
  151 + width: 100%;
  152 + /* #endif */
  153 + }
  154 +
  155 + .zp-absoulte {
  156 + /* #ifndef APP-NVUE */
  157 + position: absolute;
  158 + top: 0;
  159 + width: auto;
  160 + /* #endif */
  161 + }
  162 +
  163 + .zp-right{
  164 + right: 0;
  165 + }
  166 +
  167 + .zp-swiper-item {
  168 + height: 100%;
  169 + }
  170 +</style>
garbage-removal/src/components/z-paging/components/z-paging-load-more.vue 0 → 100644
  1 +<!-- [z-paging]上拉加载更多view -->
  2 +<template>
  3 + <view class="zp-l-container" :style="[c.customStyle]" @click="doClick">
  4 + <template v-if="!c.hideContent">
  5 + <text v-if="c.showNoMoreLine&&finalStatus===M.NoMore" class="zp-l-line" :style="[{backgroundColor:zTheme.line[ts]},c.noMoreLineCustomStyle]" />
  6 + <!-- #ifndef APP-NVUE -->
  7 + <image v-if="finalStatus===M.Loading&&!!c.loadingIconCustomImage"
  8 + :src="c.loadingIconCustomImage" :style="[c.iconCustomStyle]" :class="{'zp-l-line-loading-custom-image':true,'zp-l-line-loading-custom-image-animated':c.loadingAnimated}" />
  9 + <image v-if="finalStatus===M.Loading&&finalLoadingIconType==='flower'&&!c.loadingIconCustomImage.length"
  10 + class="zp-line-loading-image" :style="[c.iconCustomStyle]" :src="zTheme.flower[ts]" />
  11 + <!-- #endif -->
  12 + <!-- #ifdef APP-NVUE -->
  13 + <view>
  14 + <loading-indicator v-if="finalStatus===M.Loading&&finalLoadingIconType!=='circle'" class="zp-line-loading-image" :style="[{color:zTheme.indicator[ts]}]" :animating="true" />
  15 + </view>
  16 + <!-- #endif -->
  17 + <text v-if="finalStatus===M.Loading&&finalLoadingIconType==='circle'&&!c.loadingIconCustomImage.length"
  18 + class="zp-l-circle-loading-view" :style="[{borderColor:zTheme.circleBorder[ts],borderTopColor:zTheme.circleBorderTop[ts]},c.iconCustomStyle]" />
  19 + <text class="zp-l-text" :style="[{color:zTheme.title[ts]},c.titleCustomStyle]">{{ownLoadingMoreText}}</text>
  20 + <text v-if="c.showNoMoreLine&&finalStatus===M.NoMore" class="zp-l-line" :style="[{backgroundColor:zTheme.line[ts]},c.noMoreLineCustomStyle]" />
  21 + </template>
  22 + </view>
  23 +</template>
  24 +<script>
  25 + import zStatic from '../js/z-paging-static'
  26 + import Enum from '../js/z-paging-enum'
  27 + export default {
  28 + name: 'z-paging-load-more',
  29 + data() {
  30 + return {
  31 + M: Enum.More,
  32 + zTheme: {
  33 + title: { white: '#efefef', black: '#a4a4a4' },
  34 + line: { white: '#efefef', black: '#eeeeee' },
  35 + circleBorder: { white: '#aaaaaa', black: '#c8c8c8' },
  36 + circleBorderTop: { white: '#ffffff', black: '#444444' },
  37 + flower: { white: zStatic.base64FlowerWhite, black: zStatic.base64Flower },
  38 + indicator: { white: '#eeeeee', black: '#777777' }
  39 + }
  40 + };
  41 + },
  42 + props: ['zConfig'],
  43 + computed: {
  44 + ts() {
  45 + return this.c.defaultThemeStyle;
  46 + },
  47 + c() {
  48 + return this.zConfig || {};
  49 + },
  50 + ownLoadingMoreText() {
  51 + const statusTextArr = [this.c.defaultText,this.c.loadingText,this.c.noMoreText,this.c.failText];
  52 + return statusTextArr[this.finalStatus];
  53 + },
  54 + finalStatus() {
  55 + if (this.c.defaultAsLoading && this.c.status === this.M.Default) return this.M.Loading;
  56 + return this.c.status;
  57 + },
  58 + finalLoadingIconType() {
  59 + // #ifdef APP-NVUE
  60 + return 'flower';
  61 + // #endif
  62 + return this.c.loadingIconType;
  63 + }
  64 + },
  65 + methods: {
  66 + doClick() {
  67 + this.$emit('doClick');
  68 + }
  69 + }
  70 + }
  71 +</script>
  72 +
  73 +<style scoped>
  74 + @import "../css/z-paging-static.css";
  75 +
  76 + .zp-l-container {
  77 + height: 80rpx;
  78 + font-size: 27rpx;
  79 + /* #ifndef APP-NVUE */
  80 + clear: both;
  81 + display: flex;
  82 + /* #endif */
  83 + flex-direction: row;
  84 + align-items: center;
  85 + justify-content: center;
  86 + }
  87 +
  88 + .zp-l-line-loading-custom-image {
  89 + color: #a4a4a4;
  90 + margin-right: 8rpx;
  91 + width: 28rpx;
  92 + height: 28rpx;
  93 + }
  94 +
  95 + .zp-l-line-loading-custom-image-animated{
  96 + /* #ifndef APP-NVUE */
  97 + animation: loading-circle 1s linear infinite;
  98 + /* #endif */
  99 + }
  100 +
  101 + .zp-l-circle-loading-view {
  102 + margin-right: 8rpx;
  103 + width: 23rpx;
  104 + height: 23rpx;
  105 + border: 3rpx solid #dddddd;
  106 + border-radius: 50%;
  107 + /* #ifndef APP-NVUE */
  108 + animation: loading-circle 1s linear infinite;
  109 + /* #endif */
  110 + /* #ifdef APP-NVUE */
  111 + width: 30rpx;
  112 + height: 30rpx;
  113 + /* #endif */
  114 + }
  115 +
  116 + .zp-l-text {
  117 + /* #ifdef APP-NVUE */
  118 + font-size: 30rpx;
  119 + margin: 0rpx 10rpx;
  120 + /* #endif */
  121 + }
  122 +
  123 + .zp-l-line {
  124 + height: 1px;
  125 + width: 100rpx;
  126 + margin: 0rpx 10rpx;
  127 + }
  128 +
  129 + /* #ifndef APP-NVUE */
  130 + @keyframes loading-circle {
  131 + 0% {
  132 + -webkit-transform: rotate(0deg);
  133 + transform: rotate(0deg);
  134 + }
  135 + 100% {
  136 + -webkit-transform: rotate(360deg);
  137 + transform: rotate(360deg);
  138 + }
  139 + }
  140 + /* #endif */
  141 +</style>
garbage-removal/src/components/z-paging/components/z-paging-refresh.vue 0 → 100644
  1 +<!-- [z-paging]下拉刷新view -->
  2 +<template>
  3 + <view style="height: 100%;">
  4 + <view :class="showUpdateTime?'zp-r-container zp-r-container-padding':'zp-r-container'">
  5 + <view class="zp-r-left">
  6 + <image v-if="status!==R.Loading" :class="leftImageClass" :style="[leftImageStyle,imgStyle]" :src="leftImageSrc" />
  7 + <!-- #ifndef APP-NVUE -->
  8 + <image v-else :class="{'zp-line-loading-image':refreshingAnimated,'zp-r-left-image':true}" :style="[leftImageStyle,imgStyle]" :src="leftImageSrc" />
  9 + <!-- #endif -->
  10 + <!-- #ifdef APP-NVUE -->
  11 + <view v-else :style="[{'margin-right':showUpdateTime?'18rpx':'12rpx'}]">
  12 + <loading-indicator :class="isIos?'zp-loading-image-ios':'zp-loading-image-android'"
  13 + :style="[{color:zTheme.indicator[ts]},imgStyle]" :animating="true" />
  14 + </view>
  15 + <!-- #endif -->
  16 + </view>
  17 + <view class="zp-r-right">
  18 + <text class="zp-r-right-text" :style="[rightTextStyle,titleStyle]">{{currentTitle}}</text>
  19 + <text v-if="showUpdateTime&&refresherTimeText.length" class="zp-r-right-text zp-r-right-time-text" :style="[rightTextStyle,updateTimeStyle]">
  20 + {{refresherTimeText}}
  21 + </text>
  22 + </view>
  23 + </view>
  24 + </view>
  25 +</template>
  26 +<script>
  27 + import zStatic from '../js/z-paging-static'
  28 + import u from '../js/z-paging-utils'
  29 + import Enum from '../js/z-paging-enum'
  30 +
  31 + export default {
  32 + name: 'z-paging-refresh',
  33 + data() {
  34 + return {
  35 + R: Enum.Refresher,
  36 + isIos: uni.getSystemInfoSync().platform === 'ios',
  37 + refresherTimeText: '',
  38 + zTheme: {
  39 + title: { white: '#efefef', black: '#555555' },
  40 + arrow: { white: zStatic.base64ArrowWhite, black: zStatic.base64Arrow },
  41 + flower: { white: zStatic.base64FlowerWhite, black: zStatic.base64Flower },
  42 + success: { white: zStatic.base64SuccessWhite, black: zStatic.base64Success },
  43 + indicator: { white: '#eeeeee', black: '#777777' }
  44 + }
  45 + };
  46 + },
  47 + props: ['status', 'defaultThemeStyle', 'defaultText', 'pullingText', 'refreshingText', 'completeText', 'defaultImg', 'pullingImg',
  48 + 'refreshingImg', 'completeImg', 'refreshingAnimated', 'showUpdateTime', 'updateTimeKey', 'imgStyle', 'titleStyle', 'updateTimeStyle', 'updateTimeTextMap'
  49 + ],
  50 + computed: {
  51 + ts() {
  52 + return this.defaultThemeStyle;
  53 + },
  54 + statusTextArr() {
  55 + this.updateTime();
  56 + return [this.defaultText,this.pullingText,this.refreshingText,this.completeText];
  57 + },
  58 + currentTitle() {
  59 + return this.statusTextArr[this.status] || this.defaultText;
  60 + },
  61 + leftImageClass() {
  62 + if (this.status === this.R.Complete) return 'zp-r-left-image-pre-size';
  63 + return `zp-r-left-image zp-r-left-image-pre-size ${this.status === this.R.Default ? 'zp-r-arrow-down' : 'zp-r-arrow-top'}`;
  64 + },
  65 + leftImageStyle() {
  66 + const showUpdateTime = this.showUpdateTime;
  67 + const size = showUpdateTime ? '36rpx' : '30rpx';
  68 + return {width: size,height: size,'margin-right': showUpdateTime ? '20rpx' : '9rpx'};
  69 + },
  70 + leftImageSrc() {
  71 + const R = this.R;
  72 + const status = this.status;
  73 + if (status === R.Default) {
  74 + if (!!this.defaultImg) return this.defaultImg;
  75 + return this.zTheme.arrow[this.ts];
  76 + } else if (status === R.ReleaseToRefresh) {
  77 + if (!!this.pullingImg) return this.pullingImg;
  78 + if (!!this.defaultImg) return this.defaultImg;
  79 + return this.zTheme.arrow[this.ts];
  80 + } else if (status === R.Loading) {
  81 + if (!!this.refreshingImg) return this.refreshingImg;
  82 + return this.zTheme.flower[this.ts];;
  83 + } else if (status === R.Complete) {
  84 + if (!!this.completeImg) return this.completeImg;
  85 + return this.zTheme.success[this.ts];;
  86 + }
  87 + return '';
  88 + },
  89 + rightTextStyle() {
  90 + let stl = {};
  91 + // #ifdef APP-NVUE
  92 + const textHeight = this.showUpdateTime ? '40rpx' : '80rpx';
  93 + stl = {'height': textHeight, 'line-height': textHeight}
  94 + // #endif
  95 + stl['color'] = this.zTheme.title[this.ts];
  96 + return stl;
  97 + }
  98 + },
  99 + methods: {
  100 + updateTime() {
  101 + if (this.showUpdateTime) {
  102 + this.refresherTimeText = u.getRefesrherFormatTimeByKey(this.updateTimeKey, this.updateTimeTextMap);
  103 + }
  104 + }
  105 + }
  106 + }
  107 +</script>
  108 +
  109 +<style scoped>
  110 + @import "../css/z-paging-static.css";
  111 +
  112 + .zp-r-container {
  113 + /* #ifndef APP-NVUE */
  114 + display: flex;
  115 + height: 100%;
  116 + /* #endif */
  117 + flex-direction: row;
  118 + justify-content: center;
  119 + align-items: center;
  120 + }
  121 +
  122 + .zp-r-container-padding {
  123 + /* #ifdef APP-NVUE */
  124 + padding: 15rpx 0rpx;
  125 + /* #endif */
  126 + }
  127 +
  128 + .zp-r-left {
  129 + /* #ifndef APP-NVUE */
  130 + display: flex;
  131 + /* #endif */
  132 + flex-direction: row;
  133 + align-items: center;
  134 + overflow: hidden;
  135 + /* #ifdef MP-ALIPAY */
  136 + margin-top: -4rpx;
  137 + /* #endif */
  138 + }
  139 +
  140 + .zp-r-left-image {
  141 + transition-duration: .2s;
  142 + transition-property: transform;
  143 + color: #666666;
  144 + }
  145 +
  146 + .zp-r-left-image-pre-size{
  147 + /* #ifndef APP-NVUE */
  148 + width: 30rpx;
  149 + height: 30rpx;
  150 + overflow: hidden;
  151 + /* #endif */
  152 + }
  153 +
  154 + .zp-r-arrow-top {
  155 + transform: rotate(0deg);
  156 + }
  157 +
  158 + .zp-r-arrow-down {
  159 + transform: rotate(180deg);
  160 + }
  161 +
  162 + .zp-r-right {
  163 + font-size: 27rpx;
  164 + /* #ifndef APP-NVUE */
  165 + display: flex;
  166 + /* #endif */
  167 + flex-direction: column;
  168 + align-items: center;
  169 + justify-content: center;
  170 + }
  171 +
  172 + .zp-r-right-text {
  173 + /* #ifdef APP-NVUE */
  174 + font-size: 28rpx;
  175 + /* #endif */
  176 + }
  177 +
  178 + .zp-r-right-time-text {
  179 + margin-top: 10rpx;
  180 + font-size: 24rpx;
  181 + }
  182 +</style>
garbage-removal/src/components/z-paging/config/index.js 0 → 100644
  1 +// z-paging全局配置文件,注意避免更新时此文件被覆盖,若被覆盖,可在此文件中右键->点击本地历史记录,找回覆盖前的配置
  2 +
  3 +export default {}
0 \ No newline at end of file 4 \ No newline at end of file
garbage-removal/src/components/z-paging/css/z-paging-main.css 0 → 100644
  1 +/* [z-paging]公共css*/
  2 +
  3 +.z-paging-content {
  4 + position: relative;
  5 + /* #ifndef APP-NVUE */
  6 + display: flex;
  7 + width: 100%;
  8 + height: 100%;
  9 + overflow: hidden;
  10 + /* #endif */
  11 + flex-direction: column;
  12 +}
  13 +
  14 +.z-paging-content-fixed, .zp-loading-fixed {
  15 + position: fixed;
  16 + /* #ifndef APP-NVUE */
  17 + height: auto;
  18 + width: auto;
  19 + /* #endif */
  20 + top: 0;
  21 + left: 0;
  22 + bottom: 0;
  23 + right: 0;
  24 +}
  25 +
  26 +.zp-page-top,.zp-page-bottom {
  27 + /* #ifndef APP-NVUE */
  28 + width: auto;
  29 + /* #endif */
  30 + position: fixed;
  31 + left: 0;
  32 + right: 0;
  33 + z-index: 999;
  34 +}
  35 +
  36 +.zp-page-left,.zp-page-right{
  37 + /* #ifndef APP-NVUE */
  38 + height: 100%;
  39 + /* #endif */
  40 +}
  41 +
  42 +.zp-scroll-view-super {
  43 + flex: 1;
  44 + overflow: hidden;
  45 + position: relative;
  46 +}
  47 +
  48 +.zp-view-super{
  49 + /* #ifndef APP-NVUE */
  50 + display: flex;
  51 + /* #endif */
  52 + flex-direction: row;
  53 +}
  54 +
  55 +.zp-scroll-view-container,.zp-scroll-view {
  56 + position: relative;
  57 + /* #ifndef APP-NVUE */
  58 + height: 100%;
  59 + width: 100%;
  60 + /* #endif */
  61 +}
  62 +
  63 +.zp-absoulte{
  64 + /* #ifndef APP-NVUE */
  65 + position: absolute;
  66 + top: 0;
  67 + width: auto;
  68 + /* #endif */
  69 +}
  70 +
  71 +.zp-right{
  72 + right: 0;
  73 +}
  74 +
  75 +.zp-scroll-view-absolute {
  76 + position: absolute;
  77 + top: 0;
  78 + left: 0;
  79 +}
  80 +
  81 +/* #ifndef APP-NVUE */
  82 +.zp-scroll-view-hide-scrollbar ::-webkit-scrollbar {
  83 + display: none;
  84 + -webkit-appearance: none;
  85 + width: 0 !important;
  86 + height: 0 !important;
  87 + background: transparent;
  88 +}
  89 +/* #endif */
  90 +
  91 +.zp-paging-touch-view {
  92 + width: 100%;
  93 + height: 100%;
  94 + position: relative;
  95 +}
  96 +
  97 +.zp-fixed-bac-view {
  98 + position: absolute;
  99 + width: 100%;
  100 + top: 0;
  101 + left: 0;
  102 + height: 200px;
  103 +}
  104 +
  105 +.zp-paging-main {
  106 + height: 100%;
  107 + /* #ifndef APP-NVUE */
  108 + display: flex;
  109 + /* #endif */
  110 + flex-direction: column;
  111 +}
  112 +
  113 +.zp-paging-container {
  114 + flex: 1;
  115 + position: relative;
  116 + /* #ifndef APP-NVUE */
  117 + display: flex;
  118 + /* #endif */
  119 + flex-direction: column;
  120 +}
  121 +
  122 +.zp-chat-record-loading-container {
  123 + /* #ifndef APP-NVUE */
  124 + display: flex;
  125 + width: 100%;
  126 + /* #endif */
  127 + /* #ifdef APP-NVUE */
  128 + width: 750rpx;
  129 + /* #endif */
  130 + align-items: center;
  131 + justify-content: center;
  132 + height: 60rpx;
  133 + font-size: 26rpx;
  134 +}
  135 +
  136 +.zp-chat-record-loading-custom-image {
  137 + width: 35rpx;
  138 + height: 35rpx;
  139 + /* #ifndef APP-NVUE */
  140 + animation: loading-flower 1s linear infinite;
  141 + /* #endif */
  142 +}
  143 +
  144 +.zp-custom-refresher-container {
  145 + overflow: hidden;
  146 +}
  147 +
  148 +.zp-custom-refresher-refresh {
  149 + /* #ifndef APP-NVUE */
  150 + display: block;
  151 + /* #endif */
  152 +}
  153 +
  154 +.zp-back-to-top {
  155 + width: 76rpx;
  156 + height: 76rpx;
  157 + z-index: 999;
  158 + position: absolute;
  159 + bottom: 0rpx;
  160 + right: 25rpx;
  161 + transition-duration: .3s;
  162 + transition-property: opacity;
  163 +}
  164 +
  165 +.zp-back-to-top-show {
  166 + opacity: 1;
  167 +}
  168 +
  169 +.zp-back-to-top-hide {
  170 + opacity: 0;
  171 +}
  172 +
  173 +.zp-back-to-top-img {
  174 + /* #ifndef APP-NVUE */
  175 + width: 100%;
  176 + height: 100%;
  177 + /* #endif */
  178 + /* #ifdef APP-NVUE */
  179 + flex: 1;
  180 + /* #endif */
  181 + z-index: 999;
  182 +}
  183 +
  184 +.zp-empty-view {
  185 + /* #ifdef APP-NVUE */
  186 + height: 100%;
  187 + /* #endif */
  188 + flex: 1;
  189 +}
  190 +
  191 +.zp-empty-view-center {
  192 + /* #ifndef APP-NVUE */
  193 + display: flex;
  194 + /* #endif */
  195 + flex-direction: column;
  196 + align-items: center;
  197 + justify-content: center;
  198 +}
  199 +
  200 +.zp-loading-fixed {
  201 + z-index: 9999;
  202 +}
  203 +
  204 +.zp-safe-area-inset-bottom {
  205 + position: absolute;
  206 + /* #ifndef APP-PLUS */
  207 + height: env(safe-area-inset-bottom);
  208 + /* #endif */
  209 +}
  210 +
  211 +.zp-n-refresh-container {
  212 + /* #ifndef APP-NVUE */
  213 + display: flex;
  214 + /* #endif */
  215 + justify-content: center;
  216 + width: 750rpx;
  217 +}
  218 +
  219 +.zp-n-list-container{
  220 + /* #ifndef APP-NVUE */
  221 + display: flex;
  222 + /* #endif */
  223 + flex-direction: row;
  224 + flex: 1;
  225 +}
garbage-removal/src/components/z-paging/css/z-paging-static.css 0 → 100644
  1 +/* [z-paging]公用的静态css资源 */
  2 +
  3 +.zp-line-loading-image {
  4 + margin-right: 8rpx;
  5 + width: 28rpx;
  6 + height: 28rpx;
  7 + /* #ifndef APP-NVUE */
  8 + animation: loading-flower 1s steps(12) infinite;
  9 + /* #endif */
  10 + color: #666666;
  11 +}
  12 +
  13 +.zp-loading-image-ios{
  14 + width: 20px;
  15 + height: 20px;
  16 +}
  17 +
  18 +.zp-loading-image-android{
  19 + width: 32rpx;
  20 + height: 32rpx;
  21 +}
  22 +
  23 +/* #ifndef APP-NVUE */
  24 +@keyframes loading-flower {
  25 + 0% {
  26 + -webkit-transform: rotate(0deg);
  27 + transform: rotate(0deg);
  28 + }
  29 + to {
  30 + -webkit-transform: rotate(1turn);
  31 + transform: rotate(1turn);
  32 + }
  33 +}
  34 +/* #endif */
  35 +
garbage-removal/src/components/z-paging/i18n/en.json 0 → 100644
  1 +{
  2 + "zp.refresher.default": "Pull down to refresh",
  3 + "zp.refresher.pulling": "Release to refresh",
  4 + "zp.refresher.refreshing": "Refreshing...",
  5 + "zp.refresher.complete": "Refresh succeeded",
  6 +
  7 + "zp.loadingMore.default": "Click to load more",
  8 + "zp.loadingMore.loading": "Loading...",
  9 + "zp.loadingMore.noMore": "No more data",
  10 + "zp.loadingMore.fail": "Load failed,click to reload",
  11 +
  12 + "zp.emptyView.title": "No data",
  13 + "zp.emptyView.reload": "Reload",
  14 + "zp.emptyView.error": "Sorry,load failed",
  15 +
  16 + "zp.refresherUpdateTime.title": "Last update: ",
  17 + "zp.refresherUpdateTime.none": "None",
  18 + "zp.refresherUpdateTime.today": "Today",
  19 + "zp.refresherUpdateTime.yesterday": "Yesterday",
  20 +
  21 + "zp.systemLoading.title": "Loading..."
  22 +}
garbage-removal/src/components/z-paging/i18n/index.js 0 → 100644
  1 +import en from './en.json'
  2 +import zhHans from './zh-Hans.json'
  3 +import zhHant from './zh-Hant.json'
  4 +export default {
  5 + en,
  6 + 'zh-Hans': zhHans,
  7 + 'zh-Hant': zhHant
  8 +}
garbage-removal/src/components/z-paging/i18n/zh-Hans.json 0 → 100644
  1 +{
  2 + "zp.refresher.default": "继续下拉刷新",
  3 + "zp.refresher.pulling": "松开立即刷新",
  4 + "zp.refresher.refreshing": "正在刷新...",
  5 + "zp.refresher.complete": "刷新成功",
  6 +
  7 + "zp.loadingMore.default": "点击加载更多",
  8 + "zp.loadingMore.loading": "正在加载...",
  9 + "zp.loadingMore.noMore": "没有更多了",
  10 + "zp.loadingMore.fail": "加载失败,点击重新加载",
  11 +
  12 + "zp.emptyView.title": "没有数据哦~",
  13 + "zp.emptyView.reload": "重新加载",
  14 + "zp.emptyView.error": "很抱歉,加载失败",
  15 +
  16 + "zp.refresherUpdateTime.title": "最后更新:",
  17 + "zp.refresherUpdateTime.none": "无",
  18 + "zp.refresherUpdateTime.today": "今天",
  19 + "zp.refresherUpdateTime.yesterday": "昨天",
  20 +
  21 + "zp.systemLoading.title": "加载中..."
  22 +}
garbage-removal/src/components/z-paging/i18n/zh-Hant.json 0 → 100644
  1 +{
  2 + "zp.refresher.default": "繼續下拉重繪",
  3 + "zp.refresher.pulling": "鬆開立即重繪",
  4 + "zp.refresher.refreshing": "正在重繪...",
  5 + "zp.refresher.complete": "重繪成功",
  6 +
  7 + "zp.loadingMore.default": "點擊加載更多",
  8 + "zp.loadingMore.loading": "正在加載...",
  9 + "zp.loadingMore.noMore": "沒有更多了",
  10 + "zp.loadingMore.fail": "加載失敗,點擊重新加載",
  11 +
  12 + "zp.emptyView.title": "沒有數據哦~",
  13 + "zp.emptyView.reload": "重新加載",
  14 + "zp.emptyView.error": "很抱歉,加載失敗",
  15 +
  16 + "zp.refresherUpdateTime.title": "最後更新:",
  17 + "zp.refresherUpdateTime.none": "無",
  18 + "zp.refresherUpdateTime.today": "今天",
  19 + "zp.refresherUpdateTime.yesterday": "昨天",
  20 +
  21 + "zp.systemLoading.title": "加載中..."
  22 +}
garbage-removal/src/components/z-paging/js/hooks/useZPaging.js 0 → 100644
  1 +// [z-paging]useZPaging hooks
  2 +
  3 +import { onPageScroll, onReachBottom, onPullDownRefresh } from '@dcloudio/uni-app';
  4 +
  5 +function useZPaging(paging) {
  6 + const cPaging = !!paging ? paging.value || paging : null;
  7 +
  8 + onPullDownRefresh(() => {
  9 + if (!cPaging || !cPaging.value) return;
  10 + cPaging.value.reload().catch(() => {});
  11 + })
  12 +
  13 + onPageScroll(e => {
  14 + if (!cPaging || !cPaging.value) return;
  15 + cPaging.value.updatePageScrollTop(e.scrollTop);
  16 + e.scrollTop < 10 && cPaging.value.doChatRecordLoadMore();
  17 + })
  18 +
  19 + onReachBottom(() => {
  20 + if (!cPaging || !cPaging.value) return;
  21 + cPaging.value.pageReachBottom();
  22 + })
  23 +}
  24 +
  25 +export default useZPaging
0 \ No newline at end of file 26 \ No newline at end of file
garbage-removal/src/components/z-paging/js/hooks/useZPagingComp.js 0 → 100644
  1 +// [z-paging]useZPagingComp hooks
  2 +
  3 +function useZPagingComp(paging) {
  4 + const cPaging = !!paging ? paging.value || paging : null;
  5 +
  6 + const reload = () => {
  7 + if (!cPaging || !cPaging.value) return;
  8 + cPaging.value.reload().catch(() => {});
  9 + }
  10 + const updatePageScrollTop = scrollTop => {
  11 + if (!cPaging || !cPaging.value) return;
  12 + cPaging.value.updatePageScrollTop(scrollTop);
  13 + }
  14 + const doChatRecordLoadMore = () => {
  15 + if (!cPaging || !cPaging.value) return;
  16 + cPaging.value.doChatRecordLoadMore();
  17 + }
  18 + const pageReachBottom = () => {
  19 + if (!cPaging || !cPaging.value) return;
  20 + cPaging.value.pageReachBottom();
  21 + }
  22 + return { reload, updatePageScrollTop, doChatRecordLoadMore, pageReachBottom };
  23 +}
  24 +
  25 +export default useZPagingComp
0 \ No newline at end of file 26 \ No newline at end of file
garbage-removal/src/components/z-paging/js/modules/back-to-top.js 0 → 100644
  1 +// [z-paging]点击返回顶部view模块
  2 +import u from '.././z-paging-utils'
  3 +
  4 +export default {
  5 + props: {
  6 + //自动显示点击返回顶部按钮,默认为否
  7 + autoShowBackToTop: {
  8 + type: Boolean,
  9 + default: u.gc('autoShowBackToTop', false)
  10 + },
  11 + //点击返回顶部按钮显示/隐藏的阈值(滚动距离),单位为px,默认为400rpx
  12 + backToTopThreshold: {
  13 + type: [Number, String],
  14 + default: u.gc('backToTopThreshold', '400rpx')
  15 + },
  16 + //点击返回顶部按钮的自定义图片地址,默认使用z-paging内置的图片
  17 + backToTopImg: {
  18 + type: String,
  19 + default: u.gc('backToTopImg', '')
  20 + },
  21 + //点击返回顶部按钮返回到顶部时是否展示过渡动画,默认为是
  22 + backToTopWithAnimate: {
  23 + type: Boolean,
  24 + default: u.gc('backToTopWithAnimate', true)
  25 + },
  26 + //点击返回顶部按钮与底部的距离,注意添加单位px或rpx,默认为160rpx
  27 + backToTopBottom: {
  28 + type: [Number, String],
  29 + default: u.gc('backToTopBottom', '160rpx')
  30 + },
  31 + //点击返回顶部按钮的自定义样式
  32 + backToTopStyle: {
  33 + type: Object,
  34 + default: function() {
  35 + return u.gc('backToTopStyle', {});
  36 + },
  37 + },
  38 + //iOS点击顶部状态栏、安卓双击标题栏时,滚动条返回顶部,只支持竖向,默认为是
  39 + enableBackToTop: {
  40 + type: Boolean,
  41 + default: u.gc('enableBackToTop', true)
  42 + },
  43 + },
  44 + data() {
  45 + return {
  46 + backToTopClass: 'zp-back-to-top zp-back-to-top-hide',
  47 + lastBackToTopShowTime: 0,
  48 + showBackToTopClass: false,
  49 + }
  50 + },
  51 + computed: {
  52 + finalEnableBackToTop() {
  53 + return this.usePageScroll ? false : this.enableBackToTop;
  54 + },
  55 + finalBackToTopThreshold() {
  56 + return u.convertToPx(this.backToTopThreshold);
  57 + },
  58 + finalBackToTopStyle() {
  59 + const backToTopStyle = this.backToTopStyle;
  60 + if (!backToTopStyle.bottom) {
  61 + backToTopStyle.bottom = this.windowBottom + u.convertToPx(this.backToTopBottom) + 'px';
  62 + }
  63 + if(!backToTopStyle.position){
  64 + backToTopStyle.position = this.usePageScroll ? 'fixed': 'absolute';
  65 + }
  66 + return backToTopStyle;
  67 + },
  68 + },
  69 + methods: {
  70 + //点击返回顶部
  71 + _backToTopClick() {
  72 + let callbacked = false;
  73 + this.$emit('backToTopClick', toTop => {
  74 + (toTop === undefined || toTop === true) && this._handleToTop();
  75 + callbacked = true;
  76 + });
  77 + this.$nextTick(() => {
  78 + !callbacked && this._handleToTop();
  79 + })
  80 + },
  81 + //处理滚动到顶部
  82 + _handleToTop() {
  83 + !this.backToTopWithAnimate && this._checkShouldShowBackToTop(0);
  84 + this.scrollToTop(this.backToTopWithAnimate);
  85 + },
  86 + //判断是否要显示返回顶部按钮
  87 + _checkShouldShowBackToTop(scrollTop) {
  88 + if (!this.autoShowBackToTop) {
  89 + this.showBackToTopClass = false;
  90 + return;
  91 + }
  92 + if (scrollTop > this.finalBackToTopThreshold) {
  93 + if (!this.showBackToTopClass) {
  94 + this.showBackToTopClass = true;
  95 + this.lastBackToTopShowTime = new Date().getTime();
  96 + u.delay(() => {
  97 + this.backToTopClass = 'zp-back-to-top zp-back-to-top-show';
  98 + }, 300)
  99 + }
  100 + } else {
  101 + if (this.showBackToTopClass) {
  102 + this.backToTopClass = 'zp-back-to-top zp-back-to-top-hide';
  103 + u.delay(() => {
  104 + this.showBackToTopClass = false;
  105 + }, new Date().getTime() - this.lastBackToTopShowTime < 500 ? 0 : 300)
  106 + }
  107 + }
  108 + },
  109 + }
  110 +}
  111 +
garbage-removal/src/components/z-paging/js/modules/common-layout.js 0 → 100644
  1 +// [z-paging]通用布局相关模块
  2 +
  3 +// #ifdef APP-NVUE
  4 +const weexDom = weex.requireModule('dom');
  5 +// #endif
  6 +
  7 +export default {
  8 + data() {
  9 + return {
  10 + systemInfo: null,
  11 + cssSafeAreaInsetBottom: -1,
  12 + }
  13 + },
  14 + computed: {
  15 + windowTop() {
  16 + if (!this.systemInfo) return 0;
  17 + //暂时修复vue3中隐藏系统导航栏后windowTop获取不正确的问题,具体bug详见https://ask.dcloud.net.cn/question/141634
  18 + //感谢litangyu!!https://github.com/SmileZXLee/uni-z-paging/issues/25
  19 + // #ifdef VUE3 && H5
  20 + const pageHeadNode = document.getElementsByTagName("uni-page-head");
  21 + if (!pageHeadNode.length) return 0;
  22 + // #endif
  23 + return this.systemInfo.windowTop || 0;
  24 + },
  25 + safeAreaBottom() {
  26 + if (!this.systemInfo) return 0;
  27 + let safeAreaBottom = 0;
  28 + // #ifdef APP-PLUS
  29 + safeAreaBottom = this.systemInfo.safeAreaInsets.bottom || 0 ;
  30 + // #endif
  31 + // #ifndef APP-PLUS
  32 + safeAreaBottom = Math.max(this.cssSafeAreaInsetBottom, 0);
  33 + // #endif
  34 + return safeAreaBottom;
  35 + },
  36 + isOldWebView() {
  37 + // #ifndef APP-NVUE || MP-KUAISHOU
  38 + try {
  39 + const systemInfos = uni.getSystemInfoSync().system.split(' ');
  40 + const deviceType = systemInfos[0];
  41 + const version = parseInt(systemInfos[1]);
  42 + if ((deviceType === 'iOS' && version <= 10) || (deviceType === 'Android' && version <= 6)) {
  43 + return true;
  44 + }
  45 + } catch(e) {
  46 + return false;
  47 + }
  48 + // #endif
  49 + return false;
  50 + },
  51 + zSlots() {
  52 + // #ifdef VUE2
  53 +
  54 + // #ifdef MP-ALIPAY
  55 + return this.$slots;
  56 + // #endif
  57 +
  58 + return this.$scopedSlots || this.$slots;
  59 + // #endif
  60 +
  61 + return this.$slots;
  62 + }
  63 + },
  64 + methods: {
  65 + //获取节点尺寸
  66 + _getNodeClientRect(select, inDom = true, scrollOffset = false) {
  67 + // #ifdef APP-NVUE
  68 + select = select.replace(/[.|#]/g, '');
  69 + const ref = this.$refs[select];
  70 + return new Promise((resolve, reject) => {
  71 + if (ref) {
  72 + weexDom.getComponentRect(ref, option => {
  73 + resolve(option && option.result ? [option.size] : false);
  74 + })
  75 + } else {
  76 + resolve(false);
  77 + }
  78 + });
  79 + return;
  80 + // #endif
  81 + //#ifdef MP-ALIPAY
  82 + inDom = false;
  83 + //#endif
  84 + let res = !!inDom ? uni.createSelectorQuery().in(inDom === true ? this : inDom) : uni.createSelectorQuery();
  85 + scrollOffset ? res.select(select).scrollOffset() : res.select(select).boundingClientRect();
  86 + return new Promise((resolve, reject) => {
  87 + res.exec(data => {
  88 + resolve((data && data != '' && data != undefined && data.length) ? data : false);
  89 + });
  90 + });
  91 + },
  92 + //获取slot="left"和slot="right"宽度并且更新布局
  93 + _updateLeftAndRightWidth(targetStyle, parentNodePrefix) {
  94 + this.$nextTick(() => {
  95 + let delayTime = 0;
  96 + // #ifdef MP-BAIDU
  97 + delayTime = 10;
  98 + // #endif
  99 + setTimeout(() => {
  100 + ['left','right'].map(position => {
  101 + this._getNodeClientRect(`.${parentNodePrefix}-${position}`).then(res => {
  102 + this.$set(targetStyle, position, res ? res[0].width + 'px' : '0px');
  103 + });
  104 + })
  105 + }, delayTime)
  106 + })
  107 + },
  108 + //通过获取css设置的底部安全区域占位view高度设置bottom距离
  109 + _getCssSafeAreaInsetBottom(success) {
  110 + this._getNodeClientRect('.zp-safe-area-inset-bottom').then(res => {
  111 + this.cssSafeAreaInsetBottom = res ? res[0].height : -1;
  112 + res && success && success();
  113 + });
  114 + }
  115 + }
  116 +}
garbage-removal/src/components/z-paging/js/modules/data-handle.js 0 → 100644
  1 +// [z-paging]数据处理模块
  2 +import u from '.././z-paging-utils'
  3 +import c from '.././z-paging-constant'
  4 +import Enum from '.././z-paging-enum'
  5 +import interceptor from '../z-paging-interceptor'
  6 +
  7 +export default {
  8 + props: {
  9 + //自定义初始的pageNo,默认为1
  10 + defaultPageNo: {
  11 + type: [Number, String],
  12 + default: u.gc('defaultPageNo', 1),
  13 + observer: function(newVal) {
  14 + this.pageNo = newVal;
  15 + },
  16 + },
  17 + //自定义pageSize,默认为10
  18 + defaultPageSize: {
  19 + type: [Number, String],
  20 + default: u.gc('defaultPageSize', 10),
  21 + validator: (value) => {
  22 + if (value <= 0) u.consoleErr('default-page-size必须大于0!');
  23 + return value > 0;
  24 + }
  25 + },
  26 + //为保证数据一致,设置当前tab切换时的标识key,并在complete中传递相同key,若二者不一致,则complete将不会生效
  27 + dataKey: {
  28 + type: [Number, String, Object],
  29 + default: function() {
  30 + return u.gc('dataKey', null);
  31 + },
  32 + },
  33 + //使用缓存,若开启将自动缓存第一页的数据,默认为否。请注意,因考虑到切换tab时不同tab数据不同的情况,默认仅会缓存组件首次加载时第一次请求到的数据,后续的下拉刷新操作不会更新缓存。
  34 + useCache: {
  35 + type: Boolean,
  36 + default: u.gc('useCache', false)
  37 + },
  38 + //使用缓存时缓存的key,用于区分不同列表的缓存数据,useCache为true时必须设置,否则缓存无效
  39 + cacheKey: {
  40 + type: String,
  41 + default: u.gc('cacheKey', null)
  42 + },
  43 + //缓存模式,默认仅会缓存组件首次加载时第一次请求到的数据,可设置为always,即代表总是缓存,每次列表刷新(下拉刷新、调用reload等)都会更新缓存
  44 + cacheMode: {
  45 + type: String,
  46 + default: u.gc('cacheMode', Enum.CacheMode.Default)
  47 + },
  48 + //自动注入的list名,可自动修改父view(包含ref="paging")中对应name的list值
  49 + autowireListName: {
  50 + type: String,
  51 + default: u.gc('autowireListName', '')
  52 + },
  53 + //自动注入的query名,可自动调用父view(包含ref="paging")中的query方法
  54 + autowireQueryName: {
  55 + type: String,
  56 + default: u.gc('autowireQueryName', '')
  57 + },
  58 + //z-paging mounted后自动调用reload方法(mounted后自动调用接口),默认为是
  59 + auto: {
  60 + type: Boolean,
  61 + default: u.gc('auto', true)
  62 + },
  63 + //用户下拉刷新时是否触发reload方法,默认为是
  64 + reloadWhenRefresh: {
  65 + type: Boolean,
  66 + default: u.gc('reloadWhenRefresh', true)
  67 + },
  68 + //reload时自动滚动到顶部,默认为是
  69 + autoScrollToTopWhenReload: {
  70 + type: Boolean,
  71 + default: u.gc('autoScrollToTopWhenReload', true)
  72 + },
  73 + //reload时立即自动清空原list,默认为是,若立即自动清空,则在reload之后、请求回调之前页面是空白的
  74 + autoCleanListWhenReload: {
  75 + type: Boolean,
  76 + default: u.gc('autoCleanListWhenReload', true)
  77 + },
  78 + //列表刷新时自动显示下拉刷新view,默认为否
  79 + showRefresherWhenReload: {
  80 + type: Boolean,
  81 + default: u.gc('showRefresherWhenReload', false)
  82 + },
  83 + //列表刷新时自动显示加载更多view,且为加载中状态,默认为否
  84 + showLoadingMoreWhenReload: {
  85 + type: Boolean,
  86 + default: u.gc('showLoadingMoreWhenReload', false)
  87 + },
  88 + //组件created时立即触发reload(可解决一些情况下先看到页面再看到loading的问题),auto为true时有效。为否时将在mounted+nextTick后触发reload,默认为否
  89 + createdReload: {
  90 + type: Boolean,
  91 + default: u.gc('createdReload', false)
  92 + },
  93 + //本地分页时上拉加载更多延迟时间,单位为毫秒,默认200毫秒
  94 + localPagingLoadingTime: {
  95 + type: [Number, String],
  96 + default: u.gc('localPagingLoadingTime', 200)
  97 + },
  98 + //使用聊天记录模式,默认为否
  99 + useChatRecordMode: {
  100 + type: Boolean,
  101 + default: u.gc('useChatRecordMode', false)
  102 + },
  103 + //使用聊天记录模式时是否自动隐藏键盘:在用户触摸列表时候自动隐藏键盘,默认为是
  104 + autoHideKeyboardWhenChat: {
  105 + type: Boolean,
  106 + default: u.gc('autoHideKeyboardWhenChat', true)
  107 + },
  108 + //自动拼接complete中传过来的数组(使用聊天记录模式时无效)
  109 + concat: {
  110 + type: Boolean,
  111 + default: u.gc('concat', true)
  112 + },
  113 + //请求失败是否触发reject,默认为是
  114 + callNetworkReject: {
  115 + type: Boolean,
  116 + default: u.gc('callNetworkReject', true)
  117 + },
  118 + //父组件v-model所绑定的list的值
  119 + value: {
  120 + type: Array,
  121 + default: function() {
  122 + return [];
  123 + }
  124 + },
  125 + // #ifdef VUE3
  126 + modelValue: {
  127 + type: Array,
  128 + default: function() {
  129 + return [];
  130 + }
  131 + }
  132 + // #endif
  133 + },
  134 + data (){
  135 + return {
  136 + currentData: [],
  137 + totalData: [],
  138 + realTotalData: [],
  139 + totalLocalPagingList: [],
  140 + dataPromiseResultMap: {
  141 + reload: null,
  142 + complete: null,
  143 + localPaging: null
  144 + },
  145 + isSettingCacheList: false,
  146 + pageNo: 1,
  147 + currentRefreshPageSize: 0,
  148 + isLocalPaging: false,
  149 + isAddedData: false,
  150 + isTotalChangeFromAddData: false,
  151 + privateConcat: true,
  152 + myParentQuery: -1,
  153 + firstPageLoaded: false,
  154 + pagingLoaded: false,
  155 + loaded: false,
  156 + isUserReload: true,
  157 + fromEmptyViewReload: false,
  158 + queryFrom: '',
  159 + listRendering: false,
  160 + isHandlingRefreshToPage: false
  161 + }
  162 + },
  163 + computed: {
  164 + pageSize() {
  165 + return this.defaultPageSize;
  166 + },
  167 + finalConcat() {
  168 + return this.concat && this.privateConcat;
  169 + },
  170 + finalUseCache() {
  171 + if (this.useCache && !this.cacheKey) {
  172 + u.consoleErr('use-cache为true时,必须设置cache-key,否则缓存无效!');
  173 + }
  174 + return this.useCache && !!this.cacheKey;
  175 + },
  176 + finalCacheKey() {
  177 + return this.cacheKey ? `${c.cachePrefixKey}-${this.cacheKey}` : null;
  178 + },
  179 + isFirstPage() {
  180 + return this.pageNo === this.defaultPageNo;
  181 + }
  182 + },
  183 + watch: {
  184 + totalData(newVal, oldVal) {
  185 + this._totalDataChange(newVal, oldVal);
  186 + },
  187 + currentData(newVal, oldVal) {
  188 + this._currentDataChange(newVal, oldVal);
  189 + },
  190 + useChatRecordMode(newVal, oldVal) {
  191 + if (newVal) {
  192 + this.nLoadingMoreFixedHeight = false;
  193 + }
  194 + },
  195 + value: {
  196 + handler(newVal) {
  197 + this.realTotalData = newVal;
  198 + },
  199 + immediate: true
  200 + },
  201 + // #ifdef VUE3
  202 + modelValue: {
  203 + handler(newVal) {
  204 + this.realTotalData = newVal;
  205 + },
  206 + immediate: true
  207 + }
  208 + // #endif
  209 + },
  210 + methods: {
  211 + //请求结束(成功或者失败)调用此方法,将请求的结果传递给z-paging处理,第一个参数为请求结果数组,第二个参数为是否成功(默认是是)
  212 + complete(data, success = true) {
  213 + this.customNoMore = -1;
  214 + return this.addData(data, success);
  215 + },
  216 + //【保证数据一致】请求结束(成功或者失败)调用此方法,将请求的结果传递给z-paging处理,第一个参数为请求结果数组,第二个参数为dataKey,需与:data-key绑定的一致,第三个参数为是否成功(默认为是)
  217 + completeByKey(data, dataKey = null, success = true) {
  218 + if (dataKey !== null && this.dataKey !== null && dataKey !== this.dataKey) {
  219 + this.isFirstPage && this.endRefresh();
  220 + return new Promise(resolve => resolve());
  221 + }
  222 + this.customNoMore = -1;
  223 + return this.addData(data, success);
  224 + },
  225 + //【通过total判断是否有更多数据】请求结束(成功或者失败)调用此方法,将请求的结果传递给z-paging处理,第一个参数为请求结果数组,第二个参数为total(列表总数),第三个参数为是否成功(默认为是)
  226 + completeByTotal(data, total, success = true) {
  227 + if (total == 'undefined') {
  228 + this.customNoMore = -1;
  229 + } else {
  230 + const dataTypeRes = this._checkDataType(data, success, false);
  231 + data = dataTypeRes.data;
  232 + success = dataTypeRes.success;
  233 + if (total >= 0 && success) {
  234 + return new Promise((resolve, reject) => {
  235 + this.$nextTick(() => {
  236 + let nomore = false;
  237 + const realTotalDataCount = this.pageNo == this.defaultPageNo ? 0 : this.realTotalData.length;
  238 + const dataLength = this.privateConcat ? data.length : 0;
  239 + let exceedCount = realTotalDataCount + dataLength - total;
  240 + if (exceedCount >= 0) {
  241 + nomore = true;
  242 + exceedCount = this.defaultPageSize - exceedCount;
  243 + if (this.privateConcat && exceedCount > 0 && exceedCount < data.length) {
  244 + data = data.splice(0, exceedCount);
  245 + }
  246 + }
  247 + this.completeByNoMore(data, nomore, success).then(res => resolve(res)).catch(() => reject());
  248 + })
  249 + });
  250 + }
  251 + }
  252 + return this.addData(data, success);
  253 + },
  254 + //【自行判断是否有更多数据】请求结束(成功或者失败)调用此方法,将请求的结果传递给z-paging处理,第一个参数为请求结果数组,第二个参数为是否有更多数据,第三个参数为是否成功(默认是是)
  255 + completeByNoMore(data, nomore, success = true) {
  256 + if (nomore != 'undefined') {
  257 + this.customNoMore = nomore == true ? 1 : 0;
  258 + }
  259 + return this.addData(data, success);
  260 + },
  261 + //与上方complete方法功能一致,新版本中设置服务端回调数组请使用complete方法
  262 + addData(data, success = true) {
  263 + if (!this.fromCompleteEmit) {
  264 + this.disabledCompleteEmit = true;
  265 + this.fromCompleteEmit = false;
  266 + }
  267 + const currentTimeStamp = u.getTime();
  268 + const disTime = currentTimeStamp - this.requestTimeStamp;
  269 + let minDelay = this.minDelay;
  270 + if (this.isFirstPage && this.finalShowRefresherWhenReload) {
  271 + minDelay = Math.max(400, minDelay);
  272 + }
  273 + const addDataDalay = (this.requestTimeStamp > 0 && disTime < minDelay) ? minDelay - disTime : 0;
  274 + this.$nextTick(() => {
  275 + u.delay(() => {
  276 + this._addData(data, success, false);
  277 + }, this.delay > 0 ? this.delay : addDataDalay)
  278 + })
  279 +
  280 + return new Promise((resolve, reject) => {
  281 + this.dataPromiseResultMap.complete = { resolve, reject };
  282 + });
  283 + },
  284 + //从顶部添加数据,不会影响分页的pageNo和pageSize
  285 + addDataFromTop(data, toTop = true, toTopWithAnimate = true) {
  286 + data = Object.prototype.toString.call(data) !== '[object Array]' ? [data] : data.reverse();
  287 + // #ifndef APP-NVUE
  288 + this.finalUseVirtualList && this._setCellIndex(data, 'top')
  289 + // #endif
  290 + this.totalData = [...data, ...this.totalData];
  291 + if (toTop) {
  292 + u.delay(() => this._scrollToTop(toTopWithAnimate));
  293 + }
  294 + },
  295 + //重新设置列表数据,调用此方法不会影响pageNo和pageSize,也不会触发请求。适用场景:当需要删除列表中某一项时,将删除对应项后的数组通过此方法传递给z-paging。(当出现类似的需要修改列表数组的场景时,请使用此方法,请勿直接修改page中:list.sync绑定的数组)
  296 + resetTotalData(data) {
  297 + this.isTotalChangeFromAddData = true;
  298 + data = Object.prototype.toString.call(data) !== '[object Array]' ? [data] : data;
  299 + this.totalData = data;
  300 + },
  301 + //添加聊天记录
  302 + addChatRecordData(data, toBottom = true, toBottomWithAnimate = true) {
  303 + data = Object.prototype.toString.call(data) !== '[object Array]' ? [data] : data;
  304 + if (!this.useChatRecordMode) return;
  305 + this.isTotalChangeFromAddData = true;
  306 + //#ifndef APP-NVUE
  307 + this.totalData = [...this.totalData, ...data];
  308 + //#endif
  309 + //#ifdef APP-NVUE
  310 + this.totalData = this.nIsFirstPageAndNoMore ? [...this.totalData, ...data] : [...data, ...this.totalData];
  311 + //#endif
  312 + if (toBottom) {
  313 + u.delay(() => {
  314 + //#ifndef APP-NVUE
  315 + this._scrollToBottom(toBottomWithAnimate);
  316 + //#endif
  317 + //#ifdef APP-NVUE
  318 + this.nIsFirstPageAndNoMore ? this._scrollToBottom(toBottomWithAnimate) : this._scrollToTop(toBottomWithAnimate);
  319 + //#endif
  320 + })
  321 + }
  322 + },
  323 + //设置本地分页数据,请求结束(成功或者失败)调用此方法,将请求的结果传递给z-paging作分页处理(若调用了此方法,则上拉加载更多时内部会自动分页,不会触发@query所绑定的事件)
  324 + setLocalPaging(data, success = true) {
  325 + this.isLocalPaging = true;
  326 + this.$nextTick(() => {
  327 + this._addData(data, success, true);
  328 + })
  329 + return new Promise((resolve, reject) => {
  330 + this.dataPromiseResultMap.localPaging = { resolve, reject };
  331 + });
  332 + },
  333 + //重新加载分页数据,pageNo会恢复为默认值,相当于下拉刷新的效果(animate为true时会展示下拉刷新动画,默认为false)
  334 + reload(animate = this.showRefresherWhenReload) {
  335 + if (animate) {
  336 + this.privateShowRefresherWhenReload = animate;
  337 + this.isUserPullDown = true;
  338 + }
  339 + if (!this.showLoadingMoreWhenReload) {
  340 + this.listRendering = true;
  341 + }
  342 + this.$nextTick(() => {
  343 + this._preReload(animate, false);
  344 + })
  345 + return new Promise((resolve, reject) => {
  346 + this.dataPromiseResultMap.reload = { resolve, reject };
  347 + });
  348 + },
  349 + //刷新列表数据,pageNo和pageSize不会重置,列表数据会重新从服务端获取。必须保证@query绑定的方法中的pageNo和pageSize和传给服务端的一致
  350 + refresh() {
  351 + return this._handleRefreshWithDisPageNo(this.pageNo - this.defaultPageNo + 1);
  352 + },
  353 + //刷新列表数据至指定页,例如pageNo=5时则代表刷新列表至第5页,此时pageNo会变为5,列表会展示前5页的数据。必须保证@query绑定的方法中的pageNo和pageSize和传给服务端的一致
  354 + refreshToPage(pageNo) {
  355 + this.isHandlingRefreshToPage = true;
  356 + return this._handleRefreshWithDisPageNo(pageNo + this.defaultPageNo - 1);
  357 + },
  358 + //手动更新列表缓存数据,将自动截取v-model绑定的list中的前pageSize条覆盖缓存,请确保在list数据更新到预期结果后再调用此方法
  359 + updateCache() {
  360 + if (this.finalUseCache && this.totalData.length) {
  361 + this._saveLocalCache(this.totalData.slice(0, Math.min(this.totalData.length, this.pageSize)));
  362 + }
  363 + },
  364 + //清空分页数据
  365 + clean() {
  366 + this._reload(true);
  367 + this._addData([], true, false);
  368 + },
  369 + //清空分页数据
  370 + clear() {
  371 + this.clean();
  372 + },
  373 + //手动触发滚动到顶部加载更多,聊天记录模式时有效
  374 + doChatRecordLoadMore() {
  375 + this.useChatRecordMode && this._onLoadingMore('click');
  376 + },
  377 + //reload之前的一些处理
  378 + _preReload(animate = this.showRefresherWhenReload, isFromMounted = true) {
  379 + const showRefresher = this.finalRefresherEnabled && this.useCustomRefresher;
  380 + // #ifndef APP-NVUE
  381 + if (this.customRefresherHeight === -1 && showRefresher) {
  382 + u.delay(() => this._preReload(animate, isFromMounted), c.delayTime / 2);
  383 + return;
  384 + }
  385 + // #endif
  386 + this.isUserReload = true;
  387 + this.loadingType = Enum.LoadingType.Refresher;
  388 + if (animate) {
  389 + this.privateShowRefresherWhenReload = animate;
  390 + // #ifndef APP-NVUE
  391 + if (this.useCustomRefresher) {
  392 + this._doRefresherRefreshAnimate();
  393 + } else {
  394 + this.refresherTriggered = true;
  395 + }
  396 + // #endif
  397 + // #ifdef APP-NVUE
  398 + this.refresherStatus = Enum.Refresher.Loading;
  399 + this.refresherRevealStackCount ++;
  400 + u.delay(() => {
  401 + this._getNodeClientRect('zp-n-refresh-container', false).then((node) => {
  402 + if (node) {
  403 + let nodeHeight = node[0].height;
  404 + this.nShowRefresherReveal = true;
  405 + this.nShowRefresherRevealHeight = nodeHeight;
  406 + u.delay(() => {
  407 + this._nDoRefresherEndAnimation(0, -nodeHeight, false, false);
  408 + u.delay(() => {
  409 + this._nDoRefresherEndAnimation(nodeHeight, 0);
  410 + }, 10)
  411 + }, 10)
  412 + }
  413 + this._reload(false, isFromMounted);
  414 + this._doRefresherLoad(false);
  415 + });
  416 + }, this.pagingLoaded ? 10 : 100)
  417 + return;
  418 + // #endif
  419 + } else {
  420 + this._refresherEnd(false, false, false, false);
  421 + }
  422 + this._reload(false, isFromMounted);
  423 + },
  424 + //重新加载分页数据
  425 + _reload(isClean = false, isFromMounted = false, isUserPullDown = false) {
  426 + this.isAddedData = false;
  427 + this.insideOfPaging = -1;
  428 + this.cacheScrollNodeHeight = -1;
  429 + this.pageNo = this.defaultPageNo;
  430 + this._cleanRefresherEndTimeout();
  431 + !this.privateShowRefresherWhenReload && !isClean && this._startLoading(true);
  432 + this.firstPageLoaded = true;
  433 + this.isTotalChangeFromAddData = false;
  434 + if (!this.isSettingCacheList) {
  435 + this.totalData = [];
  436 + }
  437 + if (!isClean) {
  438 + this._emitQuery(this.pageNo, this.defaultPageSize, isUserPullDown ? Enum.QueryFrom.UserPullDown : Enum.QueryFrom.Reload);
  439 + let delay = 0;
  440 + // #ifdef MP-TOUTIAO
  441 + delay = 5;
  442 + // #endif
  443 + u.delay(this._callMyParentQuery, delay);
  444 + if (!isFromMounted && this.autoScrollToTopWhenReload) {
  445 + let checkedNRefresherLoading = true;
  446 + // #ifdef APP-NVUE
  447 + checkedNRefresherLoading = !this.nRefresherLoading;
  448 + // #endif
  449 + checkedNRefresherLoading && this._scrollToTop(false);
  450 + }
  451 + }
  452 + // #ifdef APP-NVUE
  453 + this.$nextTick(() => {
  454 + this.nShowBottom = this.realTotalData.length > 0;
  455 + })
  456 + // #endif
  457 + },
  458 + //处理服务端返回的数组
  459 + _addData(data, success, isLocal) {
  460 + this.isAddedData = true;
  461 + this.fromEmptyViewReload = false;
  462 + this.isTotalChangeFromAddData = true;
  463 + this.refresherTriggered = false;
  464 + this._endSystemLoadingAndRefresh();
  465 + const tempIsUserPullDown = this.isUserPullDown;
  466 + if (this.showRefresherUpdateTime && this.isFirstPage) {
  467 + u.setRefesrherTime(u.getTime(), this.refresherUpdateTimeKey);
  468 + this.$refs.refresh && this.$refs.refresh.updateTime();
  469 + }
  470 + if (!isLocal && tempIsUserPullDown && this.isFirstPage) {
  471 + this.isUserPullDown = false;
  472 + }
  473 + if (!this.isFirstPage) {
  474 + this.listRendering = true;
  475 + this.$nextTick(() => {
  476 + u.delay(() => this.listRendering = false);
  477 + })
  478 + } else {
  479 + this.listRendering = false;
  480 + }
  481 + let dataTypeRes = this._checkDataType(data, success, isLocal);
  482 + data = dataTypeRes.data;
  483 + success = dataTypeRes.success;
  484 + let delayTime = c.delayTime;
  485 + // #ifdef APP-NVUE
  486 + if (this.useChatRecordMode) delayTime = 0;
  487 + // #endif
  488 + this.loadingForNow = false;
  489 + u.delay(() => {
  490 + this.pagingLoaded = true;
  491 + this.$nextTick(()=>{
  492 + !isLocal && this._refresherEnd(delayTime > 0, true, tempIsUserPullDown);
  493 + })
  494 + })
  495 + if (this.isFirstPage) {
  496 + this.isLoadFailed = !success;
  497 + this.$emit('isLoadFailedChange', this.isLoadFailed);
  498 + if (this.finalUseCache && success && (this.cacheMode === Enum.CacheMode.Always ? true : this.isSettingCacheList)) {
  499 + this._saveLocalCache(data);
  500 + }
  501 + }
  502 + this.isSettingCacheList = false;
  503 + if (success) {
  504 + if (!(this.privateConcat === false && this.loadingStatus === Enum.More.NoMore)) {
  505 + this.loadingStatus = Enum.More.Default;
  506 + }
  507 + if (isLocal) {
  508 + this.totalLocalPagingList = data;
  509 + const localPageNo = this.defaultPageNo;
  510 + const localPageSize = this.queryFrom !== Enum.QueryFrom.Refresh ? this.defaultPageSize : this.currentRefreshPageSize;
  511 + this._localPagingQueryList(localPageNo, localPageSize, 0, res => {
  512 + this.completeByTotal(res, this.totalLocalPagingList.length);
  513 + })
  514 + } else {
  515 + let dataChangeDelayTime = 0;
  516 + // #ifdef APP-NVUE
  517 + if (this.privateShowRefresherWhenReload && this.finalNvueListIs === 'waterfall') {
  518 + dataChangeDelayTime = 150;
  519 + }
  520 + // #endif
  521 + u.delay(() => {
  522 + this._currentDataChange(data, this.currentData);
  523 + this._callDataPromise(true, this.totalData);
  524 + }, dataChangeDelayTime)
  525 + }
  526 + if (this.isHandlingRefreshToPage) {
  527 + this.isHandlingRefreshToPage = false;
  528 + this.pageNo = this.defaultPageNo + Math.ceil(data.length / this.pageSize) - 1;
  529 + if (data.length % this.pageSize !== 0) {
  530 + this.customNoMore = 1;
  531 + }
  532 + }
  533 + } else {
  534 + this._currentDataChange(data, this.currentData);
  535 + this._callDataPromise(false);
  536 + this.loadingStatus = Enum.More.Fail;
  537 + this.isHandlingRefreshToPage = false;
  538 + if (this.loadingType === Enum.LoadingType.LoadingMore) {
  539 + this.pageNo --;
  540 + }
  541 + }
  542 + },
  543 + //所有数据改变时调用
  544 + _totalDataChange(newVal, oldVal, eventThrow=true) {
  545 + if ((!this.isUserReload || !this.autoCleanListWhenReload) && this.firstPageLoaded && !newVal.length && oldVal.length) {
  546 + return;
  547 + }
  548 + this._doCheckScrollViewShouldFullHeight(newVal);
  549 + if(!this.realTotalData.length && !newVal.length){
  550 + eventThrow = false;
  551 + }
  552 + this.realTotalData = newVal;
  553 + if (eventThrow) {
  554 + this.$emit('input', newVal);
  555 + // #ifdef VUE3
  556 + this.$emit('update:modelValue', newVal);
  557 + // #endif
  558 + this.$emit('update:list', newVal);
  559 + this.$emit('listChange', newVal);
  560 + this._callMyParentList(newVal);
  561 + }
  562 + this.firstPageLoaded = false;
  563 + this.isTotalChangeFromAddData = false;
  564 + this.$nextTick(() => {
  565 + u.delay(()=>{
  566 + this._getNodeClientRect('.zp-paging-container-content').then(res => {
  567 + res && this.$emit('contentHeightChanged', res[0].height);
  568 + });
  569 + }, c.delayTime * (this.isIos ? 1 : 3))
  570 + // #ifdef APP-NVUE
  571 + if (this.useChatRecordMode && this.nIsFirstPageAndNoMore && this.isFirstPage && !this.nFirstPageAndNoMoreChecked) {
  572 + this.nFirstPageAndNoMoreChecked = true;
  573 + this._scrollToBottom(false);
  574 + }
  575 + u.delay(() => {
  576 + this.nShowBottom = true;
  577 + }, c.delayTime * 6, 'nShowBottomDelay');
  578 + // #endif
  579 + })
  580 + },
  581 + //当前数据改变时调用
  582 + _currentDataChange(newVal, oldVal) {
  583 + newVal = [...newVal];
  584 + // #ifndef APP-NVUE
  585 + this.finalUseVirtualList && this._setCellIndex(newVal, 'bottom');
  586 + this.useChatRecordMode && newVal.reverse();
  587 + // #endif
  588 + if (this.isFirstPage && this.finalConcat) {
  589 + this.totalData = [];
  590 + }
  591 + if (this.customNoMore !== -1) {
  592 + if (this.customNoMore === 1 || !newVal.length) {
  593 + this.loadingStatus = Enum.More.NoMore;
  594 + }
  595 + } else {
  596 + if (!newVal.length || (newVal.length && newVal.length < this.defaultPageSize)) {
  597 + this.loadingStatus = Enum.More.NoMore;
  598 + }
  599 + }
  600 + if (!this.totalData.length) {
  601 + if (this.finalConcat) {
  602 + // #ifdef APP-NVUE
  603 + if (this.useChatRecordMode && this.isFirstPage && this.loadingStatus === Enum.More.NoMore) {
  604 + newVal.reverse();
  605 + }
  606 + // #endif
  607 + this.totalData = newVal;
  608 + }
  609 + if (this.useChatRecordMode) {
  610 + // #ifndef APP-NVUE
  611 + this.$nextTick(() => {
  612 + this._scrollToBottom(false);
  613 + })
  614 + // #endif
  615 + }
  616 + } else {
  617 + if (this.useChatRecordMode) {
  618 + // #ifdef APP-NVUE
  619 + this.totalData = [...this.totalData, ...newVal];
  620 + // #endif
  621 + //#ifndef APP-NVUE
  622 + const idIndex = newVal.length;
  623 + let idIndexStr = `z-paging-${idIndex}`;
  624 + this.totalData = [...newVal, ...this.totalData];
  625 + if (this.pageNo !== this.defaultPageNo) {
  626 + this.privateScrollWithAnimation = 0;
  627 + this.$emit('update:chatIndex', idIndex);
  628 + this.$nextTick(() => {
  629 + this._scrollIntoView(idIndexStr, 30 + Math.max(0, this.cacheTopHeight), false, () => {
  630 + this.$emit('update:chatIndex', 0);
  631 + });
  632 + })
  633 + } else {
  634 + this.$nextTick(() => {
  635 + this._scrollToBottom(false);
  636 + })
  637 + }
  638 + //#endif
  639 +
  640 + } else {
  641 + if (this.finalConcat) {
  642 + const currentScrollTop = this.oldScrollTop;
  643 + this.totalData = [...this.totalData, ...newVal];
  644 + // #ifdef MP-WEIXIN
  645 + if (!this.isIos && !this.refresherOnly && !this.usePageScroll && newVal.length) {
  646 + this.loadingMoreTimeStamp = u.getTime();
  647 + this.$nextTick(() => {
  648 + this.scrollToY(currentScrollTop);
  649 + })
  650 + }
  651 + // #endif
  652 + } else {
  653 + this.totalData = newVal;
  654 + }
  655 + }
  656 + }
  657 + this.privateConcat = true;
  658 + },
  659 + //根据pageNo处理refresh操作
  660 + _handleRefreshWithDisPageNo(pageNo) {
  661 + if (!this.realTotalData.length) return this.reload();
  662 + if (pageNo >= 1) {
  663 + this.loading = true;
  664 + this.privateConcat = false;
  665 + const totalPageSize = pageNo * this.pageSize;
  666 + this.currentRefreshPageSize = totalPageSize;
  667 + this._emitQuery(this.defaultPageNo, totalPageSize, Enum.QueryFrom.Refresh);
  668 + this._callMyParentQuery(this.defaultPageNo, totalPageSize);
  669 + }
  670 + return new Promise((resolve, reject) => {
  671 + this.dataPromiseResultMap.reload = { resolve, reject };
  672 + });
  673 + },
  674 + //本地分页请求
  675 + _localPagingQueryList(pageNo, pageSize, localPagingLoadingTime, callback) {
  676 + pageNo = Math.max(1, pageNo);
  677 + pageSize = Math.max(1, pageSize);
  678 + const totalPagingList = [...this.totalLocalPagingList];
  679 + const pageNoIndex = (pageNo - 1) * pageSize;
  680 + const finalPageNoIndex = Math.min(totalPagingList.length, pageNoIndex + pageSize);
  681 + const resultPagingList = totalPagingList.splice(pageNoIndex, finalPageNoIndex - pageNoIndex);
  682 + u.delay(() => callback(resultPagingList), localPagingLoadingTime)
  683 + },
  684 + //存储列表缓存数据
  685 + _saveLocalCache(data) {
  686 + uni.setStorageSync(this.finalCacheKey, data);
  687 + },
  688 + //通过缓存数据填充列表数据
  689 + _setListByLocalCache() {
  690 + this.totalData = uni.getStorageSync(this.finalCacheKey) || [];
  691 + this.isSettingCacheList = true;
  692 + },
  693 + //修改父view的list
  694 + _callMyParentList(newVal) {
  695 + if (this.autowireListName.length) {
  696 + const myParent = u.getParent(this.$parent);
  697 + if (myParent && myParent[this.autowireListName]) {
  698 + myParent[this.autowireListName] = newVal;
  699 + }
  700 + }
  701 + },
  702 + //调用父view的query
  703 + _callMyParentQuery(customPageNo = 0, customPageSize = 0) {
  704 + if (this.autowireQueryName) {
  705 + if (this.myParentQuery === -1) {
  706 + const myParent = u.getParent(this.$parent);
  707 + if (myParent && myParent[this.autowireQueryName]) {
  708 + this.myParentQuery = myParent[this.autowireQueryName];
  709 + }
  710 + }
  711 + if (this.myParentQuery !== -1) {
  712 + customPageSize > 0 ? this.myParentQuery(customPageNo, customPageSize) : this.myParentQuery(this.pageNo, this.defaultPageSize);
  713 + }
  714 + }
  715 + },
  716 + //emit query事件
  717 + _emitQuery(pageNo, pageSize, from){
  718 + this.queryFrom = from;
  719 + this.requestTimeStamp = u.getTime();
  720 + const [lastItem] = this.realTotalData.slice(-1);
  721 + this.$emit('query', ...interceptor._handleQuery(pageNo, pageSize, from, lastItem || null));
  722 + },
  723 + //触发数据改变promise
  724 + _callDataPromise(success, totalList) {
  725 + for (const key in this.dataPromiseResultMap) {
  726 + const obj = this.dataPromiseResultMap[key];
  727 + if (!obj) continue;
  728 + success ? obj.resolve({ totalList, noMore: this.loadingStatus === Enum.More.NoMore }) : this.callNetworkReject && obj.reject(`z-paging-${key}-error`);
  729 + }
  730 + },
  731 + //检查complete data的类型
  732 + _checkDataType(data, success, isLocal) {
  733 + const dataType = Object.prototype.toString.call(data);
  734 + if (dataType === '[object Boolean]') {
  735 + success = data;
  736 + data = [];
  737 + } else if (dataType !== '[object Array]') {
  738 + data = [];
  739 + if (dataType !== '[object Undefined]' && dataType !== '[object Null]') {
  740 + u.consoleErr(`${isLocal ? 'setLocalPaging' : 'complete'}参数类型不正确,第一个参数类型必须为Array!`);
  741 + }
  742 + }
  743 + return { data, success };
  744 + },
  745 + }
  746 +}
garbage-removal/src/components/z-paging/js/modules/empty.js 0 → 100644
  1 +// [z-paging]空数据图view模块
  2 +import u from '.././z-paging-utils'
  3 +
  4 +export default {
  5 + props: {
  6 + //是否强制隐藏空数据图,默认为否
  7 + hideEmptyView: {
  8 + type: Boolean,
  9 + default: u.gc('hideEmptyView', false)
  10 + },
  11 + //空数据图描述文字,默认为“没有数据哦~”
  12 + emptyViewText: {
  13 + type: [String, Object],
  14 + default: u.gc('emptyViewText', null)
  15 + },
  16 + //是否显示空数据图重新加载按钮(无数据时),默认为否
  17 + showEmptyViewReload: {
  18 + type: Boolean,
  19 + default: u.gc('showEmptyViewReload', false)
  20 + },
  21 + //加载失败时是否显示空数据图重新加载按钮,默认为是
  22 + showEmptyViewReloadWhenError: {
  23 + type: Boolean,
  24 + default: u.gc('showEmptyViewReloadWhenError', true)
  25 + },
  26 + //空数据图点击重新加载文字,默认为“重新加载”
  27 + emptyViewReloadText: {
  28 + type: [String, Object],
  29 + default: u.gc('emptyViewReloadText', null)
  30 + },
  31 + //空数据图图片,默认使用z-paging内置的图片
  32 + emptyViewImg: {
  33 + type: String,
  34 + default: u.gc('emptyViewImg', '')
  35 + },
  36 + //空数据图“加载失败”描述文字,默认为“很抱歉,加载失败”
  37 + emptyViewErrorText: {
  38 + type: [String, Object],
  39 + default: u.gc('emptyViewErrorText', null)
  40 + },
  41 + //空数据图“加载失败”图片,默认使用z-paging内置的图片
  42 + emptyViewErrorImg: {
  43 + type: String,
  44 + default: u.gc('emptyViewErrorImg', '')
  45 + },
  46 + //空数据图样式
  47 + emptyViewStyle: {
  48 + type: Object,
  49 + default: function() {
  50 + return u.gc('emptyViewStyle', {});
  51 + }
  52 + },
  53 + //空数据图容器样式
  54 + emptyViewSuperStyle: {
  55 + type: Object,
  56 + default: function() {
  57 + return u.gc('emptyViewSuperStyle', {});
  58 + }
  59 + },
  60 + //空数据图img样式
  61 + emptyViewImgStyle: {
  62 + type: Object,
  63 + default: function() {
  64 + return u.gc('emptyViewImgStyle', {});
  65 + }
  66 + },
  67 + //空数据图描述文字样式
  68 + emptyViewTitleStyle: {
  69 + type: Object,
  70 + default: function() {
  71 + return u.gc('emptyViewTitleStyle', {});
  72 + }
  73 + },
  74 + //空数据图重新加载按钮样式
  75 + emptyViewReloadStyle: {
  76 + type: Object,
  77 + default: function() {
  78 + return u.gc('emptyViewReloadStyle', {});
  79 + }
  80 + },
  81 + //空数据图片是否铺满z-paging,默认为否,即填充满z-paging内列表(滚动区域)部分。若设置为否,则为填铺满整个z-paging
  82 + emptyViewFixed: {
  83 + type: Boolean,
  84 + default: u.gc('emptyViewFixed', false)
  85 + },
  86 + //空数据图片是否垂直居中,默认为是,若设置为否即为从空数据容器顶部开始显示。emptyViewFixed为false时有效
  87 + emptyViewCenter: {
  88 + type: Boolean,
  89 + default: u.gc('emptyViewCenter', true)
  90 + },
  91 + //加载中时是否自动隐藏空数据图,默认为是
  92 + autoHideEmptyViewWhenLoading: {
  93 + type: Boolean,
  94 + default: u.gc('autoHideEmptyViewWhenLoading', true)
  95 + },
  96 + //用户下拉列表触发下拉刷新加载中时是否自动隐藏空数据图,默认为是
  97 + autoHideEmptyViewWhenPull: {
  98 + type: Boolean,
  99 + default: u.gc('autoHideEmptyViewWhenPull', true)
  100 + },
  101 + //空数据view的z-index,默认为9
  102 + emptyViewZIndex: {
  103 + type: Number,
  104 + default: u.gc('emptyViewZIndex', 9)
  105 + },
  106 + },
  107 + computed: {
  108 + finalEmptyViewImg() {
  109 + return this.isLoadFailed ? this.emptyViewErrorImg : this.emptyViewImg;
  110 + },
  111 + finalShowEmptyViewReload() {
  112 + return this.isLoadFailed ? this.showEmptyViewReloadWhenError : this.showEmptyViewReload;
  113 + },
  114 + showEmpty() {
  115 + if (this.refresherOnly || this.hideEmptyView || this.realTotalData.length) return false;
  116 + if (this.autoHideEmptyViewWhenLoading) {
  117 + if (this.isAddedData && !this.firstPageLoaded && !this.loading) return true;
  118 + } else {
  119 + return true;
  120 + }
  121 + return !this.autoHideEmptyViewWhenPull && !this.isUserReload;
  122 + },
  123 + },
  124 + methods: {
  125 + //点击了空数据view重新加载按钮
  126 + _emptyViewReload() {
  127 + let callbacked = false;
  128 + this.$emit('emptyViewReload', reload => {
  129 + if (reload === undefined || reload === true) {
  130 + this.fromEmptyViewReload = true;
  131 + this.reload().catch(() => {});
  132 + }
  133 + callbacked = true;
  134 + });
  135 + this.$nextTick(() => {
  136 + if (!callbacked) {
  137 + this.fromEmptyViewReload = true;
  138 + this.reload().catch(() => {});
  139 + }
  140 + })
  141 + },
  142 + //点击了空数据view
  143 + _emptyViewClick() {
  144 + this.$emit('emptyViewClick');
  145 + },
  146 + }
  147 +}
0 \ No newline at end of file 148 \ No newline at end of file
garbage-removal/src/components/z-paging/js/modules/i18n.js 0 → 100644
  1 +// [z-paging]i18n模块
  2 +import { initVueI18n } from '@dcloudio/uni-i18n'
  3 +import messages from '../../i18n/index.js'
  4 +const { t } = initVueI18n(messages)
  5 +
  6 +import u from '.././z-paging-utils'
  7 +import c from '.././z-paging-constant'
  8 +import interceptor from '../z-paging-interceptor'
  9 +
  10 +const language = uni.getSystemInfoSync().language;
  11 +export default {
  12 + data() {
  13 + return {
  14 + language
  15 + }
  16 + },
  17 + computed: {
  18 + finalLanguage() {
  19 + try {
  20 + const local = uni.getLocale();
  21 + const language = this.language;
  22 + return local === 'auto' ? interceptor._handleLanguage2Local(language, this._language2Local(language)) : local;
  23 + } catch (e) {
  24 + return 'zh-Hans';
  25 + }
  26 + },
  27 + finalRefresherDefaultText() {
  28 + return this._getI18nText('zp.refresher.default', this.refresherDefaultText);
  29 + },
  30 + finalRefresherPullingText() {
  31 + return this._getI18nText('zp.refresher.pulling', this.refresherPullingText);
  32 + },
  33 + finalRefresherRefreshingText() {
  34 + return this._getI18nText('zp.refresher.refreshing', this.refresherRefreshingText);
  35 + },
  36 + finalRefresherCompleteText() {
  37 + return this._getI18nText('zp.refresher.complete', this.refresherCompleteText);
  38 + },
  39 + finalRefresherUpdateTimeTextMap() {
  40 + return {
  41 + title: t('zp.refresherUpdateTime.title'),
  42 + none: t('zp.refresherUpdateTime.none'),
  43 + today: t('zp.refresherUpdateTime.today'),
  44 + yesterday: t('zp.refresherUpdateTime.yesterday')
  45 + };
  46 + },
  47 + finalLoadingMoreDefaultText() {
  48 + return this._getI18nText('zp.loadingMore.default', this.loadingMoreDefaultText);
  49 + },
  50 + finalLoadingMoreLoadingText() {
  51 + return this._getI18nText('zp.loadingMore.loading', this.loadingMoreLoadingText);
  52 + },
  53 + finalLoadingMoreNoMoreText() {
  54 + return this._getI18nText('zp.loadingMore.noMore', this.loadingMoreNoMoreText);
  55 + },
  56 + finalLoadingMoreFailText() {
  57 + return this._getI18nText('zp.loadingMore.fail', this.loadingMoreFailText);
  58 + },
  59 + finalEmptyViewText() {
  60 + return this.isLoadFailed ? this.finalEmptyViewErrorText : this._getI18nText('zp.emptyView.title', this.emptyViewText);
  61 + },
  62 + finalEmptyViewReloadText() {
  63 + return this._getI18nText('zp.emptyView.reload', this.emptyViewReloadText);
  64 + },
  65 + finalEmptyViewErrorText() {
  66 + return this._getI18nText('zp.emptyView.error', this.emptyViewErrorText);
  67 + },
  68 + finalSystemLoadingText() {
  69 + return this._getI18nText('zp.systemLoading.title', this.systemLoadingText);
  70 + },
  71 + },
  72 + methods: {
  73 + //获取当前z-paging的语言
  74 + getLanguage() {
  75 + return this.finalLanguage;
  76 + },
  77 + //获取国际化转换后的文本
  78 + _getI18nText(key, value) {
  79 + const dataType = Object.prototype.toString.call(value);
  80 + if (dataType === '[object Object]') {
  81 + const nextValue = value[this.finalLanguage];
  82 + if (nextValue) return nextValue;
  83 + } else if (dataType === '[object String]') {
  84 + return value;
  85 + }
  86 + return t(key);
  87 + },
  88 + //系统language转i18n local
  89 + _language2Local(language) {
  90 + const formatedLanguage = language.toLowerCase().replace(new RegExp('_', ''), '-');
  91 + if (formatedLanguage.indexOf('zh') !== -1) {
  92 + if (formatedLanguage === 'zh' || formatedLanguage === 'zh-cn' || formatedLanguage.indexOf('zh-hans') !== -1) {
  93 + return 'zh-Hans';
  94 + }
  95 + return 'zh-Hant';
  96 + }
  97 + if (formatedLanguage.indexOf('en') !== -1) return 'en';
  98 + return language;
  99 + }
  100 + }
  101 +}
garbage-removal/src/components/z-paging/js/modules/load-more.js 0 → 100644
  1 +// [z-paging]滚动到底部加载更多模块
  2 +import u from '.././z-paging-utils'
  3 +import Enum from '.././z-paging-enum'
  4 +
  5 +export default {
  6 + props: {
  7 + //自定义底部加载更多样式
  8 + loadingMoreCustomStyle: {
  9 + type: Object,
  10 + default: function() {
  11 + return u.gc('loadingMoreCustomStyle', {});
  12 + }
  13 + },
  14 + //自定义底部加载更多文字样式
  15 + loadingMoreTitleCustomStyle: {
  16 + type: Object,
  17 + default: function() {
  18 + return u.gc('loadingMoreTitleCustomStyle', {});
  19 + }
  20 + },
  21 + //自定义底部加载更多加载中动画样式
  22 + loadingMoreLoadingIconCustomStyle: {
  23 + type: Object,
  24 + default: function() {
  25 + return u.gc('loadingMoreLoadingIconCustomStyle', {});
  26 + }
  27 + },
  28 + //自定义底部加载更多加载中动画图标类型,可选flower或circle,默认为flower
  29 + loadingMoreLoadingIconType: {
  30 + type: String,
  31 + default: u.gc('loadingMoreLoadingIconType', 'flower')
  32 + },
  33 + //自定义底部加载更多加载中动画图标图片
  34 + loadingMoreLoadingIconCustomImage: {
  35 + type: String,
  36 + default: u.gc('loadingMoreLoadingIconCustomImage', '')
  37 + },
  38 + //底部加载更多加载中view是否展示旋转动画,默认为是
  39 + loadingMoreLoadingAnimated: {
  40 + type: Boolean,
  41 + default: u.gc('loadingMoreLoadingAnimated', true)
  42 + },
  43 + //是否启用加载更多数据(含滑动到底部加载更多数据和点击加载更多数据),默认为是
  44 + loadingMoreEnabled: {
  45 + type: Boolean,
  46 + default: u.gc('loadingMoreEnabled', true)
  47 + },
  48 + //是否启用滑动到底部加载更多数据,默认为是
  49 + toBottomLoadingMoreEnabled: {
  50 + type: Boolean,
  51 + default: u.gc('toBottomLoadingMoreEnabled', true)
  52 + },
  53 + //滑动到底部状态为默认状态时,以加载中的状态展示,默认为否。若设置为是,可避免滚动到底部看到默认状态然后立刻变为加载中状态的问题,但分页数量未超过一屏时,不会显示【点击加载更多】
  54 + loadingMoreDefaultAsLoading: {
  55 + type: [Boolean],
  56 + default: u.gc('loadingMoreDefaultAsLoading', false)
  57 + },
  58 + //滑动到底部"默认"文字,默认为【点击加载更多】
  59 + loadingMoreDefaultText: {
  60 + type: [String, Object],
  61 + default: u.gc('loadingMoreDefaultText', null)
  62 + },
  63 + //滑动到底部"加载中"文字,默认为【正在加载...】
  64 + loadingMoreLoadingText: {
  65 + type: [String, Object],
  66 + default: u.gc('loadingMoreLoadingText', null)
  67 + },
  68 + //滑动到底部"没有更多"文字,默认为【没有更多了】
  69 + loadingMoreNoMoreText: {
  70 + type: [String, Object],
  71 + default: u.gc('loadingMoreNoMoreText', null)
  72 + },
  73 + //滑动到底部"加载失败"文字,默认为【加载失败,点击重新加载】
  74 + loadingMoreFailText: {
  75 + type: [String, Object],
  76 + default: u.gc('loadingMoreFailText', null)
  77 + },
  78 + //当没有更多数据且分页内容未超出z-paging时是否隐藏没有更多数据的view,默认为否
  79 + hideNoMoreInside: {
  80 + type: Boolean,
  81 + default: u.gc('hideNoMoreInside', false)
  82 + },
  83 + //当没有更多数据且分页数组长度少于这个值时,隐藏没有更多数据的view,默认为0,代表不限制。
  84 + hideNoMoreByLimit: {
  85 + type: Number,
  86 + default: u.gc('hideNoMoreByLimit', 0)
  87 + },
  88 + //是否显示默认的加载更多text,默认为是
  89 + showDefaultLoadingMoreText: {
  90 + type: Boolean,
  91 + default: u.gc('showDefaultLoadingMoreText', true)
  92 + },
  93 + //是否显示没有更多数据的view
  94 + showLoadingMoreNoMoreView: {
  95 + type: Boolean,
  96 + default: u.gc('showLoadingMoreNoMoreView', true)
  97 + },
  98 + //是否显示没有更多数据的分割线,默认为是
  99 + showLoadingMoreNoMoreLine: {
  100 + type: Boolean,
  101 + default: u.gc('showLoadingMoreNoMoreLine', true)
  102 + },
  103 + //自定义底部没有更多数据的分割线样式
  104 + loadingMoreNoMoreLineCustomStyle: {
  105 + type: Object,
  106 + default: function() {
  107 + return u.gc('loadingMoreNoMoreLineCustomStyle', {});
  108 + },
  109 + },
  110 + //当分页未满一屏时,是否自动加载更多,默认为否(nvue无效)
  111 + insideMore: {
  112 + type: Boolean,
  113 + default: u.gc('insideMore', false)
  114 + },
  115 + //距底部/右边多远时(单位px),触发 scrolltolower 事件,默认为100rpx
  116 + lowerThreshold: {
  117 + type: [Number, String],
  118 + default: u.gc('lowerThreshold', '100rpx')
  119 + },
  120 + },
  121 + data() {
  122 + return {
  123 + M: Enum.More,
  124 + //底部加载更多状态
  125 + loadingStatus: Enum.More.Default,
  126 + loadingStatusAfterRender: Enum.More.Default,
  127 + loadingMoreTimeStamp: 0,
  128 + loadingMoreDefaultSlot: null,
  129 + showLoadingMore: false,
  130 + customNoMore: -1,
  131 + }
  132 + },
  133 + computed: {
  134 + zLoadMoreConfig() {
  135 + return {
  136 + status: this.loadingStatusAfterRender,
  137 + defaultAsLoading: this.loadingMoreDefaultAsLoading,
  138 + defaultThemeStyle: this.finalLoadingMoreThemeStyle,
  139 + customStyle: this.loadingMoreCustomStyle,
  140 + titleCustomStyle: this.loadingMoreTitleCustomStyle,
  141 + iconCustomStyle: this.loadingMoreLoadingIconCustomStyle,
  142 + loadingIconType: this.loadingMoreLoadingIconType,
  143 + loadingIconCustomImage: this.loadingMoreLoadingIconCustomImage,
  144 + loadingAnimated: this.loadingMoreLoadingAnimated,
  145 + showNoMoreLine: this.showLoadingMoreNoMoreLine,
  146 + noMoreLineCustomStyle: this.loadingMoreNoMoreLineCustomStyle,
  147 + defaultText: this.finalLoadingMoreDefaultText,
  148 + loadingText: this.finalLoadingMoreLoadingText,
  149 + noMoreText: this.finalLoadingMoreNoMoreText,
  150 + failText: this.finalLoadingMoreFailText,
  151 + hideContent: !this.loadingMoreDefaultAsLoading && this.listRendering,
  152 + };
  153 + },
  154 + finalLoadingMoreThemeStyle() {
  155 + return this.loadingMoreThemeStyle.length ? this.loadingMoreThemeStyle : this.defaultThemeStyle;
  156 + },
  157 + showLoadingMoreDefault() {
  158 + return this._showLoadingMore('Default');
  159 + },
  160 + showLoadingMoreLoading() {
  161 + return this._showLoadingMore('Loading');
  162 + },
  163 + showLoadingMoreNoMore() {
  164 + return this._showLoadingMore('NoMore');
  165 + },
  166 + showLoadingMoreFail() {
  167 + return this._showLoadingMore('Fail');
  168 + },
  169 + showLoadingMoreCustom() {
  170 + return this._showLoadingMore('Custom');
  171 + }
  172 + },
  173 + methods: {
  174 + //页面滚动到底部时通知z-paging进行进一步处理
  175 + pageReachBottom() {
  176 + !this.useChatRecordMode && this._onLoadingMore('toBottom');
  177 + },
  178 + //手动触发上拉加载更多(非必须,可依据具体需求使用)
  179 + doLoadMore(type) {
  180 + this._onLoadingMore(type);
  181 + },
  182 + //通过@scroll事件检测是否滚动到了底部
  183 + _checkScrolledToBottom(scrollDiff, checked = false) {
  184 + if (this.cacheScrollNodeHeight === -1) {
  185 + this._getNodeClientRect('.zp-scroll-view').then((res) => {
  186 + if (res) {
  187 + const pageScrollNodeHeight = res[0].height;
  188 + this.cacheScrollNodeHeight = pageScrollNodeHeight;
  189 + if (scrollDiff - pageScrollNodeHeight <= this.finalLowerThreshold) {
  190 + this._onLoadingMore('toBottom');
  191 + }
  192 + }
  193 + });
  194 + } else {
  195 + if (scrollDiff - this.cacheScrollNodeHeight <= this.finalLowerThreshold) {
  196 + this._onLoadingMore('toBottom');
  197 + } else if (scrollDiff - this.cacheScrollNodeHeight <= 500 && !checked) {
  198 + u.delay(() => {
  199 + this._getNodeClientRect('.zp-scroll-view', true, true).then((res) => {
  200 + this.oldScrollTop = res[0].scrollTop;
  201 + const newScrollDiff = res[0].scrollHeight - this.oldScrollTop;
  202 + this._checkScrolledToBottom(newScrollDiff, true);
  203 + })
  204 + }, 150, 'checkScrolledToBottomDelay')
  205 + }
  206 + }
  207 + },
  208 + //触发加载更多时调用,from:toBottom-滑动到底部触发;1、click-点击加载更多触发
  209 + _onLoadingMore(from = 'click') {
  210 + if (this.isIos && from === 'toBottom' && !this.scrollToBottomBounceEnabled && this.scrollEnable) {
  211 + this.scrollEnable = false;
  212 + this.$nextTick(() => {
  213 + this.scrollEnable = true;
  214 + })
  215 + }
  216 + this.$emit('scrolltolower', from);
  217 + if (from === 'toBottom' && (!this.toBottomLoadingMoreEnabled || this.useChatRecordMode)) return;
  218 + if (this.refresherOnly || !this.loadingMoreEnabled || !(this.loadingStatus === Enum.More.Default || this.loadingStatus === Enum.More.Fail) || this.loading || this.showEmpty) return;
  219 + // #ifdef MP-WEIXIN
  220 + if (!this.isIos && !this.refresherOnly && !this.usePageScroll) {
  221 + const currentTimestamp = u.getTime();
  222 + if (this.loadingMoreTimeStamp > 0 && currentTimestamp - this.loadingMoreTimeStamp < 100) {
  223 + this.loadingMoreTimeStamp = 0;
  224 + return;
  225 + }
  226 + }
  227 + // #endif
  228 + this._doLoadingMore();
  229 + },
  230 + //处理开始加载更多
  231 + _doLoadingMore() {
  232 + if (this.pageNo >= this.defaultPageNo && this.loadingStatus !== Enum.More.NoMore) {
  233 + this.pageNo ++;
  234 + this._startLoading(false);
  235 + if (this.isLocalPaging) {
  236 + this._localPagingQueryList(this.pageNo, this.defaultPageSize, this.localPagingLoadingTime, res => {
  237 + this.completeByTotal(res, this.totalLocalPagingList.length);
  238 + })
  239 + } else {
  240 + this._emitQuery(this.pageNo, this.defaultPageSize, Enum.QueryFrom.LoadingMore);
  241 + this._callMyParentQuery();
  242 + }
  243 + this.loadingType = Enum.LoadingType.LoadingMore;
  244 + }
  245 + },
  246 + //(预处理)判断当没有更多数据且分页内容未超出z-paging时是否显示没有更多数据的view
  247 + _preCheckShowNoMoreInside(newVal, scrollViewNode, pagingContainerNode) {
  248 + if (this.loadingStatus === Enum.More.NoMore && this.hideNoMoreByLimit > 0 && newVal.length) {
  249 + this.showLoadingMore = newVal.length > this.hideNoMoreByLimit;
  250 + } else if ((this.loadingStatus === Enum.More.NoMore && this.hideNoMoreInside && newVal.length) || (this.insideMore && this.insideOfPaging !== false && newVal.length)) {
  251 + this.$nextTick(() => {
  252 + this._checkShowNoMoreInside(newVal, scrollViewNode, pagingContainerNode);
  253 + })
  254 + if (this.insideMore && this.insideOfPaging !== false && newVal.length) {
  255 + this.showLoadingMore = newVal.length;
  256 + }
  257 + } else {
  258 + this.showLoadingMore = newVal.length;
  259 + }
  260 + },
  261 + //判断当没有更多数据且分页内容未超出z-paging时是否显示没有更多数据的view
  262 + async _checkShowNoMoreInside(totalData, oldScrollViewNode, oldPagingContainerNode) {
  263 + try {
  264 + const scrollViewNode = oldScrollViewNode || await this._getNodeClientRect('.zp-scroll-view');
  265 + if (this.usePageScroll) {
  266 + if (scrollViewNode) {
  267 + const scrollViewTotalH = scrollViewNode[0].top + scrollViewNode[0].height;
  268 + this.insideOfPaging = scrollViewTotalH < this.windowHeight;
  269 + if (this.hideNoMoreInside) {
  270 + this.showLoadingMore = !this.insideOfPaging;
  271 + }
  272 + this._updateInsideOfPaging();
  273 + }
  274 + } else {
  275 + const pagingContainerNode = oldPagingContainerNode || await this._getNodeClientRect('.zp-paging-container-content');
  276 + const pagingContainerH = pagingContainerNode ? pagingContainerNode[0].height : 0;
  277 + const scrollViewH = scrollViewNode ? scrollViewNode[0].height : 0;
  278 + this.insideOfPaging = pagingContainerH < scrollViewH;
  279 + if (this.hideNoMoreInside) {
  280 + this.showLoadingMore = !this.insideOfPaging;
  281 + }
  282 + this._updateInsideOfPaging();
  283 + }
  284 + } catch (e) {
  285 + this.insideOfPaging = !totalData.length;
  286 + if (this.hideNoMoreInside) {
  287 + this.showLoadingMore = !this.insideOfPaging;
  288 + }
  289 + this._updateInsideOfPaging();
  290 + }
  291 + },
  292 + //是否要展示上拉加载更多view
  293 + _showLoadingMore(type) {
  294 + if (!this.showLoadingMoreWhenReload && (!(this.loadingStatus === Enum.More.Default ? this.nShowBottom : true) || !this.realTotalData.length)) return false;
  295 + if (((!this.showLoadingMoreWhenReload || this.isUserPullDown || this.loadingStatus !== Enum.More.Loading) && !this.showLoadingMore) ||
  296 + (!this.loadingMoreEnabled && (!this.showLoadingMoreWhenReload || this.isUserPullDown || this.loadingStatus !== Enum.More.Loading)) || this.refresherOnly) {
  297 + return false;
  298 + }
  299 + if (this.useChatRecordMode && type !== 'Loading') return false;
  300 + if (!this.zSlots) return false;
  301 + if (type === 'Custom') {
  302 + return this.showDefaultLoadingMoreText && !(this.loadingStatus === Enum.More.NoMore && !this.showLoadingMoreNoMoreView);
  303 + }
  304 + const res = this.loadingStatus === Enum.More[type] && this.zSlots[`loadingMore${type}`] && (type === 'NoMore' ? this.showLoadingMoreNoMoreView : true);
  305 + if (res) {
  306 + // #ifdef APP-NVUE
  307 + if (!this.isIos) {
  308 + this.nLoadingMoreFixedHeight = false;
  309 + }
  310 + // #endif
  311 + }
  312 + return res;
  313 + },
  314 + }
  315 +}
garbage-removal/src/components/z-paging/js/modules/loading.js 0 → 100644
  1 +// [z-paging]loading相关模块
  2 +import u from '.././z-paging-utils'
  3 +import Enum from '.././z-paging-enum'
  4 +
  5 +export default {
  6 + props: {
  7 + //第一次加载后自动隐藏loading slot,默认为是
  8 + autoHideLoadingAfterFirstLoaded: {
  9 + type: Boolean,
  10 + default: u.gc('autoHideLoadingAfterFirstLoaded', true)
  11 + },
  12 + //loading slot是否铺满屏幕并固定,默认为否
  13 + loadingFullFixed: {
  14 + type: Boolean,
  15 + default: u.gc('loadingFullFixed', false)
  16 + },
  17 + //是否自动显示系统Loading:即uni.showLoading,若开启则将在刷新列表时(调用reload、refresh时)显示,下拉刷新和滚动到底部加载更多不会显示,默认为false。
  18 + autoShowSystemLoading: {
  19 + type: Boolean,
  20 + default: u.gc('autoShowSystemLoading', false)
  21 + },
  22 + //显示系统Loading时是否显示透明蒙层,防止触摸穿透,默认为是(H5、App、微信小程序、百度小程序有效)
  23 + systemLoadingMask: {
  24 + type: Boolean,
  25 + default: u.gc('systemLoadingMask', true)
  26 + },
  27 + //显示系统Loading时显示的文字,默认为"加载中"
  28 + systemLoadingText: {
  29 + type: [String, Object],
  30 + default: u.gc('systemLoadingText', null)
  31 + },
  32 + },
  33 + data() {
  34 + return {
  35 + loading: false,
  36 + loadingForNow: false,
  37 + }
  38 + },
  39 + watch: {
  40 + loadingStatus(newVal) {
  41 + this.$emit('loadingStatusChange', newVal);
  42 + this.$nextTick(() => {
  43 + this.loadingStatusAfterRender = newVal;
  44 + })
  45 + // #ifdef APP-NVUE
  46 + if (this.useChatRecordMode) {
  47 + if (this.pageNo === this.defaultPageNo && newVal === Enum.More.NoMore) {
  48 + this.nIsFirstPageAndNoMore = true;
  49 + return;
  50 + }
  51 + }
  52 + this.nIsFirstPageAndNoMore = false;
  53 + // #endif
  54 + },
  55 + loading(newVal){
  56 + if (newVal) {
  57 + this.loadingForNow = newVal;
  58 + }
  59 + },
  60 + },
  61 + computed: {
  62 + showLoading() {
  63 + if (this.firstPageLoaded || !this.loading || !this.loadingForNow) return false;
  64 + if (this.finalShowSystemLoading){
  65 + uni.showLoading({
  66 + title: this.finalSystemLoadingText,
  67 + mask: this.systemLoadingMask
  68 + })
  69 + }
  70 + return this.autoHideLoadingAfterFirstLoaded ? (this.fromEmptyViewReload ? true : !this.pagingLoaded) : this.loadingType === Enum.LoadingType.Refresher;
  71 + },
  72 + finalShowSystemLoading() {
  73 + return this.autoShowSystemLoading && this.loadingType === Enum.LoadingType.Refresher;
  74 + }
  75 + },
  76 + methods: {
  77 + //处理开始加载更多状态
  78 + _startLoading(isReload = false) {
  79 + if ((this.showLoadingMoreWhenReload && !this.isUserPullDown) || !isReload) {
  80 + this.loadingStatus = Enum.More.Loading;
  81 + }
  82 + this.loading = true;
  83 + },
  84 + //停止系统loading和refresh
  85 + _endSystemLoadingAndRefresh(){
  86 + this.finalShowSystemLoading && uni.hideLoading();
  87 + !this.useCustomRefresher && uni.stopPullDownRefresh();
  88 + // #ifdef APP-NVUE
  89 + this.usePageScroll && uni.stopPullDownRefresh();
  90 + // #endif
  91 + }
  92 + }
  93 +}
garbage-removal/src/components/z-paging/js/modules/nvue.js 0 → 100644
  1 +// [z-paging]nvue独有部分模块
  2 +import u from '.././z-paging-utils'
  3 +import c from '.././z-paging-constant'
  4 +import Enum from '.././z-paging-enum'
  5 +
  6 +// #ifdef APP-NVUE
  7 +const weexAnimation = weex.requireModule('animation');
  8 +// #endif
  9 +export default {
  10 + props: {
  11 + // #ifdef APP-NVUE
  12 + //nvue中修改列表类型,可选值有list、waterfall和scroller,默认为list
  13 + nvueListIs: {
  14 + type: String,
  15 + default: u.gc('nvueListIs', 'list')
  16 + },
  17 + //nvue waterfall配置,仅在nvue中且nvueListIs=waterfall时有效,配置参数详情参见:https://uniapp.dcloud.io/component/waterfall
  18 + nvueWaterfallConfig: {
  19 + type: Object,
  20 + default: function() {
  21 + return u.gc('nvueWaterfallConfig', {});
  22 + }
  23 + },
  24 + //nvue 控制是否回弹效果,iOS不支持动态修改
  25 + nvueBounce: {
  26 + type: Boolean,
  27 + default: u.gc('nvueBounce', true)
  28 + },
  29 + //nvue中通过代码滚动到顶部/底部时,是否加快动画效果(无滚动动画时无效),默认为否
  30 + nvueFastScroll: {
  31 + type: Boolean,
  32 + default: u.gc('nvueFastScroll', false)
  33 + },
  34 + //nvue中list的id
  35 + nvueListId: {
  36 + type: String,
  37 + default: u.gc('nvueListId', '')
  38 + },
  39 + //nvue中refresh组件的样式
  40 + nvueRefresherStyle: {
  41 + type: Object,
  42 + default: function() {
  43 + return u.gc('nvueRefresherStyle', {});
  44 + }
  45 + },
  46 + //nvue中是否按分页模式(类似竖向swiper)显示List,默认为false
  47 + nvuePagingEnabled: {
  48 + type: Boolean,
  49 + default: u.gc('nvuePagingEnabled', false)
  50 + },
  51 + //是否隐藏nvue列表底部的tagView,此view用于标识滚动到底部位置,若隐藏则滚动到底部功能将失效,在nvue中实现吸顶+swiper功能时需将最外层z-paging的此属性设置为true。默认为否
  52 + hideNvueBottomTag: {
  53 + type: Boolean,
  54 + default: u.gc('hideNvueBottomTag', false)
  55 + },
  56 + //nvue中控制onscroll事件触发的频率:表示两次onscroll事件之间列表至少滚动了10px。注意,将该值设置为较小的数值会提高滚动事件采样的精度,但同时也会降低页面的性能
  57 + offsetAccuracy: {
  58 + type: Number,
  59 + default: u.gc('offsetAccuracy', 10)
  60 + },
  61 + // #endif
  62 + },
  63 + data() {
  64 + return {
  65 + nRefresherLoading: false,
  66 + nListIsDragging: false,
  67 + nShowBottom: true,
  68 + nFixFreezing: false,
  69 + nShowRefresherReveal: false,
  70 + nIsFirstPageAndNoMore: false,
  71 + nFirstPageAndNoMoreChecked: false,
  72 + nLoadingMoreFixedHeight: false,
  73 + nShowRefresherRevealHeight: 0,
  74 + nOldShowRefresherRevealHeight: -1,
  75 + nRefresherWidth: uni.upx2px(750),
  76 + }
  77 + },
  78 + watch: {
  79 + // #ifdef APP-NVUE
  80 + nIsFirstPageAndNoMore: {
  81 + handler(newVal) {
  82 + const cellStyle = !this.useChatRecordMode || newVal ? {} : { transform: 'rotate(180deg)' };
  83 + this.$emit('update:cellStyle', cellStyle);
  84 + this.$emit('cellStyleChange', cellStyle);
  85 + },
  86 + immediate: true
  87 + },
  88 + // #endif
  89 + },
  90 + computed: {
  91 + // #ifdef APP-NVUE
  92 + nScopedSlots() {
  93 + // #ifdef VUE2
  94 + return this.$scopedSlots;
  95 + // #endif
  96 + // #ifdef VUE3
  97 + return null;
  98 + // #endif
  99 + },
  100 + nWaterfallColumnCount() {
  101 + if (this.finalNvueListIs !== 'waterfall') return 0;
  102 + return this._nGetWaterfallConfig('column-count', 2);
  103 + },
  104 + nWaterfallColumnWidth() {
  105 + return this._nGetWaterfallConfig('column-width', 'auto');
  106 + },
  107 + nWaterfallColumnGap() {
  108 + return this._nGetWaterfallConfig('column-gap', 'normal');
  109 + },
  110 + nWaterfallLeftGap() {
  111 + return this._nGetWaterfallConfig('left-gap', 0);
  112 + },
  113 + nWaterfallRightGap() {
  114 + return this._nGetWaterfallConfig('right-gap', 0);
  115 + },
  116 + nViewIs() {
  117 + const is = this.finalNvueListIs;
  118 + return is === 'scroller' || is === 'view' ? 'view' : is === 'waterfall' ? 'header' : 'cell';
  119 + },
  120 + nSafeAreaBottomHeight() {
  121 + return this.safeAreaInsetBottom ? this.safeAreaBottom : 0;
  122 + },
  123 + nChatRecordRotateStyle() {
  124 + return this.useChatRecordMode ? { transform: this.nIsFirstPageAndNoMore ? 'rotate(0deg)' : 'rotate(180deg)' } : {};
  125 + },
  126 + finalNvueListIs() {
  127 + if (this.usePageScroll) return 'view';
  128 + const nvueListIsLowerCase = this.nvueListIs.toLowerCase();
  129 + if (['list','waterfall','scroller'].indexOf(nvueListIsLowerCase) !== -1) return nvueListIsLowerCase;
  130 + return 'list';
  131 + },
  132 + finalNvueSuperListIs() {
  133 + return this.usePageScroll ? 'view' : 'scroller';
  134 + },
  135 + finalNvueRefresherEnabled() {
  136 + return this.finalNvueListIs !== 'view' && this.finalRefresherEnabled && !this.nShowRefresherReveal && !this.useChatRecordMode;
  137 + },
  138 + // #endif
  139 + },
  140 + mounted(){
  141 + // #ifdef APP-NVUE
  142 + //旋转屏幕时更新宽度
  143 + uni.onWindowResize((res) => {
  144 + // this._nUpdateRefresherWidth();
  145 + })
  146 + // #endif
  147 + },
  148 + methods: {
  149 + // #ifdef APP-NVUE
  150 + //列表滚动时触发
  151 + _nOnScroll(e) {
  152 + this.$emit('scroll', e);
  153 + const contentOffsetY = -e.contentOffset.y;
  154 + this.oldScrollTop = contentOffsetY;
  155 + this.nListIsDragging = e.isDragging;
  156 + this._checkShouldShowBackToTop(contentOffsetY, contentOffsetY - 1);
  157 + },
  158 + //下拉刷新刷新中
  159 + _nOnRrefresh() {
  160 + if (this.nShowRefresherReveal) return;
  161 + this.nRefresherLoading = true;
  162 + this.refresherStatus = Enum.Refresher.Loading;
  163 + this._doRefresherLoad();
  164 + },
  165 + //下拉刷新下拉中
  166 + _nOnPullingdown(e) {
  167 + if (this.refresherStatus === Enum.Refresher.Loading || (this.isIos && !this.nListIsDragging)) return;
  168 + this._emitTouchmove(e);
  169 + const { viewHeight, pullingDistance } = e;
  170 + this.refresherStatus = pullingDistance >= viewHeight ? Enum.Refresher.ReleaseToRefresh : Enum.Refresher.Default;
  171 + },
  172 + //下拉刷新结束
  173 + _nRefresherEnd(doEnd = true) {
  174 + if (doEnd) {
  175 + this._nDoRefresherEndAnimation(0, -this.nShowRefresherRevealHeight);
  176 + !this.usePageScroll && this.$refs['zp-n-list'].resetLoadmore();
  177 + this.nRefresherLoading = false;
  178 + }
  179 + },
  180 + //执行主动触发下拉刷新动画
  181 + _nDoRefresherEndAnimation(height, translateY, animate = true, checkStack = true) {
  182 + this._cleanRefresherCompleteTimeout();
  183 + this._cleanRefresherEndTimeout();
  184 +
  185 + if (!this.finalShowRefresherWhenReload) {
  186 + this.refresherEndTimeout = u.delay(() => {
  187 + this.refresherStatus = Enum.Refresher.Default;
  188 + }, this.refresherCompleteDuration);
  189 + return;
  190 + }
  191 + const stackCount = this.refresherRevealStackCount;
  192 + if (height === 0 && checkStack) {
  193 + this.refresherRevealStackCount --;
  194 + if (stackCount > 1) return;
  195 + this.refresherEndTimeout = u.delay(() => {
  196 + this.refresherStatus = Enum.Refresher.Default;
  197 + }, this.refresherCompleteDuration);
  198 + }
  199 + if (stackCount > 1) {
  200 + this.refresherStatus = Enum.Refresher.Loading;
  201 + }
  202 +
  203 + const duration = animate ? 200 : 0;
  204 + if (this.nOldShowRefresherRevealHeight !== height) {
  205 + if (height > 0) {
  206 + this.nShowRefresherReveal = true;
  207 + }
  208 + weexAnimation.transition(this.$refs['zp-n-list-refresher-reveal'], {
  209 + styles: {
  210 + height: `${height}px`,
  211 + transform: `translateY(${translateY}px)`,
  212 + },
  213 + duration,
  214 + timingFunction: 'linear',
  215 + needLayout: true,
  216 + delay: 0
  217 + })
  218 + }
  219 + u.delay(() => {
  220 + if (animate) {
  221 + this.nShowRefresherReveal = height > 0;
  222 + }
  223 + }, duration > 0 ? duration - 60 : 0);
  224 + this.nOldShowRefresherRevealHeight = height;
  225 + },
  226 + //滚动到底部加载更多
  227 + _nOnLoadmore() {
  228 + if (this.nShowRefresherReveal || !this.totalData.length) return;
  229 + this.useChatRecordMode ? this.doChatRecordLoadMore() : this._onLoadingMore('toBottom');
  230 + },
  231 + //获取nvue waterfall单项配置
  232 + _nGetWaterfallConfig(key, defaultValue) {
  233 + return this.nvueWaterfallConfig[key] || defaultValue;
  234 + },
  235 + //更新nvue 下拉刷新view容器的宽度
  236 + _nUpdateRefresherWidth() {
  237 + u.delay(() => {
  238 + this.$nextTick(()=>{
  239 + this._getNodeClientRect('.zp-n-list').then(node => {
  240 + if (node) {
  241 + this.nRefresherWidth = node[0].width || this.nRefresherWidth;
  242 + }
  243 + })
  244 + })
  245 + })
  246 + }
  247 + // #endif
  248 + }
  249 +}
garbage-removal/src/components/z-paging/js/modules/refresher.js 0 → 100644
  1 +// [z-paging]下拉刷新view模块
  2 +import u from '.././z-paging-utils'
  3 +import c from '.././z-paging-constant'
  4 +import Enum from '.././z-paging-enum'
  5 +
  6 +export default {
  7 + props: {
  8 + //下拉刷新的主题样式,支持black,white,默认black
  9 + refresherThemeStyle: {
  10 + type: String,
  11 + default: u.gc('refresherThemeStyle', '')
  12 + },
  13 + //自定义下拉刷新中左侧图标的样式
  14 + refresherImgStyle: {
  15 + type: Object,
  16 + default: function() {
  17 + return u.gc('refresherImgStyle', {});
  18 + }
  19 + },
  20 + //自定义下拉刷新中右侧状态描述文字的样式
  21 + refresherTitleStyle: {
  22 + type: Object,
  23 + default: function() {
  24 + return u.gc('refresherTitleStyle', {});
  25 + }
  26 + },
  27 + //自定义下拉刷新中右侧最后更新时间文字的样式(show-refresher-update-time为true时有效)
  28 + refresherUpdateTimeStyle: {
  29 + type: Object,
  30 + default: function() {
  31 + return u.gc('refresherUpdateTimeStyle', {});
  32 + }
  33 + },
  34 + //在微信小程序和QQ小程序中,是否实时监听下拉刷新中进度,默认为否
  35 + watchRefresherTouchmove: {
  36 + type: Boolean,
  37 + default: u.gc('watchRefresherTouchmove', false)
  38 + },
  39 + //底部加载更多的主题样式,支持black,white,默认black
  40 + loadingMoreThemeStyle: {
  41 + type: String,
  42 + default: u.gc('loadingMoreThemeStyle', '')
  43 + },
  44 + //是否只使用下拉刷新,设置为true后将关闭mounted自动请求数据、关闭滚动到底部加载更多,强制隐藏空数据图。默认为否
  45 + refresherOnly: {
  46 + type: Boolean,
  47 + default: u.gc('refresherOnly', false)
  48 + },
  49 + //自定义下拉刷新默认状态下回弹动画时间,单位为毫秒,默认为100毫秒,nvue无效
  50 + refresherDefaultDuration: {
  51 + type: [Number, String],
  52 + default: u.gc('refresherDefaultDuration', 100)
  53 + },
  54 + //自定义下拉刷新结束以后延迟回弹的时间,单位为毫秒,默认为0
  55 + refresherCompleteDelay: {
  56 + type: [Number, String],
  57 + default: u.gc('refresherCompleteDelay', 0)
  58 + },
  59 + //自定义下拉刷新结束回弹动画时间,单位为毫秒,默认为300毫秒(refresherEndBounceEnabled为false时,refresherCompleteDuration为设定值的1/3),nvue无效
  60 + refresherCompleteDuration: {
  61 + type: [Number, String],
  62 + default: u.gc('refresherCompleteDuration', 300)
  63 + },
  64 + //自定义下拉刷新结束状态下是否允许列表滚动,默认为否
  65 + refresherCompleteScrollable: {
  66 + type: Boolean,
  67 + default: u.gc('refresherCompleteScrollable', false)
  68 + },
  69 + //是否使用自定义的下拉刷新,默认为是,即使用z-paging的下拉刷新。设置为false即代表使用uni scroll-view自带的下拉刷新,h5、App、微信小程序以外的平台不支持uni scroll-view自带的下拉刷新
  70 + useCustomRefresher: {
  71 + type: Boolean,
  72 + default: u.gc('useCustomRefresher', true)
  73 + },
  74 + //自定义下拉刷新下拉帧率,默认为40,过高可能会出现抖动问题
  75 + refresherFps: {
  76 + type: [Number, String],
  77 + default: u.gc('refresherFps', 40)
  78 + },
  79 + //自定义下拉刷新允许触发的最大下拉角度,默认为40度,当下拉角度小于设定值时,自定义下拉刷新动画不会被触发
  80 + refresherMaxAngle: {
  81 + type: [Number, String],
  82 + default: u.gc('refresherMaxAngle', 40)
  83 + },
  84 + //自定义下拉刷新的角度由未达到最大角度变到达到最大角度时,是否继续下拉刷新手势,默认为否
  85 + refresherAngleEnableChangeContinued: {
  86 + type: Boolean,
  87 + default: u.gc('refresherAngleEnableChangeContinued', false)
  88 + },
  89 + //自定义下拉刷新默认状态下的文字
  90 + refresherDefaultText: {
  91 + type: [String, Object],
  92 + default: u.gc('refresherDefaultText', null)
  93 + },
  94 + //自定义下拉刷新松手立即刷新状态下的文字
  95 + refresherPullingText: {
  96 + type: [String, Object],
  97 + default: u.gc('refresherPullingText', null)
  98 + },
  99 + //自定义下拉刷新刷新中状态下的文字
  100 + refresherRefreshingText: {
  101 + type: [String, Object],
  102 + default: u.gc('refresherRefreshingText', null)
  103 + },
  104 + //自定义下拉刷新刷新结束状态下的文字
  105 + refresherCompleteText: {
  106 + type: [String, Object],
  107 + default: u.gc('refresherCompleteText', null)
  108 + },
  109 + //自定义下拉刷新默认状态下的图片
  110 + refresherDefaultImg: {
  111 + type: String,
  112 + default: u.gc('refresherDefaultImg', null)
  113 + },
  114 + //自定义下拉刷新松手立即刷新状态下的图片,默认与refresherDefaultImg一致
  115 + refresherPullingImg: {
  116 + type: String,
  117 + default: u.gc('refresherPullingImg', null)
  118 + },
  119 + //自定义下拉刷新刷新中状态下的图片
  120 + refresherRefreshingImg: {
  121 + type: String,
  122 + default: u.gc('refresherRefreshingImg', null)
  123 + },
  124 + //自定义下拉刷新刷新结束状态下的图片
  125 + refresherCompleteImg: {
  126 + type: String,
  127 + default: u.gc('refresherCompleteImg', null)
  128 + },
  129 + //自定义下拉刷新刷新中状态下是否展示旋转动画
  130 + refresherRefreshingAnimated: {
  131 + type: Boolean,
  132 + default: u.gc('refresherRefreshingAnimated', true)
  133 + },
  134 + //是否开启自定义下拉刷新刷新结束回弹效果,默认为是
  135 + refresherEndBounceEnabled: {
  136 + type: Boolean,
  137 + default: u.gc('refresherEndBounceEnabled', true)
  138 + },
  139 + //是否开启自定义下拉刷新,默认为是
  140 + refresherEnabled: {
  141 + type: Boolean,
  142 + default: u.gc('refresherEnabled', true)
  143 + },
  144 + //设置自定义下拉刷新阈值,默认为80rpx
  145 + refresherThreshold: {
  146 + type: [Number, String],
  147 + default: u.gc('refresherThreshold', '80rpx')
  148 + },
  149 + //设置系统下拉刷新默认样式,支持设置 black,white,none,none 表示不使用默认样式,默认为black
  150 + refresherDefaultStyle: {
  151 + type: String,
  152 + default: u.gc('refresherDefaultStyle', 'black')
  153 + },
  154 + //设置自定义下拉刷新区域背景
  155 + refresherBackground: {
  156 + type: String,
  157 + default: u.gc('refresherBackground', 'transparent')
  158 + },
  159 + //设置固定的自定义下拉刷新区域背景
  160 + refresherFixedBackground: {
  161 + type: String,
  162 + default: u.gc('refresherFixedBackground', 'transparent')
  163 + },
  164 + //设置固定的自定义下拉刷新区域高度,默认为0
  165 + refresherFixedBacHeight: {
  166 + type: [Number, String],
  167 + default: u.gc('refresherFixedBacHeight', 0)
  168 + },
  169 + //设置自定义下拉刷新下拉超出阈值后继续下拉位移衰减的比例,范围0-1,值越大代表衰减越多。默认为0.65(nvue无效)
  170 + refresherOutRate: {
  171 + type: Number,
  172 + default: u.gc('refresherOutRate', 0.65)
  173 + },
  174 + //设置自定义下拉刷新下拉时实际下拉位移与用户下拉距离的比值,默认为0.75,即代表若用户下拉10px,则实际位移为7.5px(nvue无效)
  175 + refresherPullRate: {
  176 + type: Number,
  177 + default: u.gc('refresherPullRate', 0.75)
  178 + },
  179 + //是否显示最后更新时间,默认为否
  180 + showRefresherUpdateTime: {
  181 + type: Boolean,
  182 + default: u.gc('showRefresherUpdateTime', false)
  183 + },
  184 + //如果需要区别不同页面的最后更新时间,请为不同页面的z-paging的`refresher-update-time-key`设置不同的字符串
  185 + refresherUpdateTimeKey: {
  186 + type: String,
  187 + default: u.gc('refresherUpdateTimeKey', 'default')
  188 + },
  189 + //下拉刷新时下拉到“松手立即刷新”状态时是否使手机短振动,默认为否(h5无效)
  190 + refresherVibrate: {
  191 + type: Boolean,
  192 + default: u.gc('refresherVibrate', false)
  193 + },
  194 + //下拉刷新时是否禁止下拉刷新view跟随用户触摸竖直移动,默认为否。注意此属性只是禁止下拉刷新view移动,其他下拉刷新逻辑依然会正常触发
  195 + refresherNoTransform: {
  196 + type: Boolean,
  197 + default: u.gc('refresherNoTransform', false)
  198 + },
  199 + //是否开启下拉刷新状态栏占位,适用于隐藏导航栏时,下拉刷新需要避开状态栏高度的情况,默认为否
  200 + useRefresherStatusBarPlaceholder: {
  201 + type: Boolean,
  202 + default: u.gc('useRefresherStatusBarPlaceholder', false)
  203 + },
  204 + },
  205 + data() {
  206 + return {
  207 + R: Enum.Refresher,
  208 + //下拉刷新状态
  209 + refresherStatus: Enum.Refresher.Default,
  210 + refresherTouchstartY: 0,
  211 + lastRefresherTouchmove: null,
  212 + refresherReachMaxAngle: true,
  213 + refresherTransform: 'translateY(0px)',
  214 + refresherTransition: '',
  215 + finalRefresherDefaultStyle: 'black',
  216 + refresherRevealStackCount: 0,
  217 + refresherCompleteTimeout: null,
  218 + refresherCompleteSubTimeout: null,
  219 + refresherEndTimeout: null,
  220 + isTouchmovingTimeout: null,
  221 + refresherTriggered: false,
  222 + isTouchmoving: false,
  223 + isTouchEnded: false,
  224 + isUserPullDown: false,
  225 + privateRefresherEnabled: -1,
  226 + privateShowRefresherWhenReload: false,
  227 + customRefresherHeight: -1,
  228 + showCustomRefresher: false,
  229 + doRefreshAnimateAfter: false,
  230 + isRefresherInComplete: false,
  231 + pullDownTimeStamp: 0,
  232 + moveDis: 0,
  233 + oldMoveDis: 0,
  234 + currentDis: 0,
  235 + oldCurrentMoveDis: 0,
  236 + oldRefresherTouchmoveY: 0,
  237 + oldTouchDirection: '',
  238 + oldEmitedTouchDirection: '',
  239 + oldPullingDistance: -1,
  240 + refresherThresholdUpdateTag: 0
  241 + }
  242 + },
  243 + watch: {
  244 + refresherDefaultStyle: {
  245 + handler(newVal) {
  246 + if (newVal.length) {
  247 + this.finalRefresherDefaultStyle = newVal;
  248 + }
  249 + },
  250 + immediate: true
  251 + },
  252 + refresherStatus(newVal) {
  253 + newVal === Enum.Refresher.Loading && this._cleanRefresherEndTimeout();
  254 + this.refresherVibrate && newVal === Enum.Refresher.ReleaseToRefresh && this._doVibrateShort();
  255 + this.$emit('refresherStatusChange', newVal);
  256 + this.$emit('update:refresherStatus', newVal);
  257 + },
  258 + refresherEnabled(newVal) {
  259 + !newVal && this.endRefresh();
  260 + }
  261 + },
  262 + computed: {
  263 + pullDownDisTimeStamp() {
  264 + return 1000 / this.refresherFps;
  265 + },
  266 + finalRefresherEnabled() {
  267 + if (this.useChatRecordMode) return false;
  268 + if (this.privateRefresherEnabled === -1) return this.refresherEnabled;
  269 + return this.privateRefresherEnabled === 1;
  270 + },
  271 + finalRefresherThreshold() {
  272 + let refresherThreshold = this.refresherThreshold;
  273 + let idDefault = false;
  274 + if (refresherThreshold === '80rpx') {
  275 + idDefault = true;
  276 + if (this.showRefresherUpdateTime) {
  277 + refresherThreshold = '120rpx';
  278 + }
  279 + }
  280 + if (idDefault && this.customRefresherHeight > 0) return this.customRefresherHeight + this.finalRefresherThresholdPlaceholder;
  281 + return u.convertToPx(refresherThreshold) + this.finalRefresherThresholdPlaceholder;
  282 + },
  283 + finalRefresherThresholdPlaceholder() {
  284 + return this.useRefresherStatusBarPlaceholder ? this.statusBarHeight : 0;
  285 + },
  286 + finalRefresherFixedBacHeight() {
  287 + return u.convertToPx(this.refresherFixedBacHeight);
  288 + },
  289 + finalRefresherThemeStyle() {
  290 + return this.refresherThemeStyle.length ? this.refresherThemeStyle : this.defaultThemeStyle;
  291 + },
  292 + finalRefresherOutRate() {
  293 + let rate = this.refresherOutRate;
  294 + rate = Math.max(0,rate);
  295 + rate = Math.min(1,rate);
  296 + return rate;
  297 + },
  298 + finalRefresherPullRate() {
  299 + let rate = this.refresherPullRate;
  300 + rate = Math.max(0,rate);
  301 + return rate;
  302 + },
  303 + finalRefresherTransform() {
  304 + if (this.refresherNoTransform || this.refresherTransform === 'translateY(0px)') return 'none';
  305 + return this.refresherTransform;
  306 + },
  307 + finalShowRefresherWhenReload() {
  308 + return this.showRefresherWhenReload || this.privateShowRefresherWhenReload;
  309 + },
  310 + finalRefresherTriggered() {
  311 + if (!(this.finalRefresherEnabled && !this.useCustomRefresher)) return false;
  312 + return this.refresherTriggered;
  313 + },
  314 + showRefresher() {
  315 + const showRefresher = this.finalRefresherEnabled && this.useCustomRefresher;
  316 + // #ifndef APP-NVUE
  317 + this.customRefresherHeight === -1 && showRefresher && this.updateCustomRefresherHeight();
  318 + // #endif
  319 + return showRefresher;
  320 + },
  321 + hasTouchmove(){
  322 + // #ifdef VUE2
  323 + // #ifdef APP-VUE || H5
  324 + if (this.$listeners && !this.$listeners.refresherTouchmove) return false;
  325 + // #endif
  326 + // #ifdef MP-WEIXIN || MP-QQ
  327 + return this.watchRefresherTouchmove;
  328 + // #endif
  329 + return true;
  330 + // #endif
  331 + return this.watchRefresherTouchmove;
  332 + },
  333 + },
  334 + methods: {
  335 + //终止下拉刷新状态
  336 + endRefresh() {
  337 + this.totalData = this.realTotalData;
  338 + this._refresherEnd();
  339 + this._endSystemLoadingAndRefresh();
  340 + this._handleScrollViewDisableBounce({ bounce: true });
  341 + this.$nextTick(() => {
  342 + this.refresherTriggered = false;
  343 + })
  344 + },
  345 + handleRefresherStatusChanged(func) {
  346 + this.refresherStatusChangedFunc = func;
  347 + },
  348 + //手动更新自定义下拉刷新view高度
  349 + updateCustomRefresherHeight() {
  350 + u.delay(() => this.$nextTick(this._updateCustomRefresherHeight));
  351 + },
  352 + //自定义下拉刷新被触发
  353 + _onRefresh(fromScrollView = false,isUserPullDown = true) {
  354 + if (fromScrollView && !(this.finalRefresherEnabled && !this.useCustomRefresher)) return;
  355 + this.$emit('onRefresh');
  356 + this.$emit('Refresh');
  357 + // #ifdef APP-NVUE
  358 + if (this.loading) {
  359 + u.delay(this._nRefresherEnd, 500)
  360 + return;
  361 + }
  362 + // #endif
  363 + if (this.loading || this.isRefresherInComplete) return;
  364 + this.loadingType = Enum.LoadingType.Refresher;
  365 + if (this.nShowRefresherReveal) return;
  366 + this.isUserPullDown = isUserPullDown;
  367 + this.isUserReload = !isUserPullDown;
  368 + this._startLoading(true);
  369 + this.refresherTriggered = true;
  370 + if(this.reloadWhenRefresh && isUserPullDown){
  371 + this.useChatRecordMode ? this._onLoadingMore('click') : this._reload(false, false, isUserPullDown);
  372 + }
  373 + },
  374 + //自定义下拉刷新被复位
  375 + _onRestore() {
  376 + this.refresherTriggered = 'restore';
  377 + this.$emit('onRestore');
  378 + this.$emit('Restore');
  379 + },
  380 + // #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5
  381 + //拖拽开始
  382 + _refresherTouchstart(e) {
  383 + this._handleListTouchstart();
  384 + if (this._touchDisabled()) return;
  385 + this._handleRefresherTouchstart(u.getTouch(e));
  386 + },
  387 + // #endif
  388 + //进一步处理拖拽开始结果
  389 + _handleRefresherTouchstart(touch) {
  390 + if (!this.loading && this.isTouchEnded) {
  391 + this.isTouchmoving = false;
  392 + }
  393 + this.loadingType = Enum.LoadingType.Refresher;
  394 + this.isTouchmovingTimeout && clearTimeout(this.isTouchmovingTimeout);
  395 + this.isTouchEnded = false;
  396 + this.refresherTransition = '';
  397 + this.refresherTouchstartY = touch.touchY;
  398 + this.$emit('refresherTouchstart', this.refresherTouchstartY);
  399 + this.lastRefresherTouchmove = touch;
  400 + this._cleanRefresherCompleteTimeout();
  401 + this._cleanRefresherEndTimeout();
  402 + },
  403 + // #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5
  404 + //拖拽中
  405 + _refresherTouchmove(e) {
  406 + const currentTimeStamp = u.getTime();
  407 + let touch = null;
  408 + let refresherTouchmoveY = 0;
  409 + if (this.watchTouchDirectionChange) {
  410 + touch = u.getTouch(e);
  411 + refresherTouchmoveY = touch.touchY;
  412 + const direction = refresherTouchmoveY > this.oldRefresherTouchmoveY ? 'top' : 'bottom';
  413 + if (direction === this.oldTouchDirection && direction !== this.oldEmitedTouchDirection) {
  414 + this._handleTouchDirectionChange({ direction });
  415 + this.oldEmitedTouchDirection = direction;
  416 + }
  417 + this.oldTouchDirection = direction;
  418 + this.oldRefresherTouchmoveY = refresherTouchmoveY;
  419 + }
  420 + if (this.pullDownTimeStamp && currentTimeStamp - this.pullDownTimeStamp <= this.pullDownDisTimeStamp) return;
  421 + if (this._touchDisabled()) return;
  422 + this.pullDownTimeStamp = Number(currentTimeStamp);
  423 + touch = u.getTouch(e);
  424 + refresherTouchmoveY = touch.touchY;
  425 + let moveDis = refresherTouchmoveY - this.refresherTouchstartY;
  426 + if (moveDis < 0) return;
  427 + if (this.refresherMaxAngle >= 0 && this.refresherMaxAngle <= 90 && this.lastRefresherTouchmove && this.lastRefresherTouchmove.touchY <= refresherTouchmoveY) {
  428 + if (!moveDis && !this.refresherAngleEnableChangeContinued && this.moveDis < 1 && !this.refresherReachMaxAngle) return;
  429 + const x = Math.abs(touch.touchX - this.lastRefresherTouchmove.touchX);
  430 + const y = Math.abs(refresherTouchmoveY - this.lastRefresherTouchmove.touchY);
  431 + const z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
  432 + if ((x || y) && x > 1) {
  433 + const angle = Math.asin(y / z) / Math.PI * 180;
  434 + if (angle < this.refresherMaxAngle) {
  435 + this.lastRefresherTouchmove = touch;
  436 + this.refresherReachMaxAngle = false;
  437 + return;
  438 + }
  439 + }
  440 + }
  441 + moveDis = this._getFinalRefresherMoveDis(moveDis);
  442 + this._handleRefresherTouchmove(moveDis, touch);
  443 + if (!this.disabledBounce) {
  444 + if(this.isIos){
  445 + // #ifndef MP-LARK
  446 + this._handleScrollViewDisableBounce({ bounce: false });
  447 + // #endif
  448 + }
  449 + this.disabledBounce = true;
  450 + }
  451 + this._emitTouchmove({ pullingDistance: moveDis, dy: this.moveDis - this.oldMoveDis });
  452 + },
  453 + // #endif
  454 + //进一步处理拖拽中结果
  455 + _handleRefresherTouchmove(moveDis, touch) {
  456 + this.refresherReachMaxAngle = true;
  457 + this.isTouchmovingTimeout && clearTimeout(this.isTouchmovingTimeout);
  458 + this.isTouchmoving = true;
  459 + this.isTouchEnded = false;
  460 + this.refresherStatus = moveDis >= this.finalRefresherThreshold ? Enum.Refresher.ReleaseToRefresh : this.refresherStatus = Enum.Refresher.Default;
  461 + // #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5
  462 + // this.scrollEnable = false;
  463 + this.refresherTransform = `translateY(${moveDis}px)`;
  464 + this.lastRefresherTouchmove = touch;
  465 + // #endif
  466 + this.moveDis = moveDis;
  467 + },
  468 + // #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5
  469 + //拖拽结束
  470 + _refresherTouchend(e) {
  471 + if (this._touchDisabled() || !this.isTouchmoving) return;
  472 + const touch = u.getTouch(e);
  473 + let refresherTouchendY = touch.touchY;
  474 + let moveDis = refresherTouchendY - this.refresherTouchstartY;
  475 + moveDis = this._getFinalRefresherMoveDis(moveDis);
  476 + this._handleRefresherTouchend(moveDis);
  477 + this._handleScrollViewDisableBounce({bounce: true});
  478 + this.disabledBounce = false;
  479 + },
  480 + // #endif
  481 + //进一步处理拖拽结束结果
  482 + _handleRefresherTouchend(moveDis) {
  483 + // #ifndef APP-PLUS || H5 || MP-WEIXIN
  484 + if (!this.isTouchmoving) return;
  485 + // #endif
  486 + this.isTouchmovingTimeout && clearTimeout(this.isTouchmovingTimeout);
  487 + this.refresherReachMaxAngle = true;
  488 + this.isTouchEnded = true;
  489 + const refresherThreshold = this.finalRefresherThreshold;
  490 + if (moveDis >= refresherThreshold && this.refresherStatus === Enum.Refresher.ReleaseToRefresh) {
  491 + // #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5
  492 + this.refresherTransform = `translateY(${refresherThreshold}px)`;
  493 + this.refresherTransition = 'transform .1s linear';
  494 + // #endif
  495 + u.delay(() => {
  496 + this._emitTouchmove({ pullingDistance: refresherThreshold, dy: this.moveDis - refresherThreshold });
  497 + }, 0.1);
  498 + this.moveDis = refresherThreshold;
  499 + this.refresherStatus = Enum.Refresher.Loading;
  500 + this._doRefresherLoad();
  501 + } else {
  502 + this._refresherEnd();
  503 + this.isTouchmovingTimeout = u.delay(() => {
  504 + this.isTouchmoving = false;
  505 + }, this.refresherDefaultDuration);
  506 + }
  507 + this.scrollEnable = true;
  508 + this.$emit('refresherTouchend', moveDis);
  509 + },
  510 + //处理列表触摸开始事件
  511 + _handleListTouchstart() {
  512 + if (this.useChatRecordMode && this.autoHideKeyboardWhenChat) {
  513 + uni.hideKeyboard();
  514 + this.$emit('hidedKeyboard');
  515 + }
  516 + },
  517 + //处理scroll-view bounce是否生效
  518 + _handleScrollViewDisableBounce({ bounce }) {
  519 + if (!this.usePageScroll && !this.scrollToTopBounceEnabled && this.wxsScrollTop <= 5) {
  520 + // #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5
  521 + this.refresherTransition = '';
  522 + // #endif
  523 + this.scrollEnable = bounce;
  524 + }
  525 + },
  526 + //wxs正在下拉状态改变处理
  527 + _handleWxsPullingDownStatusChange(onPullingDown) {
  528 + this.wxsOnPullingDown = onPullingDown;
  529 + if (onPullingDown && !this.useChatRecordMode) {
  530 + this.renderPropScrollTop = 0;
  531 + }
  532 + },
  533 + //wxs正在下拉处理
  534 + _handleWxsPullingDown({ moveDis, diffDis }){
  535 + this._emitTouchmove({ pullingDistance: moveDis,dy: diffDis });
  536 + },
  537 + //wxs触摸方向改变
  538 + _handleTouchDirectionChange({ direction }) {
  539 + this.$emit('touchDirectionChange',direction);
  540 + },
  541 + //wxs通知更新其props
  542 + _handlePropUpdate(){
  543 + this.wxsPropType = u.getTime().toString();
  544 + },
  545 + //下拉刷新结束
  546 + _refresherEnd(shouldEndLoadingDelay = true, fromAddData = false, isUserPullDown = false, setLoading = true) {
  547 + if (this.loadingType === Enum.LoadingType.Refresher) {
  548 + const refresherCompleteDelay = (fromAddData && (isUserPullDown || this.showRefresherWhenReload)) ? this.refresherCompleteDelay : 0;
  549 + const refresherStatus = refresherCompleteDelay > 0 ? Enum.Refresher.Complete : Enum.Refresher.Default;
  550 + if (this.finalShowRefresherWhenReload) {
  551 + const stackCount = this.refresherRevealStackCount;
  552 + this.refresherRevealStackCount --;
  553 + if (stackCount > 1) return;
  554 + }
  555 + this._cleanRefresherEndTimeout();
  556 + this.refresherEndTimeout = u.delay(() => {
  557 + this.refresherStatus = refresherStatus;
  558 + }, this.refresherStatus !== Enum.Refresher.Default && refresherStatus === Enum.Refresher.Default ? this.refresherCompleteDuration : 0);
  559 +
  560 + // #ifndef APP-NVUE
  561 + if (refresherCompleteDelay > 0) {
  562 + this.isRefresherInComplete = true;
  563 + }
  564 + // #endif
  565 + this._cleanRefresherCompleteTimeout();
  566 + this.refresherCompleteTimeout = u.delay(() => {
  567 + let animateDuration = 1;
  568 + const animateType = this.refresherEndBounceEnabled && fromAddData ? 'cubic-bezier(0.19,1.64,0.42,0.72)' : 'linear';
  569 + if (fromAddData) {
  570 + animateDuration = this.refresherEndBounceEnabled ? this.refresherCompleteDuration / 1000 : this.refresherCompleteDuration / 3000;
  571 + }
  572 + this.refresherTransition = `transform ${fromAddData ? animateDuration : this.refresherDefaultDuration / 1000}s ${animateType}`;
  573 + // #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5
  574 + this.refresherTransform = 'translateY(0px)';
  575 + this.currentDis = 0;
  576 + // #endif
  577 + // #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5
  578 + this.wxsPropType = this.refresherTransition + 'end' + u.getTime();
  579 + // #endif
  580 + // #ifdef APP-NVUE
  581 + this._nRefresherEnd();
  582 + // #endif
  583 + this.moveDis = 0;
  584 + // #ifndef APP-NVUE
  585 + if (refresherStatus === Enum.Refresher.Complete) {
  586 + if (this.refresherCompleteSubTimeout) {
  587 + clearTimeout(this.refresherCompleteSubTimeout);
  588 + this.refresherCompleteSubTimeout = null;
  589 + }
  590 + this.refresherCompleteSubTimeout = u.delay(() => {
  591 + this.$nextTick(() => {
  592 + this.refresherStatus = Enum.Refresher.Default;
  593 + this.isRefresherInComplete = false;
  594 + })
  595 + }, animateDuration * 800);
  596 + }
  597 + // #endif
  598 + this._emitTouchmove({ pullingDistance: 0, dy: this.moveDis });
  599 + }, refresherCompleteDelay);
  600 + }
  601 + if (setLoading) {
  602 + u.delay(() => this.loading = false, shouldEndLoadingDelay ? c.delayTime : 0);
  603 + isUserPullDown && this._onRestore();
  604 + }
  605 + },
  606 + //模拟用户手动触发下拉刷新
  607 + _doRefresherRefreshAnimate() {
  608 + this._cleanRefresherCompleteTimeout();
  609 + // #ifndef APP-NVUE
  610 + const doRefreshAnimateAfter = !this.doRefreshAnimateAfter && (this.finalShowRefresherWhenReload) && this
  611 + .customRefresherHeight === -1 && this.refresherThreshold === '80rpx';
  612 + if (doRefreshAnimateAfter) {
  613 + this.doRefreshAnimateAfter = true;
  614 + return;
  615 + }
  616 + // #endif
  617 + this.refresherRevealStackCount ++;
  618 + // #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5
  619 + this.refresherTransform = `translateY(${this.finalRefresherThreshold}px)`;
  620 + // #endif
  621 + // #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5
  622 + this.wxsPropType = 'begin' + u.getTime();
  623 + // #endif
  624 + this.moveDis = this.finalRefresherThreshold;
  625 + this.refresherStatus = Enum.Refresher.Loading;
  626 + this.isTouchmoving = true;
  627 + this.isTouchmovingTimeout && clearTimeout(this.isTouchmovingTimeout);
  628 + this._doRefresherLoad(false);
  629 + },
  630 + //触发下拉刷新
  631 + _doRefresherLoad(isUserPullDown = true) {
  632 + this._onRefresh(false,isUserPullDown);
  633 + this.loading = true;
  634 + },
  635 + // #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5
  636 + //获取处理后的moveDis
  637 + _getFinalRefresherMoveDis(moveDis) {
  638 + let diffDis = moveDis - this.oldCurrentMoveDis;
  639 + this.oldCurrentMoveDis = moveDis;
  640 + if (diffDis > 0) {
  641 + diffDis = diffDis * this.finalRefresherPullRate;
  642 + if (this.currentDis > this.finalRefresherThreshold) {
  643 + diffDis = diffDis * (1 - this.finalRefresherOutRate);
  644 + }
  645 + }
  646 + diffDis = diffDis > 100 ? diffDis / 100 : diffDis;
  647 + this.currentDis += diffDis;
  648 + this.currentDis = Math.max(0, this.currentDis);
  649 + return this.currentDis;
  650 + },
  651 + //判断touch手势是否要触发
  652 + _touchDisabled() {
  653 + const checkOldScrollTop = this.oldScrollTop > 5;
  654 + return this.loading || this.isRefresherInComplete || this.useChatRecordMode || !this.refresherEnabled || !this.useCustomRefresher ||(this.usePageScroll && this.useCustomRefresher && this.pageScrollTop > 10) || (!(this.usePageScroll && this.useCustomRefresher) && checkOldScrollTop);
  655 + },
  656 + // #endif
  657 + //更新自定义下拉刷新view高度
  658 + _updateCustomRefresherHeight() {
  659 + this._getNodeClientRect('.zp-custom-refresher-slot-view').then((res) => {
  660 + this.customRefresherHeight = res ? res[0].height : 0;
  661 + this.showCustomRefresher = this.customRefresherHeight > 0;
  662 + if (this.doRefreshAnimateAfter) {
  663 + this.doRefreshAnimateAfter = false;
  664 + this._doRefresherRefreshAnimate();
  665 + }
  666 + });
  667 + },
  668 + //发射pullingDown事件
  669 + _emitTouchmove(e) {
  670 + // #ifndef APP-NVUE
  671 + e.viewHeight = this.finalRefresherThreshold;
  672 + // #endif
  673 + e.rate = e.viewHeight > 0 ? e.pullingDistance / e.viewHeight : 0;
  674 + this.hasTouchmove && this.oldPullingDistance !== e.pullingDistance && this.$emit('refresherTouchmove', e);
  675 + this.oldPullingDistance = e.pullingDistance;
  676 + },
  677 + //清除refresherCompleteTimeout
  678 + _cleanRefresherCompleteTimeout() {
  679 + this.refresherCompleteTimeout = this._cleanTimeout(this.refresherCompleteTimeout);
  680 + // #ifdef APP-NVUE
  681 + this._nRefresherEnd(false);
  682 + // #endif
  683 + },
  684 + //清除refresherEndTimeout
  685 + _cleanRefresherEndTimeout() {
  686 + this.refresherEndTimeout = this._cleanTimeout(this.refresherEndTimeout);
  687 + },
  688 + }
  689 +}
garbage-removal/src/components/z-paging/js/modules/scroller.js 0 → 100644
  1 +// [z-paging]scroll相关模块
  2 +import u from '.././z-paging-utils'
  3 +import Enum from '.././z-paging-enum'
  4 +
  5 +// #ifdef APP-NVUE
  6 +const weexDom = weex.requireModule('dom');
  7 +// #endif
  8 +
  9 +export default {
  10 + props: {
  11 + //使用页面滚动,默认为否,当设置为是时则使用页面的滚动而非此组件内部的scroll-view的滚动,使用页面滚动时z-paging无需设置确定的高度且对于长列表展示性能更高,但配置会略微繁琐
  12 + usePageScroll: {
  13 + type: Boolean,
  14 + default: u.gc('usePageScroll', false)
  15 + },
  16 + //是否可以滚动,使用内置scroll-view和nvue时有效,默认为是
  17 + scrollable: {
  18 + type: Boolean,
  19 + default: u.gc('scrollable', true)
  20 + },
  21 + //控制是否出现滚动条,默认为是
  22 + showScrollbar: {
  23 + type: Boolean,
  24 + default: u.gc('showScrollbar', true)
  25 + },
  26 + //是否允许横向滚动,默认为否
  27 + scrollX: {
  28 + type: Boolean,
  29 + default: u.gc('scrollX', false)
  30 + },
  31 + //iOS设备上滚动到顶部时是否允许回弹效果,默认为否。关闭回弹效果后可使滚动到顶部与下拉刷新更连贯,但是有吸顶view时滚动到顶部时可能出现抖动。
  32 + scrollToTopBounceEnabled: {
  33 + type: Boolean,
  34 + default: u.gc('scrollToTopBounceEnabled', false)
  35 + },
  36 + //iOS设备上滚动到底部时是否允许回弹效果,默认为是。
  37 + scrollToBottomBounceEnabled: {
  38 + type: Boolean,
  39 + default: u.gc('scrollToBottomBounceEnabled', true)
  40 + },
  41 + //在设置滚动条位置时使用动画过渡,默认为否
  42 + scrollWithAnimation: {
  43 + type: Boolean,
  44 + default: u.gc('scrollWithAnimation', false)
  45 + },
  46 + //值应为某子元素id(id不能以数字开头)。设置哪个方向可滚动,则在哪个方向滚动到该元素
  47 + scrollIntoView: {
  48 + type: String,
  49 + default: u.gc('scrollIntoView', '')
  50 + },
  51 + },
  52 + data() {
  53 + return {
  54 + scrollTop: 0,
  55 + oldScrollTop: 0,
  56 + scrollViewStyle: {},
  57 + scrollViewContainerStyle: {},
  58 + scrollViewInStyle: {},
  59 + pageScrollTop: -1,
  60 + scrollEnable: true,
  61 + privateScrollWithAnimation: -1,
  62 + cacheScrollNodeHeight: -1
  63 + }
  64 + },
  65 + watch: {
  66 + oldScrollTop(newVal) {
  67 + !this.usePageScroll && this._scrollTopChange(newVal,false);
  68 + },
  69 + pageScrollTop(newVal) {
  70 + this.usePageScroll && this._scrollTopChange(newVal,true);
  71 + },
  72 + usePageScroll: {
  73 + handler(newVal) {
  74 + this.loaded && this.autoHeight && this._setAutoHeight(!newVal);
  75 + // #ifdef H5
  76 + if (newVal) {
  77 + this.$nextTick(() => {
  78 + const mainScrollRef = this.$refs['zp-scroll-view'].$refs.main;
  79 + if (mainScrollRef) {
  80 + mainScrollRef.style = {};
  81 + }
  82 + })
  83 + }
  84 + // #endif
  85 + },
  86 + immediate: true
  87 + },
  88 + finalScrollTop(newVal) {
  89 + if (!this.useChatRecordMode) {
  90 + this.renderPropScrollTop = newVal < 6 ? 0 : 10;
  91 + }
  92 + },
  93 + },
  94 + computed: {
  95 + finalScrollWithAnimation() {
  96 + if (this.privateScrollWithAnimation !== -1) {
  97 + const scrollWithAnimation = this.privateScrollWithAnimation === 1;
  98 + this.privateScrollWithAnimation = -1;
  99 + return scrollWithAnimation;
  100 + }
  101 + return this.scrollWithAnimation;
  102 + },
  103 + finalScrollViewStyle() {
  104 + if (this.superContentZIndex != 1) {
  105 + this.scrollViewStyle['z-index'] = this.superContentZIndex;
  106 + this.scrollViewStyle['position'] = 'relative';
  107 + }
  108 + return this.scrollViewStyle;
  109 + },
  110 + finalScrollTop() {
  111 + return this.usePageScroll ? this.pageScrollTop : this.oldScrollTop;
  112 + },
  113 + finalIsOldWebView() {
  114 + return this.isOldWebView && !this.usePageScroll;
  115 + }
  116 + },
  117 + methods: {
  118 + //滚动到顶部,animate为是否展示滚动动画,默认为是
  119 + scrollToTop(animate, checkReverse = true) {
  120 + // #ifdef APP-NVUE
  121 + if (checkReverse && this.useChatRecordMode) {
  122 + if (!this.nIsFirstPageAndNoMore) {
  123 + this.scrollToBottom(animate, false);
  124 + return;
  125 + }
  126 + }
  127 + // #endif
  128 + this.$nextTick(() => {
  129 + this._scrollToTop(animate, false);
  130 + // #ifdef APP-NVUE
  131 + if (this.nvueFastScroll && animate) {
  132 + u.delay(() => {
  133 + this._scrollToTop(false, false);
  134 + });
  135 + }
  136 + // #endif
  137 + })
  138 + },
  139 + //滚动到底部,animate为是否展示滚动动画,默认为是
  140 + scrollToBottom(animate, checkReverse = true) {
  141 + // #ifdef APP-NVUE
  142 + if (checkReverse && this.useChatRecordMode) {
  143 + if (!this.nIsFirstPageAndNoMore) {
  144 + this.scrollToTop(animate, false);
  145 + return;
  146 + }
  147 + }
  148 + // #endif
  149 + this.$nextTick(() => {
  150 + this._scrollToBottom(animate);
  151 + // #ifdef APP-NVUE
  152 + if (this.nvueFastScroll && animate) {
  153 + u.delay(() => {
  154 + this._scrollToBottom(false);
  155 + });
  156 + }
  157 + // #endif
  158 + })
  159 + },
  160 + //滚动到指定view(vue中有效)。sel为需要滚动的view的id值,不包含"#";offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否
  161 + scrollIntoViewById(sel, offset, animate) {
  162 + this._scrollIntoView(sel, offset, animate);
  163 + },
  164 + //滚动到指定view(vue中有效)。nodeTop为需要滚动的view的top值(通过uni.createSelectorQuery()获取);offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否
  165 + scrollIntoViewByNodeTop(nodeTop, offset, animate) {
  166 + this.scrollTop = this.oldScrollTop;
  167 + this.$nextTick(() => {
  168 + this._scrollIntoViewByNodeTop(nodeTop, offset, animate);
  169 + })
  170 + },
  171 + //滚动到指定位置(vue中有效)。y为与顶部的距离,单位为px;offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否
  172 + scrollToY(y, offset, animate) {
  173 + this.scrollTop = this.oldScrollTop;
  174 + this.$nextTick(() => {
  175 + this._scrollToY(y, offset, animate);
  176 + })
  177 + },
  178 + //滚动到指定view(nvue中有效)。index为需要滚动的view的index(第几个);offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否
  179 + scrollIntoViewByIndex(index, offset, animate) {
  180 + this._scrollIntoView(index, offset, animate);
  181 + },
  182 + //滚动到指定view(nvue中有效)。view为需要滚动的view(通过`this.$refs.xxx`获取),不包含"#";offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否
  183 + scrollIntoViewByView(view, offset, animate) {
  184 + this._scrollIntoView(view, offset, animate);
  185 + },
  186 + //当使用页面滚动并且自定义下拉刷新时,请在页面的onPageScroll中调用此方法,告知z-paging当前的pageScrollTop,否则会导致在任意位置都可以下拉刷新
  187 + updatePageScrollTop(value) {
  188 + this.pageScrollTop = value;
  189 + },
  190 + //当使用页面滚动并且设置了slot="top"时,默认初次加载会自动获取其高度,并使内部容器下移,当slot="top"的view高度动态改变时,在其高度需要更新时调用此方法
  191 + updatePageScrollTopHeight() {
  192 + this._updatePageScrollTopOrBottomHeight('top');
  193 + },
  194 + //当使用页面滚动并且设置了slot="bottom"时,默认初次加载会自动获取其高度,并使内部容器下移,当slot="bottom"的view高度动态改变时,在其高度需要更新时调用此方法
  195 + updatePageScrollBottomHeight() {
  196 + this._updatePageScrollTopOrBottomHeight('bottom');
  197 + },
  198 + //更新slot="left"和slot="right"宽度,当slot="left"或slot="right"宽度动态改变时调用
  199 + updateLeftAndRightWidth() {
  200 + if (!this.finalIsOldWebView) return;
  201 + this.$nextTick(() => this._updateLeftAndRightWidth(this.scrollViewContainerStyle, 'zp-page'));
  202 + },
  203 + //更新z-paging内置scroll-view的scrollTop
  204 + updateScrollViewScrollTop(scrollTop, animate = true) {
  205 + this.privateScrollWithAnimation = animate ? 1 : 0;
  206 + this.scrollTop = this.oldScrollTop;
  207 + this.$nextTick(() => {
  208 + this.scrollTop = scrollTop;
  209 + this.oldScrollTop = this.scrollTop;
  210 + });
  211 + },
  212 +
  213 + //当滚动到顶部时
  214 + _onScrollToUpper() {
  215 + this.$emit('scrolltoupper');
  216 + this.$emit('scrollTopChange', 0);
  217 + this.$nextTick(() => {
  218 + this.oldScrollTop = 0;
  219 + })
  220 + this.useChatRecordMode && this.loadingStatus !== Enum.More.NoMore && this._onLoadingMore('click');
  221 + },
  222 + //当滚动到底部时
  223 + _onScrollToLower(e) {
  224 + (!e.detail || !e.detail.direction || e.detail.direction === 'bottom') && this._onLoadingMore('toBottom')
  225 + },
  226 + //滚动到顶部
  227 + _scrollToTop(animate = true, isPrivate = true) {
  228 + // #ifdef APP-NVUE
  229 + const el = this.$refs['zp-n-list-top-tag'];
  230 + if (this.usePageScroll) {
  231 + this._getNodeClientRect('zp-page-scroll-top', false).then(node => {
  232 + const nodeHeight = node ? node[0].height : 0;
  233 + weexDom.scrollToElement(el, {
  234 + offset: -nodeHeight,
  235 + animated: animate
  236 + });
  237 + });
  238 + } else {
  239 + if (!this.isIos && this.nvueListIs === 'scroller') {
  240 + this._getNodeClientRect('zp-n-refresh-container', false).then(node => {
  241 + const nodeHeight = node ? node[0].height : 0;
  242 + weexDom.scrollToElement(el, {
  243 + offset: -nodeHeight,
  244 + animated: animate
  245 + });
  246 + });
  247 + } else {
  248 + weexDom.scrollToElement(el, {
  249 + offset: 0,
  250 + animated: animate
  251 + });
  252 + }
  253 + }
  254 + return;
  255 + // #endif
  256 + if (this.usePageScroll) {
  257 + this.$nextTick(() => {
  258 + uni.pageScrollTo({
  259 + scrollTop: 0,
  260 + duration: animate ? 100 : 0,
  261 + });
  262 + });
  263 + return;
  264 + }
  265 + this.privateScrollWithAnimation = animate ? 1 : 0;
  266 + this.scrollTop = this.oldScrollTop;
  267 + this.$nextTick(() => {
  268 + this.scrollTop = 0;
  269 + this.oldScrollTop = this.scrollTop;
  270 + });
  271 + },
  272 + //滚动到底部
  273 + async _scrollToBottom(animate = true) {
  274 + // #ifdef APP-NVUE
  275 + const el = this.$refs['zp-n-list-bottom-tag'];
  276 + if (el) {
  277 + weexDom.scrollToElement(el, {
  278 + offset: 0,
  279 + animated: animate
  280 + });
  281 + } else {
  282 + u.consoleErr('滚动到底部失败,因为您设置了hideNvueBottomTag为true');
  283 + }
  284 + return;
  285 + // #endif
  286 + if (this.usePageScroll) {
  287 + this.$nextTick(() => {
  288 + uni.pageScrollTo({
  289 + scrollTop: Number.MAX_VALUE,
  290 + duration: animate ? 100 : 0,
  291 + });
  292 + });
  293 + return;
  294 + }
  295 + try {
  296 + this.privateScrollWithAnimation = animate ? 1 : 0;
  297 + const pagingContainerNode = await this._getNodeClientRect('.zp-paging-container');
  298 + const scrollViewNode = await this._getNodeClientRect('.zp-scroll-view');
  299 + const pagingContainerH = pagingContainerNode ? pagingContainerNode[0].height : 0;
  300 + const scrollViewH = scrollViewNode ? scrollViewNode[0].height : 0;
  301 + if (pagingContainerH > scrollViewH) {
  302 + this.scrollTop = this.oldScrollTop;
  303 + this.$nextTick(() => {
  304 + this.scrollTop = pagingContainerH - scrollViewH + this.virtualPlaceholderTopHeight;
  305 + this.oldScrollTop = this.scrollTop;
  306 + });
  307 + }
  308 + } catch (e) {}
  309 + },
  310 + //滚动到指定view
  311 + _scrollIntoView(sel, offset = 0, animate = false, finishCallback) {
  312 + try {
  313 + this.scrollTop = this.oldScrollTop;
  314 + this.$nextTick(() => {
  315 + // #ifdef APP-NVUE
  316 + const refs = this.$parent.$refs;
  317 + if (!refs) return;
  318 + const dataType = Object.prototype.toString.call(sel);
  319 + let el = null;
  320 + if (dataType === '[object Number]') {
  321 + const els = refs[`z-paging-${sel}`];
  322 + el = els ? els[0] : null;
  323 + } else if (dataType === '[object Array]') {
  324 + el = sel[0];
  325 + } else {
  326 + el = sel;
  327 + }
  328 + if (el) {
  329 + weexDom.scrollToElement(el, {
  330 + offset: -offset,
  331 + animated: animate
  332 + });
  333 + } else {
  334 + u.consoleErr('在nvue中滚动到指定位置,cell必须设置 :ref="`z-paging-${index}`"');
  335 + }
  336 + return;
  337 + // #endif
  338 + this._getNodeClientRect('#' + sel.replace('#', ''), this.$parent).then((node) => {
  339 + if (node) {
  340 + let nodeTop = node[0].top;
  341 + this._scrollIntoViewByNodeTop(nodeTop, offset, animate);
  342 + finishCallback && finishCallback();
  343 + }
  344 + });
  345 + });
  346 + } catch (e) {}
  347 + },
  348 + //通过nodeTop滚动到指定view
  349 + _scrollIntoViewByNodeTop(nodeTop, offset = 0, animate = false) {
  350 + this._scrollToY(nodeTop, offset, animate, true);
  351 + },
  352 + //滚动到指定位置
  353 + _scrollToY(y, offset = 0, animate = false, addScrollTop = false) {
  354 + this.privateScrollWithAnimation = animate ? 1 : 0;
  355 + if (this.usePageScroll) {
  356 + uni.pageScrollTo({
  357 + scrollTop: y - offset,
  358 + duration: animate ? 100 : 0
  359 + });
  360 + } else {
  361 + if(addScrollTop){
  362 + y += this.oldScrollTop;
  363 + }
  364 + this.scrollTop = y - offset;
  365 + this.oldScrollTop = this.scrollTop;
  366 + }
  367 + },
  368 + //scroll-view滚动中
  369 + _scroll(e) {
  370 + this.$emit('scroll', e);
  371 + const scrollTop = e.detail.scrollTop;
  372 + // #ifndef APP-NVUE
  373 + this.finalUseVirtualList && this._updateVirtualScroll(scrollTop, this.oldScrollTop - scrollTop);
  374 + // #endif
  375 + this.oldScrollTop = scrollTop;
  376 + const scrollDiff = e.detail.scrollHeight - this.oldScrollTop;
  377 + !this.isIos && this._checkScrolledToBottom(scrollDiff);
  378 + },
  379 + //检测scrollView是否要铺满屏幕
  380 + _doCheckScrollViewShouldFullHeight(totalData) {
  381 + if (this.autoFullHeight && this.usePageScroll && this.isTotalChangeFromAddData) {
  382 + // #ifndef APP-NVUE
  383 + this.$nextTick(() => {
  384 + this._checkScrollViewShouldFullHeight((scrollViewNode, pagingContainerNode) => {
  385 + this._preCheckShowNoMoreInside(totalData, scrollViewNode, pagingContainerNode)
  386 + });
  387 + })
  388 + // #endif
  389 + // #ifdef APP-NVUE
  390 + this._preCheckShowNoMoreInside(totalData)
  391 + // #endif
  392 + } else {
  393 + this._preCheckShowNoMoreInside(totalData)
  394 + }
  395 + },
  396 + //检测z-paging是否要全屏覆盖(当使用页面滚动并且不满全屏时,默认z-paging需要铺满全屏,避免数据过少时内部的empty-view无法正确展示)
  397 + async _checkScrollViewShouldFullHeight(callback) {
  398 + try {
  399 + const scrollViewNode = await this._getNodeClientRect('.zp-scroll-view');
  400 + const pagingContainerNode = await this._getNodeClientRect('.zp-paging-container-content');
  401 + if (!scrollViewNode || !pagingContainerNode) return;
  402 + const scrollViewHeight = pagingContainerNode[0].height;
  403 + const scrollViewTop = scrollViewNode[0].top;
  404 + if (this.isAddedData && scrollViewHeight + scrollViewTop <= this.windowHeight) {
  405 + this._setAutoHeight(true, scrollViewNode);
  406 + callback(scrollViewNode, pagingContainerNode);
  407 + } else {
  408 + this._setAutoHeight(false);
  409 + callback(null, null);
  410 + }
  411 + } catch (e) {
  412 + callback(null, null);
  413 + }
  414 + },
  415 + //scrollTop改变时触发
  416 + _scrollTopChange(newVal, isPageScrollTop){
  417 + this.$emit('scrollTopChange', newVal);
  418 + this.$emit('update:scrollTop', newVal);
  419 + this._checkShouldShowBackToTop(newVal);
  420 + const scrollTop = this.isIos ? (newVal > 5 ? 6 : 0) : (newVal > 105 ? 106 : (newVal > 5 ? 6 : 0));
  421 + if (isPageScrollTop && this.wxsPageScrollTop !== scrollTop) {
  422 + this.wxsPageScrollTop = scrollTop;
  423 + } else if (!isPageScrollTop && this.wxsScrollTop !== scrollTop) {
  424 + this.wxsScrollTop = scrollTop;
  425 + if (scrollTop > 6) {
  426 + this.scrollEnable = true;
  427 + }
  428 + }
  429 + },
  430 + //更新使用页面滚动时slot="top"或"bottom"插入view的高度
  431 + _updatePageScrollTopOrBottomHeight(type) {
  432 + // #ifndef APP-NVUE
  433 + if (!this.usePageScroll) return;
  434 + // #endif
  435 + this._doCheckScrollViewShouldFullHeight(this.realTotalData);
  436 + const node = `.zp-page-${type}`;
  437 + const marginText = `margin${type.slice(0,1).toUpperCase() + type.slice(1)}`;
  438 + let safeAreaInsetBottomAdd = this.safeAreaInsetBottom;
  439 + this.$nextTick(() => {
  440 + let delayTime = 0;
  441 + // #ifdef MP-BAIDU || APP-NVUE
  442 + delayTime = 50;
  443 + // #endif
  444 + u.delay(() => {
  445 + this._getNodeClientRect(node).then((res) => {
  446 + if (res) {
  447 + let pageScrollNodeHeight = res[0].height;
  448 + if (type === 'bottom') {
  449 + if (safeAreaInsetBottomAdd) {
  450 + pageScrollNodeHeight += this.safeAreaBottom;
  451 + }
  452 + } else {
  453 + this.cacheTopHeight = pageScrollNodeHeight;
  454 + }
  455 + this.$set(this.scrollViewStyle, marginText, `${pageScrollNodeHeight}px`);
  456 + } else if (safeAreaInsetBottomAdd) {
  457 + this.$set(this.scrollViewStyle, marginText, `${this.safeAreaBottom}px`);
  458 + }
  459 + });
  460 + }, delayTime)
  461 + })
  462 + },
  463 + }
  464 +}
garbage-removal/src/components/z-paging/js/modules/virtual-list.js 0 → 100644
  1 +// [z-paging]虚拟列表模块
  2 +import u from '.././z-paging-utils'
  3 +import c from '.././z-paging-constant'
  4 +import Enum from '.././z-paging-enum'
  5 +
  6 +export default {
  7 + props: {
  8 + //是否使用虚拟列表,默认为否
  9 + useVirtualList: {
  10 + type: Boolean,
  11 + default: u.gc('useVirtualList', false)
  12 + },
  13 + //在使用虚拟列表时,是否使用兼容模式,默认为否
  14 + useCompatibilityMode: {
  15 + type: Boolean,
  16 + default: u.gc('useCompatibilityMode', false)
  17 + },
  18 + //使用兼容模式时传递的附加数据
  19 + extraData: {
  20 + type: Object,
  21 + default: function() {
  22 + return u.gc('extraData', {});
  23 + }
  24 + },
  25 + //是否在z-paging内部循环渲染列表(内置列表),默认为否。若use-virtual-list为true,则此项恒为true
  26 + useInnerList: {
  27 + type: Boolean,
  28 + default: u.gc('useInnerList', false)
  29 + },
  30 + //强制关闭inner-list,默认为false,如果为true将强制关闭innerList,适用于开启了虚拟列表后需要强制关闭inner-list的情况
  31 + forceCloseInnerList: {
  32 + type: Boolean,
  33 + default: u.gc('forceCloseInnerList', false)
  34 + },
  35 + //内置列表cell的key名称,仅nvue有效,在nvue中开启use-inner-list时必须填此项
  36 + cellKeyName: {
  37 + type: String,
  38 + default: u.gc('cellKeyName', '')
  39 + },
  40 + //innerList样式
  41 + innerListStyle: {
  42 + type: Object,
  43 + default: function() {
  44 + return u.gc('innerListStyle', {});
  45 + }
  46 + },
  47 + //innerCell样式
  48 + innerCellStyle: {
  49 + type: Object,
  50 + default: function() {
  51 + return u.gc('innerCellStyle', {});
  52 + }
  53 + },
  54 + //预加载的列表可视范围(列表高度)页数,默认为12,即预加载当前页及上下各12页的cell。此数值越大,则虚拟列表中加载的dom越多,内存消耗越大(会维持在一个稳定值),但增加预加载页面数量可缓解快速滚动短暂白屏问题
  55 + preloadPage: {
  56 + type: [Number, String],
  57 + default: u.gc('preloadPage', 12),
  58 + validator: (value) => {
  59 + if (value <= 0) u.consoleErr('preload-page必须大于0!');
  60 + return value > 0;
  61 + }
  62 + },
  63 + //虚拟列表cell高度模式,默认为fixed,也就是每个cell高度完全相同,将以第一个cell高度为准进行计算。可选值【dynamic】,即代表高度是动态非固定的,【dynamic】性能低于【fixed】。
  64 + cellHeightMode: {
  65 + type: String,
  66 + default: u.gc('cellHeightMode', Enum.CellHeightMode.Fixed)
  67 + },
  68 + //虚拟列表列数,默认为1。常用于每行有多列的情况,例如每行有2列数据,需要将此值设置为2
  69 + virtualListCol: {
  70 + type: [Number, String],
  71 + default: u.gc('virtualListCol', 1)
  72 + },
  73 + //虚拟列表scroll取样帧率,默认为80,过低容易出现白屏问题,过高容易出现卡顿问题
  74 + virtualScrollFps: {
  75 + type: [Number, String],
  76 + default: u.gc('virtualScrollFps', 80)
  77 + },
  78 + },
  79 + data() {
  80 + return {
  81 + virtualListKey: u.getInstanceId(),
  82 + virtualPageHeight: 0,
  83 + virtualCellHeight: 0,
  84 + virtualScrollTimeStamp: 0,
  85 +
  86 + virtualList: [],
  87 + virtualPlaceholderTopHeight: 0,
  88 + virtualPlaceholderBottomHeight: 0,
  89 + virtualTopRangeIndex: 0,
  90 + virtualBottomRangeIndex: 0,
  91 + lastVirtualTopRangeIndex: 0,
  92 + lastVirtualBottomRangeIndex: 0,
  93 + virtualItemInsertedCount: 0,
  94 +
  95 + virtualHeightCacheList: [],
  96 +
  97 + getCellHeightRetryCount: {
  98 + fixed: 0,
  99 + dynamic: 0
  100 + },
  101 + pagingOrgTop: -1,
  102 + updateVirtualListFromDataChange: false
  103 + }
  104 + },
  105 + watch: {
  106 + realTotalData(newVal) {
  107 + // #ifndef APP-NVUE
  108 + if (this.finalUseVirtualList) {
  109 + this.updateVirtualListFromDataChange = true;
  110 + this.$nextTick(() => {
  111 + this.getCellHeightRetryCount.fixed = 0;
  112 + !newVal.length && this._resetDynamicListState(!this.isUserPullDown);
  113 + newVal.length && this.cellHeightMode === Enum.CellHeightMode.Fixed && this.isFirstPage && this._updateFixedCellHeight();
  114 + this._updateVirtualScroll(this.oldScrollTop);
  115 + })
  116 + }
  117 + // #endif
  118 + },
  119 + virtualList(newVal){
  120 + this.$emit('update:virtualList', newVal);
  121 + this.$emit('virtualListChange', newVal);
  122 + }
  123 + },
  124 + computed: {
  125 + virtualCellIndexKey() {
  126 + return c.listCellIndexKey;
  127 + },
  128 + finalUseVirtualList() {
  129 + if (this.useVirtualList && this.usePageScroll){
  130 + u.consoleErr('使用页面滚动时,开启虚拟列表无效!');
  131 + }
  132 + return this.useVirtualList && !this.usePageScroll;
  133 + },
  134 + finalUseInnerList() {
  135 + return this.useInnerList || (this.finalUseVirtualList && !this.forceCloseInnerList);
  136 + },
  137 + finalCellKeyName() {
  138 + // #ifdef APP-NVUE
  139 + if (this.finalUseVirtualList && !this.cellKeyName.length){
  140 + u.consoleErr('在nvue中开启use-virtual-list必须设置cell-key-name,否则将可能导致列表渲染错误!');
  141 + }
  142 + // #endif
  143 + return this.cellKeyName;
  144 + },
  145 + finalVirtualPageHeight(){
  146 + return this.virtualPageHeight > 0 ? this.virtualPageHeight : this.windowHeight;
  147 + },
  148 + virtualRangePageHeight(){
  149 + return this.finalVirtualPageHeight * this.preloadPage;
  150 + },
  151 + virtualScrollDisTimeStamp() {
  152 + return 1000 / this.virtualScrollFps;
  153 + },
  154 + },
  155 + methods: {
  156 + //在使用动态高度虚拟列表时,若在列表数组中需要插入某个item,需要调用此方法;item:需要插入的item,index:插入的cell位置,若index为2,则插入的item在原list的index=1之后,index从0开始
  157 + doInsertVirtualListItem(item, index) {
  158 + if (this.cellHeightMode !== Enum.CellHeightMode.Dynamic) return;
  159 + this.virtualItemInsertedCount ++;
  160 + if (!item || Object.prototype.toString.call(item) !== '[object Object]') {
  161 + item = { item };
  162 + }
  163 + const cellIndexKey = this.virtualCellIndexKey;
  164 + item[cellIndexKey] = `custom-${this.virtualItemInsertedCount}`;
  165 + item[c.listCellIndexUniqueKey] = `${this.virtualListKey}-${item[cellIndexKey]}`;
  166 + this.totalData.splice(index, 0, item);
  167 + this.$nextTick(async () => {
  168 + let retryCount = 0;
  169 + while (retryCount <= 10) {
  170 + await u.wait(c.delayTime);
  171 +
  172 + const cellNode = await this._getNodeClientRect(`#zp-id-${item[cellIndexKey]}`, this.finalUseInnerList);
  173 + if (!cellNode) {
  174 + retryCount ++;
  175 + continue;
  176 + }
  177 +
  178 + const currentHeight = cellNode ? cellNode[0].height : 0;
  179 + const lastHeightCache = this.virtualHeightCacheList[index - 1];
  180 + const lastTotalHeight = lastHeightCache ? lastHeightCache.totalHeight : 0;
  181 + this.virtualHeightCacheList.splice(index, 0, {
  182 + height: currentHeight,
  183 + lastTotalHeight,
  184 + totalHeight: lastTotalHeight + currentHeight
  185 + });
  186 +
  187 + for (let i = index + 1; i < this.virtualHeightCacheList.length; i++) {
  188 + const thisNode = this.virtualHeightCacheList[i];
  189 + thisNode.lastTotalHeight += currentHeight;
  190 + thisNode.totalHeight += currentHeight;
  191 + }
  192 +
  193 + this._updateVirtualScroll(this.oldScrollTop);
  194 + break;
  195 + }
  196 + })
  197 + },
  198 + //在使用动态高度虚拟列表时,手动更新指定cell的缓存高度(当cell高度在初始化之后再次改变时调用);index:需要更新的cell在列表中的位置,从0开始
  199 + didUpdateVirtualListCell(index) {
  200 + if (this.cellHeightMode !== Enum.CellHeightMode.Dynamic) return;
  201 + const currentNode = this.virtualHeightCacheList[index];
  202 + this.$nextTick(() => {
  203 + this._getNodeClientRect(`#zp-id-${index}`, this.finalUseInnerList).then(cellNode => {
  204 + const cellNodeHeight = cellNode ? cellNode[0].height : 0;
  205 + const heightDis = cellNodeHeight - currentNode.height;
  206 + currentNode.height = cellNodeHeight;
  207 + currentNode.totalHeight = currentNode.lastTotalHeight + cellNodeHeight;
  208 +
  209 + for (let i = index + 1; i < this.virtualHeightCacheList.length; i++) {
  210 + const thisNode = this.virtualHeightCacheList[i];
  211 + thisNode.totalHeight += heightDis;
  212 + thisNode.lastTotalHeight += heightDis;
  213 + }
  214 + });
  215 + })
  216 + },
  217 + //在使用动态高度虚拟列表时,若删除了列表数组中的某个item,需要调用此方法以更新高度缓存数组;index:删除的cell在列表中的位置,从0开始
  218 + didDeleteVirtualListCell(index) {
  219 + if (this.cellHeightMode !== Enum.CellHeightMode.Dynamic) return;
  220 + const currentNode = this.virtualHeightCacheList[index];
  221 + for (let i = index + 1; i < this.virtualHeightCacheList.length; i++) {
  222 + const thisNode = this.virtualHeightCacheList[i];
  223 + thisNode.totalHeight -= currentNode.height;
  224 + thisNode.lastTotalHeight -= currentNode.height;
  225 + }
  226 + this.virtualHeightCacheList.splice(index, 1);
  227 + },
  228 + //初始化虚拟列表
  229 + _virtualListInit() {
  230 + this.$nextTick(() => {
  231 + u.delay(() => {
  232 + this._getNodeClientRect('.zp-scroll-view').then(node => {
  233 + if (node) {
  234 + this.pagingOrgTop = node[0].top;
  235 + this.virtualPageHeight = node[0].height;
  236 + }
  237 + });
  238 + });
  239 + })
  240 + },
  241 + //cellHeightMode为fixed时获取第一个cell高度
  242 + _updateFixedCellHeight() {
  243 + this.$nextTick(() => {
  244 + u.delay(() => {
  245 + this._getNodeClientRect(`#zp-id-${0}`,this.finalUseInnerList).then(cellNode => {
  246 + if (!cellNode) {
  247 + if (this.getCellHeightRetryCount.fixed > 10) return;
  248 + this.getCellHeightRetryCount.fixed ++;
  249 + this._updateFixedCellHeight();
  250 + } else {
  251 + this.virtualCellHeight = cellNode[0].height;
  252 + this._updateVirtualScroll(this.oldScrollTop);
  253 + }
  254 + });
  255 + }, c.delayTime, 'updateFixedCellHeightDelay');
  256 + })
  257 + },
  258 + //cellHeightMode为dynamic时获取每个cell高度
  259 + _updateDynamicCellHeight(list, dataFrom = 'bottom') {
  260 + const dataFromTop = dataFrom === 'top';
  261 + const heightCacheList = this.virtualHeightCacheList;
  262 + const currentCacheList = dataFromTop ? [] : heightCacheList;
  263 + let listTotalHeight = 0;
  264 + this.$nextTick(() => {
  265 + u.delay(async () => {
  266 + for (let i = 0; i < list.length; i++) {
  267 + const cellNode = await this._getNodeClientRect(`#zp-id-${list[i][this.virtualCellIndexKey]}`, this.finalUseInnerList);
  268 + const currentHeight = cellNode ? cellNode[0].height : 0;
  269 + if (!cellNode) {
  270 + if (this.getCellHeightRetryCount.dynamic <= 10) {
  271 + heightCacheList.splice(heightCacheList.length - i, i);
  272 + this.getCellHeightRetryCount.dynamic ++;
  273 + this._updateDynamicCellHeight(list, dataFrom);
  274 + }
  275 + return;
  276 + }
  277 + const lastHeightCache = currentCacheList.length ? currentCacheList.slice(-1)[0] : null;
  278 + const lastTotalHeight = lastHeightCache ? lastHeightCache.totalHeight : 0;
  279 + currentCacheList.push({
  280 + height: currentHeight,
  281 + lastTotalHeight,
  282 + totalHeight: lastTotalHeight + currentHeight
  283 + });
  284 + if (dataFromTop) {
  285 + listTotalHeight += currentHeight;
  286 + }
  287 + }
  288 + if (dataFromTop && list.length) {
  289 + for (let i = 0; i < heightCacheList.length; i++) {
  290 + const heightCacheItem = heightCacheList[i];
  291 + heightCacheItem.lastTotalHeight += listTotalHeight;
  292 + heightCacheItem.totalHeight += listTotalHeight;
  293 + }
  294 + this.virtualHeightCacheList = currentCacheList.concat(heightCacheList);
  295 + }
  296 + this._updateVirtualScroll(this.oldScrollTop);
  297 + }, c.delayTime, 'updateDynamicCellHeightDelay')
  298 + })
  299 + },
  300 + //设置cellItem的index
  301 + _setCellIndex(list, dataFrom = 'bottom') {
  302 + let currentItemIndex = 0;
  303 + const cellIndexKey = this.virtualCellIndexKey;
  304 + if (this.totalData.length) {
  305 + if (dataFrom === 'bottom') {
  306 + currentItemIndex = this.realTotalData.length;
  307 + const lastItem = this.realTotalData.length ? this.realTotalData.slice(-1)[0] : null;
  308 + if (lastItem && lastItem[cellIndexKey] !== undefined) {
  309 + currentItemIndex = lastItem[cellIndexKey] + 1;
  310 + }
  311 + } else if (dataFrom === 'top') {
  312 + const firstItem = this.realTotalData.length ? this.realTotalData[0] : null;
  313 + if (firstItem && firstItem[cellIndexKey] !== undefined) {
  314 + currentItemIndex = firstItem[cellIndexKey] - list.length;
  315 + }
  316 + }
  317 + } else {
  318 + this._resetDynamicListState();
  319 + }
  320 + for (let i = 0; i < list.length; i++) {
  321 + let item = list[i];
  322 + if (!item || Object.prototype.toString.call(item) !== '[object Object]') {
  323 + item = { item };
  324 + }
  325 + item[cellIndexKey] = currentItemIndex + i;
  326 + item[c.listCellIndexUniqueKey] = `${this.virtualListKey}-${item[cellIndexKey]}`;
  327 + list[i] = item;
  328 + }
  329 + this.getCellHeightRetryCount.dynamic = 0;
  330 + this.cellHeightMode === Enum.CellHeightMode.Dynamic && this._updateDynamicCellHeight(list, dataFrom);
  331 + },
  332 + //更新scroll滚动
  333 + _updateVirtualScroll(scrollTop, scrollDiff = 0) {
  334 + const currentTimeStamp = u.getTime();
  335 + scrollTop === 0 && this._resetTopRange();
  336 + if (scrollTop !== 0 && this.virtualScrollTimeStamp && currentTimeStamp - this.virtualScrollTimeStamp <= this.virtualScrollDisTimeStamp) {
  337 + return;
  338 + }
  339 + this.virtualScrollTimeStamp = currentTimeStamp;
  340 +
  341 + let scrollIndex = 0;
  342 + const cellHeightMode = this.cellHeightMode;
  343 + if (cellHeightMode === Enum.CellHeightMode.Fixed) {
  344 + scrollIndex = parseInt(scrollTop / this.virtualCellHeight) || 0;
  345 + this._updateFixedTopRangeIndex(scrollIndex);
  346 + this._updateFixedBottomRangeIndex(scrollIndex);
  347 + } else if(cellHeightMode === Enum.CellHeightMode.Dynamic) {
  348 + const scrollDirection = scrollDiff > 0 ? 'top' : 'bottom';
  349 + const rangePageHeight = this.virtualRangePageHeight;
  350 + const topRangePageOffset = scrollTop - rangePageHeight;
  351 + const bottomRangePageOffset = scrollTop + this.finalVirtualPageHeight + rangePageHeight;
  352 +
  353 + let virtualBottomRangeIndex = 0;
  354 + let virtualPlaceholderBottomHeight = 0;
  355 + let reachedLimitBottom = false;
  356 + const heightCacheList = this.virtualHeightCacheList;
  357 + const lastHeightCache = !!heightCacheList ? heightCacheList.slice(-1)[0] : null;
  358 +
  359 + let startTopRangeIndex = this.virtualTopRangeIndex;
  360 + if (scrollDirection === 'bottom') {
  361 + for (let i = startTopRangeIndex; i < heightCacheList.length; i++){
  362 + const heightCacheItem = heightCacheList[i];
  363 + if (heightCacheItem && heightCacheItem.totalHeight > topRangePageOffset) {
  364 + this.virtualTopRangeIndex = i;
  365 + this.virtualPlaceholderTopHeight = heightCacheItem.lastTotalHeight;
  366 + break;
  367 + }
  368 + }
  369 + } else {
  370 + let topRangeMatched = false;
  371 + for (let i = startTopRangeIndex; i >= 0; i--){
  372 + const heightCacheItem = heightCacheList[i];
  373 + if (heightCacheItem && heightCacheItem.totalHeight < topRangePageOffset) {
  374 + this.virtualTopRangeIndex = i;
  375 + this.virtualPlaceholderTopHeight = heightCacheItem.lastTotalHeight;
  376 + topRangeMatched = true;
  377 + break;
  378 + }
  379 + }
  380 + !topRangeMatched && this._resetTopRange();
  381 + }
  382 + for (let i = this.virtualTopRangeIndex; i < heightCacheList.length; i++){
  383 + const heightCacheItem = heightCacheList[i];
  384 + if (heightCacheItem && heightCacheItem.totalHeight > bottomRangePageOffset) {
  385 + virtualBottomRangeIndex = i;
  386 + virtualPlaceholderBottomHeight = lastHeightCache.totalHeight - heightCacheItem.totalHeight;
  387 + reachedLimitBottom = true;
  388 + break;
  389 + }
  390 + }
  391 + if (!reachedLimitBottom || this.virtualBottomRangeIndex === 0) {
  392 + this.virtualBottomRangeIndex = this.realTotalData.length ? this.realTotalData.length - 1 : this.pageSize;
  393 + this.virtualPlaceholderBottomHeight = 0;
  394 + } else {
  395 + this.virtualBottomRangeIndex = virtualBottomRangeIndex;
  396 + this.virtualPlaceholderBottomHeight = virtualPlaceholderBottomHeight;
  397 + }
  398 + this._updateVirtualList();
  399 + }
  400 + },
  401 + //更新fixedCell模式下topRangeIndex&placeholderTopHeight
  402 + _updateFixedTopRangeIndex(scrollIndex) {
  403 + let virtualTopRangeIndex = this.virtualCellHeight === 0 ? 0 : scrollIndex - (parseInt(this.finalVirtualPageHeight / this.virtualCellHeight) || 1) * this.preloadPage;
  404 + virtualTopRangeIndex *= this.virtualListCol;
  405 + virtualTopRangeIndex = Math.max(0, virtualTopRangeIndex);
  406 + this.virtualTopRangeIndex = virtualTopRangeIndex;
  407 + this.virtualPlaceholderTopHeight = (virtualTopRangeIndex / this.virtualListCol) * this.virtualCellHeight;
  408 + },
  409 + //更新fixedCell模式下bottomRangeIndex&placeholderBottomHeight
  410 + _updateFixedBottomRangeIndex(scrollIndex) {
  411 + let virtualBottomRangeIndex = this.virtualCellHeight === 0 ? this.pageSize : scrollIndex + (parseInt(this.finalVirtualPageHeight / this.virtualCellHeight) || 1) * (this.preloadPage + 1);
  412 + virtualBottomRangeIndex *= this.virtualListCol;
  413 + virtualBottomRangeIndex = Math.min(this.realTotalData.length, virtualBottomRangeIndex);
  414 + this.virtualBottomRangeIndex = virtualBottomRangeIndex;
  415 + this.virtualPlaceholderBottomHeight = (this.realTotalData.length - virtualBottomRangeIndex) * this.virtualCellHeight / this.virtualListCol;
  416 + this._updateVirtualList();
  417 + },
  418 + //更新virtualList
  419 + _updateVirtualList() {
  420 + const shouldUpdateList = this.updateVirtualListFromDataChange || (this.lastVirtualTopRangeIndex !== this.virtualTopRangeIndex || this.lastVirtualBottomRangeIndex !== this.virtualBottomRangeIndex);
  421 + if (shouldUpdateList) {
  422 + this.updateVirtualListFromDataChange = false;
  423 + this.lastVirtualTopRangeIndex = this.virtualTopRangeIndex;
  424 + this.lastVirtualBottomRangeIndex = this.virtualBottomRangeIndex;
  425 + this.virtualList = this.realTotalData.slice(this.virtualTopRangeIndex, this.virtualBottomRangeIndex + 1);
  426 + }
  427 + },
  428 + //重置动态cell模式下的高度缓存数据、虚拟列表和滚动状态
  429 + _resetDynamicListState(resetVirtualList = false) {
  430 + this.virtualHeightCacheList = [];
  431 + if (resetVirtualList) {
  432 + this.virtualList = [];
  433 + }
  434 + this.virtualTopRangeIndex = 0;
  435 + this.virtualPlaceholderTopHeight = 0;
  436 + },
  437 + //重置topRangeIndex和placeholderTopHeight
  438 + _resetTopRange() {
  439 + this.virtualTopRangeIndex = 0;
  440 + this.virtualPlaceholderTopHeight = 0;
  441 + this._updateVirtualList();
  442 + },
  443 + //检测虚拟列表当前滚动位置,如发现滚动位置不正确则重新计算虚拟列表相关参数(为解决在App中可能出现的长时间进入后台后打开App白屏的问题)
  444 + _checkVirtualListScroll() {
  445 + if (this.finalUseVirtualList) {
  446 + this.$nextTick(() => {
  447 + this._getNodeClientRect('.zp-paging-touch-view').then(node => {
  448 + const currentTop = node ? node[0].top : 0;
  449 + if (!node || (currentTop === this.pagingOrgTop && this.virtualPlaceholderTopHeight !== 0)) {
  450 + this._updateVirtualScroll(0);
  451 + }
  452 + });
  453 + })
  454 + }
  455 + },
  456 + //处理使用内置列表时点击了cell事件
  457 + _innerCellClick(item, index) {
  458 + this.$emit('innerCellClick', item, index);
  459 + }
  460 + }
  461 +}
garbage-removal/src/components/z-paging/js/z-paging-config.js 0 → 100644
  1 +// [z-paging]处理main.js中的配置信息工具
  2 +
  3 +let config = null;
  4 +let getedStorage = false;
  5 +const storageKey = 'Z-PAGING-CONFIG-STORAGE-KEY'
  6 +
  7 +function setConfig(value) {
  8 + uni.setStorageSync(storageKey, value);
  9 +}
  10 +
  11 +function getConfig() {
  12 + if (getedStorage) return config;
  13 + config = uni.getStorageSync(storageKey);
  14 + getedStorage = true;
  15 + return config;
  16 +}
  17 +
  18 +export default {
  19 + setConfig,
  20 + getConfig
  21 +};
garbage-removal/src/components/z-paging/js/z-paging-constant.js 0 → 100644
  1 +// [z-paging]常量
  2 +
  3 +export default {
  4 + version: '2.6.2',
  5 + delayTime: 100,
  6 + errorUpdateKey: 'z-paging-error-emit',
  7 + completeUpdateKey: 'z-paging-complete-emit',
  8 + cachePrefixKey: 'z-paging-cache',
  9 +
  10 + listCellIndexKey: 'zp_index',
  11 + listCellIndexUniqueKey: 'zp_unique_index'
  12 +}
garbage-removal/src/components/z-paging/js/z-paging-enum.js 0 → 100644
  1 +// [z-paging]枚举
  2 +
  3 +export default {
  4 + //当前加载类型 0.下拉刷新 1.上拉加载更多
  5 + LoadingType: {
  6 + Refresher: 0,
  7 + LoadingMore: 1
  8 + },
  9 + //下拉刷新状态 0.默认状态 1.松手立即刷新 2.刷新中 3.刷新结束
  10 + Refresher: {
  11 + Default: 0,
  12 + ReleaseToRefresh: 1,
  13 + Loading: 2,
  14 + Complete: 3
  15 + },
  16 + //底部加载更多状态 0.默认状态 1.加载中 2.没有更多数据 3.加载失败
  17 + More: {
  18 + Default: 0,
  19 + Loading: 1,
  20 + NoMore: 2,
  21 + Fail: 3
  22 + },
  23 + //@query触发来源 0.用户主动下拉刷新 1.通过reload触发 2.通过refresh触发 3.通过滚动到底部加载更多或点击底部加载更多触发
  24 + QueryFrom: {
  25 + UserPullDown: 0,
  26 + Reload: 1,
  27 + Refresh: 2,
  28 + LoadingMore: 3
  29 + },
  30 + //虚拟列表cell高度模式
  31 + CellHeightMode: {
  32 + //固定高度
  33 + Fixed: 'fixed',
  34 + //动态高度
  35 + Dynamic: 'dynamic'
  36 + },
  37 + //列表缓存模式
  38 + CacheMode: {
  39 + //默认模式,只会缓存一次
  40 + Default: 'default',
  41 + //总是缓存,每次列表刷新(下拉刷新、调用reload等)都会更新缓存
  42 + Always: 'always'
  43 + }
  44 +}
0 \ No newline at end of file 45 \ No newline at end of file
garbage-removal/src/components/z-paging/js/z-paging-interceptor.js 0 → 100644
  1 +// [z-paging]拦截器
  2 +
  3 +//拦截&处理@query事件
  4 +function handleQuery(callback) {
  5 + try {
  6 + setTimeout(function() {
  7 + _getApp().globalData.zp_handleQueryCallback = callback;
  8 + }, 1);
  9 + } catch (e) {}
  10 +}
  11 +
  12 +//拦截&处理@query事件(私有,请勿调用)
  13 +function _handleQuery(pageNo, pageSize, from, lastItem){
  14 + const callback = _getApp().globalData.zp_handleQueryCallback;
  15 + return callback ? callback(pageNo, pageSize, from, lastItem) : [pageNo, pageSize, from];
  16 +}
  17 +
  18 +//拦截&处理系统language转i18n local
  19 +function handleLanguage2Local(callback) {
  20 + try {
  21 + setTimeout(function() {
  22 + _getApp().globalData.zp_handleLanguage2LocalCallback = callback;
  23 + }, 1);
  24 + } catch (e) {}
  25 +}
  26 +
  27 +//拦截&处理系统language转i18n local(私有,请勿调用)
  28 +function _handleLanguage2Local(language, local){
  29 + const callback = _getApp().globalData.zp_handleLanguage2LocalCallback;
  30 + return callback ? callback(language, local) : local;
  31 +}
  32 +
  33 +//获取当前app对象
  34 +function _getApp(){
  35 + // #ifndef APP-NVUE
  36 + return getApp();
  37 + // #endif
  38 + // #ifdef APP-NVUE
  39 + return getApp({ allowDefault: true });
  40 + // #endif
  41 +}
  42 +
  43 +export default {
  44 + handleQuery,
  45 + _handleQuery,
  46 + handleLanguage2Local,
  47 + _handleLanguage2Local
  48 +};