Commit 7399632e424ccf902533a6c2aafdf15a31bc8cff

Authored by guzijian
1 parent 6dcb91e5

feat: 新增订单样式

Showing 51 changed files with 7660 additions and 1104 deletions
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 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 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 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 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 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 +};
... ...
garbage-removal/src/components/z-paging/js/z-paging-main.js 0 → 100644
  1 +// [z-paging]核心js
  2 +
  3 +import zStatic from './z-paging-static'
  4 +import c from './z-paging-constant'
  5 +import u from './z-paging-utils'
  6 +
  7 +import zPagingRefresh from '../components/z-paging-refresh'
  8 +import zPagingLoadMore from '../components/z-paging-load-more'
  9 +import zPagingEmptyView from '../../z-paging-empty-view/z-paging-empty-view'
  10 +
  11 +// modules
  12 +import commonLayoutModule from './modules/common-layout'
  13 +import dataHandleModule from './modules/data-handle'
  14 +import i18nModule from './modules/i18n'
  15 +import nvueModule from './modules/nvue'
  16 +import emptyModule from './modules/empty'
  17 +import refresherModule from './modules/refresher'
  18 +import loadMoreModule from './modules/load-more'
  19 +import loadingModule from './modules/loading'
  20 +import scrollerModule from './modules/scroller'
  21 +import backToTopModule from './modules/back-to-top'
  22 +import virtualListModule from './modules/virtual-list'
  23 +
  24 +import Enum from './z-paging-enum'
  25 +
  26 +const systemInfo = uni.getSystemInfoSync();
  27 +
  28 +export default {
  29 + name: "z-paging",
  30 + components: {
  31 + zPagingRefresh,
  32 + zPagingLoadMore,
  33 + zPagingEmptyView
  34 + },
  35 + mixins: [
  36 + commonLayoutModule,
  37 + dataHandleModule,
  38 + i18nModule,
  39 + nvueModule,
  40 + emptyModule,
  41 + refresherModule,
  42 + loadMoreModule,
  43 + loadingModule,
  44 + scrollerModule,
  45 + backToTopModule,
  46 + virtualListModule
  47 + ],
  48 + data() {
  49 + return {
  50 + //--------------静态资源---------------
  51 + base64Arrow: zStatic.base64Arrow,
  52 + base64Flower: zStatic.base64Flower,
  53 + base64BackToTop: zStatic.base64BackToTop,
  54 +
  55 + //-------------全局数据相关--------------
  56 + //当前加载类型
  57 + loadingType: Enum.LoadingType.Refresher,
  58 + requestTimeStamp: 0,
  59 + chatRecordLoadingMoreText: '',
  60 + wxsPropType: '',
  61 + renderPropScrollTop: -1,
  62 + checkScrolledToBottomTimeOut: null,
  63 + cacheTopHeight: -1,
  64 + statusBarHeight: systemInfo.statusBarHeight,
  65 +
  66 + //--------------状态&判断---------------
  67 + insideOfPaging: -1,
  68 + isLoadFailed: false,
  69 + isIos: systemInfo.platform === 'ios',
  70 + disabledBounce: false,
  71 + fromCompleteEmit: false,
  72 + disabledCompleteEmit: false,
  73 + pageLaunched: false,
  74 +
  75 + //---------------wxs相关---------------
  76 + wxsIsScrollTopInTopRange: true,
  77 + wxsScrollTop: 0,
  78 + wxsPageScrollTop: 0,
  79 + wxsOnPullingDown: false,
  80 + };
  81 + },
  82 + props: {
  83 + //调用complete后延迟处理的时间,单位为毫秒,默认0毫秒,优先级高于minDelay
  84 + delay: {
  85 + type: [Number, String],
  86 + default: u.gc('delay', 0),
  87 + },
  88 + //触发@query后最小延迟处理的时间,单位为毫秒,默认0毫秒,优先级低于delay(假设设置为300毫秒,若分页请求时间小于300毫秒,则在调用complete后延迟[300毫秒-请求时长];若请求时长大于300毫秒,则不延迟),当show-refresher-when-reload为true或reload(true)时,其最小值为400
  89 + minDelay: {
  90 + type: [Number, String],
  91 + default: u.gc('minDelay', 0),
  92 + },
  93 + //设置z-paging的style,部分平台(如微信小程序)无法直接修改组件的style,可使用此属性代替
  94 + pagingStyle: {
  95 + type: Object,
  96 + default: function() {
  97 + return u.gc('pagingStyle', {});
  98 + },
  99 + },
  100 + //z-paging的高度,优先级低于pagingStyle中设置的height;传字符串,如100px、100rpx、100%
  101 + height: {
  102 + type: String,
  103 + default: u.gc('height', '')
  104 + },
  105 + //z-paging的宽度,优先级低于pagingStyle中设置的width;传字符串,如100px、100rpx、100%
  106 + width: {
  107 + type: String,
  108 + default: u.gc('width', '')
  109 + },
  110 + //z-paging的背景色,优先级低于pagingStyle中设置的background。传字符串,如"#ffffff"
  111 + bgColor: {
  112 + type: String,
  113 + default: u.gc('bgColor', '')
  114 + },
  115 + //设置z-paging的容器(插槽的父view)的style
  116 + pagingContentStyle: {
  117 + type: Object,
  118 + default: function() {
  119 + return u.gc('pagingContentStyle', {});
  120 + },
  121 + },
  122 + //z-paging是否自动高度,若自动高度则会自动铺满屏幕
  123 + autoHeight: {
  124 + type: Boolean,
  125 + default: u.gc('autoHeight', false)
  126 + },
  127 + //z-paging是否自动高度时,附加的高度,注意添加单位px或rpx,若需要减少高度,则传负数
  128 + autoHeightAddition: {
  129 + type: [Number, String],
  130 + default: u.gc('autoHeightAddition', '0px')
  131 + },
  132 + //loading(下拉刷新、上拉加载更多)的主题样式,支持black,white,默认black
  133 + defaultThemeStyle: {
  134 + type: String,
  135 + default: u.gc('defaultThemeStyle', 'black')
  136 + },
  137 + //z-paging是否使用fixed布局,若使用fixed布局,则z-paging的父view无需固定高度,z-paging高度默认为100%,默认为是(当使用内置scroll-view滚动时有效)
  138 + fixed: {
  139 + type: Boolean,
  140 + default: u.gc('fixed', true)
  141 + },
  142 + //是否开启底部安全区域适配
  143 + safeAreaInsetBottom: {
  144 + type: Boolean,
  145 + default: u.gc('safeAreaInsetBottom', false)
  146 + },
  147 + //开启底部安全区域适配后,是否使用placeholder形式实现,默认为否。为否时滚动区域会自动避开底部安全区域,也就是所有滚动内容都不会挡住底部安全区域,若设置为是,则滚动时滚动内容会挡住底部安全区域,但是当滚动到底部时才会避开底部安全区域
  148 + useSafeAreaPlaceholder: {
  149 + type: Boolean,
  150 + default: u.gc('useSafeAreaPlaceholder', false)
  151 + },
  152 + //slot="top"的view的z-index,默认为99,仅使用页面滚动时有效
  153 + topZIndex: {
  154 + type: Number,
  155 + default: u.gc('topZIndex', 99)
  156 + },
  157 + //z-paging内容容器父view的z-index,默认为1
  158 + superContentZIndex: {
  159 + type: Number,
  160 + default: u.gc('superContentZIndex', 1)
  161 + },
  162 + //z-paging内容容器部分的z-index,默认为10
  163 + contentZIndex: {
  164 + type: Number,
  165 + default: u.gc('contentZIndex', 10)
  166 + },
  167 + //使用页面滚动时,是否在不满屏时自动填充满屏幕,默认为是
  168 + autoFullHeight: {
  169 + type: Boolean,
  170 + default: u.gc('autoFullHeight', true)
  171 + },
  172 + //是否监听列表触摸方向改变,默认为否
  173 + watchTouchDirectionChange: {
  174 + type: Boolean,
  175 + default: u.gc('watchTouchDirectionChange', false)
  176 + },
  177 + },
  178 + created(){
  179 + if (this.createdReload && !this.refresherOnly && this.auto) {
  180 + this._startLoading();
  181 + this.$nextTick(this._preReload);
  182 + }
  183 + },
  184 + mounted() {
  185 + this.wxsPropType = u.getTime().toString();
  186 + this.renderJsIgnore;
  187 + if (!this.createdReload && !this.refresherOnly && this.auto) {
  188 + this.$nextTick(this._preReload);
  189 + }
  190 + this.finalUseCache && this._setListByLocalCache();
  191 + let delay = 0;
  192 + // #ifdef H5 || MP
  193 + delay = c.delayTime;
  194 + // #endif
  195 + this.$nextTick(() => {
  196 + this.systemInfo = uni.getSystemInfoSync();
  197 + !this.usePageScroll && this.autoHeight && this._setAutoHeight();
  198 + this.loaded = true;
  199 + })
  200 + this.updatePageScrollTopHeight();
  201 + this.updatePageScrollBottomHeight();
  202 + this.updateLeftAndRightWidth();
  203 + if (this.finalRefresherEnabled && this.useCustomRefresher) {
  204 + this.$nextTick(() => {
  205 + this.isTouchmoving = true;
  206 + })
  207 + }
  208 + this._onEmit();
  209 + // #ifdef APP-NVUE
  210 + if (!this.isIos && !this.useChatRecordMode) {
  211 + this.nLoadingMoreFixedHeight = true;
  212 + }
  213 + this._nUpdateRefresherWidth();
  214 + // #endif
  215 + // #ifndef APP-NVUE
  216 + this.finalUseVirtualList && this._virtualListInit();
  217 + // #endif
  218 + // #ifndef APP-PLUS
  219 + this.$nextTick(() => {
  220 + setTimeout(() => {
  221 + this._getCssSafeAreaInsetBottom(() => this.safeAreaInsetBottom && this.updatePageScrollBottomHeight());
  222 + }, delay)
  223 + })
  224 + // #endif
  225 + },
  226 + destroyed() {
  227 + this._offEmit();
  228 + },
  229 + // #ifdef VUE3
  230 + unmounted() {
  231 + this._offEmit();
  232 + },
  233 + // #endif
  234 + watch: {
  235 + defaultThemeStyle: {
  236 + handler(newVal) {
  237 + if (newVal.length) {
  238 + this.finalRefresherDefaultStyle = newVal;
  239 + }
  240 + },
  241 + immediate: true
  242 + },
  243 + autoHeight(newVal) {
  244 + this.loaded && !this.usePageScroll && this._setAutoHeight(newVal);
  245 + },
  246 + autoHeightAddition(newVal) {
  247 + this.loaded && !this.usePageScroll && this.autoHeight && this._setAutoHeight(newVal);
  248 + },
  249 + },
  250 + computed: {
  251 + finalPagingStyle() {
  252 + const pagingStyle = this.pagingStyle;
  253 + if (!this.systemInfo) return pagingStyle;
  254 + const { windowTop, windowBottom } = this;
  255 + if (!this.usePageScroll && this.fixed) {
  256 + if (windowTop && !pagingStyle.top) {
  257 + pagingStyle.top = windowTop + 'px';
  258 + }
  259 + if (windowBottom && !pagingStyle.bottom) {
  260 + pagingStyle.bottom = windowBottom + 'px';
  261 + }
  262 + }
  263 + if (this.bgColor.length && !pagingStyle['background']) {
  264 + pagingStyle['background'] = this.bgColor;
  265 + }
  266 + if (this.height.length && !pagingStyle['height']) {
  267 + pagingStyle['height'] = this.height;
  268 + }
  269 + if (this.width.length && !pagingStyle['width']) {
  270 + pagingStyle['width'] = this.width;
  271 + }
  272 + return pagingStyle;
  273 + },
  274 + finalLowerThreshold() {
  275 + return u.convertToPx(this.lowerThreshold);
  276 + },
  277 + finalPagingContentStyle() {
  278 + if (this.contentZIndex != 1) {
  279 + this.pagingContentStyle['z-index'] = this.contentZIndex;
  280 + this.pagingContentStyle['position'] = 'relative';
  281 + }
  282 + return this.pagingContentStyle;
  283 + },
  284 + renderJsIgnore() {
  285 + if ((this.usePageScroll && this.useChatRecordMode) || !this.refresherEnabled || !this.useCustomRefresher) {
  286 + this.$nextTick(() => {
  287 + this.renderPropScrollTop = 10;
  288 + })
  289 + }
  290 + return 0;
  291 + },
  292 + windowHeight() {
  293 + if (!this.systemInfo) return 0;
  294 + return this.systemInfo.windowHeight || 0;
  295 + },
  296 + windowBottom() {
  297 + if (!this.systemInfo) return 0;
  298 + let windowBottom = this.systemInfo.windowBottom || 0;
  299 + if (this.safeAreaInsetBottom && !this.useSafeAreaPlaceholder) {
  300 + windowBottom += this.safeAreaBottom;
  301 + }
  302 + return windowBottom;
  303 + },
  304 + isIosAndH5() {
  305 + // #ifndef H5
  306 + return false;
  307 + // #endif
  308 + return this.isIos;
  309 + }
  310 + },
  311 + methods: {
  312 + //当前版本号
  313 + getVersion() {
  314 + return `z-paging v${c.version}`;
  315 + },
  316 + //设置nvue List的specialEffects
  317 + setSpecialEffects(args) {
  318 + this.setListSpecialEffects(args);
  319 + },
  320 + //与setSpecialEffects等效,兼容旧版本
  321 + setListSpecialEffects(args) {
  322 + this.nFixFreezing = args && Object.keys(args).length;
  323 + if (this.isIos) {
  324 + this.privateRefresherEnabled = 0;
  325 + }
  326 + !this.usePageScroll && this.$refs['zp-n-list'].setSpecialEffects(args);
  327 + },
  328 + // #ifdef APP-VUE
  329 + //当app长时间进入后台后进入前台,因系统内存管理导致app重新加载时,进行一些适配处理
  330 + _handlePageLaunch() {
  331 + // 首次触发不进行处理,只有进入后台后打开app重新加载时才处理
  332 + if (this.pageLaunched) {
  333 + // 解决在vue3+ios中,app ReLaunch时顶部下拉刷新展示位置向下偏移的问题
  334 + // #ifdef VUE3
  335 + this.refresherThresholdUpdateTag = 1;
  336 + this.$nextTick(() => {
  337 + this.refresherThresholdUpdateTag = 0;
  338 + })
  339 + // #endif
  340 + // 解决使用虚拟列表时,app ReLaunch时白屏问题
  341 + this._checkVirtualListScroll();
  342 + }
  343 + this.pageLaunched = true;
  344 + },
  345 + // #endif
  346 + //使手机发生较短时间的振动(15ms)
  347 + _doVibrateShort() {
  348 + // #ifndef H5
  349 +
  350 + // #ifdef APP-PLUS
  351 + if (this.isIos) {
  352 + const UISelectionFeedbackGenerator = plus.ios.importClass('UISelectionFeedbackGenerator');
  353 + const feedbackGenerator = new UISelectionFeedbackGenerator();
  354 + feedbackGenerator.init();
  355 + setTimeout(() => {
  356 + feedbackGenerator.selectionChanged();
  357 + }, 0)
  358 + } else {
  359 + plus.device.vibrate(15);
  360 + }
  361 + // #endif
  362 + // #ifndef APP-PLUS
  363 + uni.vibrateShort();
  364 + // #endif
  365 +
  366 + // #endif
  367 + },
  368 + //设置z-paging高度
  369 + async _setAutoHeight(shouldFullHeight = true, scrollViewNode = null) {
  370 + let heightKey = 'min-height';
  371 + // #ifndef APP-NVUE
  372 + heightKey = 'min-height';
  373 + // #endif
  374 + try {
  375 + if (shouldFullHeight) {
  376 + let finalScrollViewNode = scrollViewNode || await this._getNodeClientRect('.zp-scroll-view');
  377 + let finalScrollBottomNode = await this._getNodeClientRect('.zp-page-bottom');
  378 + if (finalScrollViewNode) {
  379 + const scrollViewTop = finalScrollViewNode[0].top;
  380 + let scrollViewHeight = this.windowHeight - scrollViewTop;
  381 + scrollViewHeight -= finalScrollBottomNode ? finalScrollBottomNode[0].height : 0;
  382 + const additionHeight = u.convertToPx(this.autoHeightAddition);
  383 + const finalHeight = scrollViewHeight + additionHeight - (this.insideMore ? 1 : 0) + 'px !important';
  384 + this.$set(this.scrollViewStyle, heightKey, finalHeight);
  385 + this.$set(this.scrollViewInStyle, heightKey, finalHeight);
  386 + }
  387 + } else {
  388 + this.$delete(this.scrollViewStyle, heightKey);
  389 + this.$delete(this.scrollViewInStyle, heightKey);
  390 + }
  391 + } catch (e) {}
  392 + },
  393 + //触发更新是否超出页面状态
  394 + _updateInsideOfPaging() {
  395 + this.insideMore && this.insideOfPaging === true && setTimeout(this.doLoadMore, 200)
  396 + },
  397 + //清除timeout
  398 + _cleanTimeout(timeout) {
  399 + if (timeout) {
  400 + clearTimeout(timeout);
  401 + timeout = null;
  402 + }
  403 + return timeout;
  404 + },
  405 + //添加全局emit监听
  406 + _onEmit() {
  407 + uni.$on(c.errorUpdateKey, () => {
  408 + this.loading && this.complete(false).catch(() => {});
  409 + })
  410 + uni.$on(c.completeUpdateKey, (data) => {
  411 + setTimeout(() => {
  412 + if (this.loading) {
  413 + if (!this.disabledCompleteEmit) {
  414 + const type = data.type || 'normal';
  415 + const list = data.list || data;
  416 + const rule = data.rule;
  417 + this.fromCompleteEmit = true;
  418 + switch (type){
  419 + case 'normal':
  420 + this.complete(list);
  421 + break;
  422 + case 'total':
  423 + this.completeByTotal(list, rule);
  424 + break;
  425 + case 'nomore':
  426 + this.completeByNoMore(list, rule);
  427 + break;
  428 + case 'key':
  429 + this.completeByKey(list, rule);
  430 + break;
  431 + default:
  432 + break;
  433 + }
  434 + } else {
  435 + this.disabledCompleteEmit = false;
  436 + }
  437 + }
  438 + }, 1);
  439 + })
  440 + },
  441 + //销毁全局emit和listener监听
  442 + _offEmit(){
  443 + uni.$off(c.errorUpdateKey);
  444 + uni.$off(c.completeUpdateKey);
  445 + }
  446 + },
  447 +};
... ...
garbage-removal/src/components/z-paging/js/z-paging-mixin.js 0 → 100644
  1 +// [z-paging]使用页面滚动时引入此mixin,用于监听和处理onPullDownRefresh等页面生命周期方法
  2 +
  3 +export default {
  4 + onPullDownRefresh() {
  5 + if (this.isPagingRefNotFound()) return;
  6 + this.$refs.paging.reload().catch(() => {});
  7 + },
  8 + onPageScroll(e) {
  9 + if (this.isPagingRefNotFound()) return;
  10 + this.$refs.paging.updatePageScrollTop(e.scrollTop);
  11 + e.scrollTop < 10 && this.$refs.paging.doChatRecordLoadMore();
  12 + },
  13 + onReachBottom() {
  14 + if (this.isPagingRefNotFound()) return;
  15 + this.$refs.paging.pageReachBottom();
  16 + },
  17 + methods: {
  18 + isPagingRefNotFound() {
  19 + return !this.$refs.paging;
  20 + }
  21 + }
  22 +}
... ...
garbage-removal/src/components/z-paging/js/z-paging-static.js 0 → 100644
  1 +// [z-paging]公用的静态图片资源
  2 +
  3 +export default {
  4 + base64Arrow: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkBAMAAACCzIhnAAAAD1BMVEVHcExRUVFMTExRUVFRUVE9CdWsAAAABHRSTlMAjjrY9ZnUjwAAAQFJREFUWMPt2MsNgzAMgGEEE1B1gKJmAIRYoCH7z9RCXrabh33iYktcIv35EEg5ZBh07pvxJU6MFSPOSRnjnBUjUsaciRUjMsb4xIoRCWNiYsUInzE5sWKEyxiYWDbyefqHx1zIeiYTk7mQYziTYecxHvEJjwmIT3hMQELCYSISEg4TkZj0mYTEpM8kJCU9JiMp6TEZyUmbAUhO2gxAQNJiIAKSFgMRmNQZhMCkziAEJTUGIyipMRjBSZkhCE7KDEFIUmTeGCHJxWz0zXaE0GTCG8ZFtEaS347r/1fe11YyHYVfubxayfjoHmc0YYwmmmiiiSaaaKLJ7ckyz5ve+dw3Xw2emdwm9xSbAAAAAElFTkSuQmCC',
  5 + base64ArrowWhite: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkBAMAAACCzIhnAAAAElBMVEVHcEz///////////////////+IGTx/AAAABnRSTlMA/dAkXZOhASU/AAABYElEQVRYw+2YwXLCIBCGsdAHWGbyAKZ4zxi9O017rxLf/1UaWFAgA1m8dcpedNSPf/l/Vh0Ya/Wn6hN0JcGvoCqRM4C8VBFiDwBqqNuJKV0rAnCgy3AUqZE57x0iqTL8Br4U3WBf/YWaIlTKfAcELU/h9w72CSVPa3C3OCDvhpHbRp/s2vq4fHhCeiCl2A3m4Qd71DQR257mFBlMcTlbFnFWzNtHxewYEfSiaLS4el8d8nyhmKJd1CF4eOS0keLMAuSxubLBIeIGQW8YHCFFo7EH9+YDcQt9FMZEswTheaNxTHwHT8SZorJjMrEVwo4Zo0U8HSEyZvJMOg4RjnmmRr8nDYeIz3OMkbfE/QhBo+U9RnZJxjGCRh/WKmHEMWLNkfPKsGh/CWJk1JjG0kcuJggTt34VDP8aWAFhp4nybVb5+9qQhjSkIQ1pSEMa8k+Q5U9rV3dF8MpFBK+/7miVq1/HZ2qmo9D+pAAAAABJRU5ErkJggg==',
  6 + base64Flower: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkBAMAAACCzIhnAAAAKlBMVEVHcEzDw8Ovr6+pqamUlJTCwsKenp61tbWxsbGysrLNzc2bm5u5ubmjo6MpovhuAAAACnRSTlMA/P79/sHDhiZS0DxZowAABBBJREFUWMPtl89rE0EUx7ctTXatB3MI1SWnDbUKPUgXqh4ED8Uf7KUVSm3ooVSpSii0Fn/gD4j4o+APiEoVmos9FO2celiqZVgwgaKHPQiCCkv+F99kM7Ozm5kxq1dfD91k9pPve9/3ZjbRNHHok/mKli4eIPNgSuRObuN9SqSEzM20iGnm0yIbqCuV7NSSSIV7uyPM6JMBYdeTOanh/QihJYZsUCSby+VkMj2AvOt0rAeQAwqE3lfKMZVlQCZk1QOCKkkVPadITCfIRNKxfoJI5+0OIFtJx14CMSg1mRSDko7VAfksRQzEbGYqxOJcVTWMCH2I1/IACNW0PWU2M8cmAVHtnH5mM1VRWtwKZjOd5JbF6s1IbaYqaotjNlPHgDAnlAizubTR6ovMYn052g/U5qcmOpi0WL8xTS/3IfSet5m8MEr5ajjF5le6dq/OJpobrdY0t3i9QgefWrxW9/1BLhk0E9m8FeUMhhXal499iD0eQRfDF+ts/tttORRerfp+oV7f4xJj82iUYm1Yzod+ZQEAlS/8mMBwKebVmCVp1f0JLS6zKd17+iwRKTARVg2SHtz3iEbBH+Q+U28zW2Jiza8Tjb1YFoYZMsJyjDqp3M9XBQdSdPLFdxEpvOB37JrHcmR/y9+LgoTlCFGZEa2sc6d4PGlweEa2JSVPoVm+IfGG3ZL037iV9oH+P+Jxc4HGVflNq1M0pivao/EopO4b/ojVCP9GjmiXOeS0DOn1o/iiccT4ORnyvBGF3yUywkQajW4Ti0SGuiy/wVSg/L8w+X/8Q+hvUx8Xd90z4oV5a1i88MbFWHz0WZZ1UrTwBGPX3Rat9AFiXRMRjoMdIdJLEOt2h7jrYOzgOamKZSWSNspOS0X8SAqRYmxRL7sg4eLzYmNehcxh3uoyud/BH2Udux4ywxFTc1xC7Mgf4vMhc5S+kSH3Y7yj+qpwIWSoPTVCOOPVthGx9FbGqrwFw6wSFxJr+17zeKcztt3u+2roAEVgUjDd+AHGuxHy2rZHaa8JMkTHEeyi85ANPO9j9BVuBRD2FY5LDMo/Sz/2hReqGIs/KiFin+CsPsYO/yvM3jL2vE8EbX7/Bf8ejtr2GLN65bioAdgLd8Bis/mD5GmP2qeqyo2ZwQEOtAjRIDH7mBKpUcMoApbZJ5UIxkEwxyMZyMxW/uKFvHCFR3SSmerHyDNQ2dF4JG6zIMpBgLfjSF9x1D6smFcYnGApjmSLICO3ecCDWrQ48geba9DI3STy2i7ax6WIB62fSyIZIiO3GFQqSURp8wCo7GhJBGwuSovJBNjb7kT6FPVnIa9qJ2Ko+l9mefGIdinaMp0yC1URYiwsdfNE45EuA5Cx9EhalfvN5s+UyItm81vaB3p4joniN+SCP7Qc1hblAAAAAElFTkSuQmCC',
  7 + base64FlowerWhite: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkBAMAAACCzIhnAAAAElBMVEX///9HcEz///////////////84chYNAAAABnRSTlP/AGzCOYZj5g1nAAACfklEQVRYw+2YTVPDIBCGtza9Jw25a0bvcax30o73OOr//yvma2F3YWlpPTijXNpAHrK8LLALVPFium2vNIFSbwGKTGQA2GUiHcD29yDNy3sMIdUBQl7r2H8mOEVqAHgPkYZUS6Qc2zYhQqtjyDZEximCZwWZLIBeIgYShs2NzxKpSUehYpMJhURGb+O+w5BpMCAREKPnCDHbIY20SzhM5yxziAXpOiBXydrekT9i5XDEq4NIIHHgyU5mRGqviII4mREJJA4QJzMiILwlRJzpKxJKvCBm8OsBBbLux0tsPl4RKYm5aPu6jw1U4mGxEUR9g8M1PcqBEp/WJliNgYOXueBzS4jZSIcgY5lCtevgDSgyzE+rAfuOTQMq0yzvoGH18qju27Mayzs4fPyMziCx81NJa5RNfW7vPYK9KOfDiVkBxFHG8hAj9txuoBuSWORsFfkpBf7xKFLSeaOefEojh5jz22DJEqMP8fUyaKdQx+RnG+yXMpe8Aars8ueR1pVH/bW3FyyvPRw90upLDHwpgBDtg4aUBNkxRLXMAi03IhcZtr1m+FeI/O/JNyDmmL1djLOauSlNflBpW18RQ2bPqXI22MXXEk75KRHTnkPkYbESbdKP2ZFk0r5sIwffAjy1lx+vx7NLjB6/E7Jfv5ERKhzpN0w8IDE8IGFDv5dhz10s7GFiXRZcUeLCEG5P5nDq9k4PFDcoMpE3GY4OuxuCXhmuyNB6k0RsLIAvqp9NE5r8ZCSS8gxnUp7ODdYhZTqxuiJ9uyJJtPmpqJ7wVj+XVieS903iViHziqAhchLEJAyb7jWU647EpUofQ0ziUuXXXhDddtlllSwjgSQu7r4BRWhQqfDPMVwAAAAASUVORK5CYII=',
  8 + base64Success: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkBAMAAACCzIhnAAAAElBMVEVRUVFHcExTU1NRUVFRUVFRUVFOSlSUAAAABnRSTlP/AI6+VySB3ZENAAACcElEQVRYw+2YyYKCMAyGI8hdpdxdZu7gcpdZ7jL6/s8yYheSNi0aPdqbwOffpGmaFOYPD3gj4bisN7vddv17N/JVgxn5x12IWgIaWTuO/IE3PseQbwjGPo2cgRmHFLJwdm/X643zwiqOKPPJ1nj3sjEP2iiifZWj5bhopSyGaEO2HX5fbQJzwJ+W7x/jw5ZFjsEU0PMph9xE8i5EqprKALW95eJQURkgzw98uJ/JvwGecR7bIjWWsUgVrrIfFZ2HlLy3sKETD1mmRLRMRhGVssRa0xJkdn3SpJBymBkM8+pSSDXMDNyDaToVHd2fgpNt0sjwiUZO19+jGQ+gQEg9Oq+bufmAVGihomNmjQG7UG3020vrlm7lkFnKFGU3kZ0KGAdmKe821pipQ+qEKcrZeTL2g5FsUks4cStjEZWwXg0b0n4GxmEpkWwIs5VBynjgK7xZaz1/0D7OxkVuLpsY5BQNFyLS84VBjjbg0iL2r2EQHBOxBhikuUOkdxODVF1cxHoWtPPsiyXO455Iv34hssCO8EV4ZIYTjS8SR4qYSHRiTiYQ4ZFbHi0iIhhBTi6dTCgSWRcnw4h4yGTuyTAiOGBIWGoZTgSHJQl+LcOJ4OCnW6yX2bMnJ9pidCOXtkTkTrIGpYuOynAiOF14SamMiOCk5Ke+mq8BcOrrvym8d0zKIQnWT+M1WwOQNO4fFiWb18hhERxJPx2fblbPHHyC41VyiAtKBUFBIih7JMWVoIQTFIr3lKPN80WvoLSWFPC653ioTZA0I0FrQ7qU6asaK0H7JmkSJa2ooOGVtNUsc3j9FYHkIkJy3SG6VHnfXKXGP9t4N9Q4Ye98AAAAAElFTkSuQmCC',
  9 + base64SuccessWhite: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkBAMAAACCzIhnAAAAGFBMVEVHcEz///////////////////////////8dS1W+AAAAB3RSTlMAiVYk6KvDHLfaegAAAo1JREFUWMPtWEtzmzAQNhCTq910ytXpiyvxTNOr60zrayepx9d02gnX4sTm7xcEiJX2gdnkGJ1A4tOnfWqXyeR1vMRYzrcPD9v5h5MBl3/Ldvx4cxIg/FWC8X0xjLjalM54uhhCfCrRuJURX0pi3EmIqZV7O59vrRZmguStHL9b7S7ftfLwOtiZDw7AHMtmquAQ12b5Wwbnordm8g9zLLO49qc/m2n6aKnhwPOGZ08hAiNHhheiHae1lOUPGZpQkPKa3q0mOUjaRzSRaGUjpy/mmWSwySSpllcEteBKAT52KEnSbblA51pJEPxBQoiH1FP4E3s5+FJv07h6/ylD6ui7B+9fq/ehrFB98ghec9EoVtyjK8pqCHLmCBOwMWSCeWFNN4MbPAk55NhsvoFHSSVR0k5TCTTEzlUGcqV/nVp7n9oIVkmtaqbAEqEgfdgHJPwsEAyZ9r4VAZXFjpEwyaw3+H2v42KYxKhs1XvY/gSSGv+IHyUSuHXCeZhLAgVI3EjgSGo1Fb3xO0tGGU9S2/KAIbtjxpJASG73qox6w5LUq0cEOa+iIONIWIilQSQ0pPa2jgaRQAgQP7c0mITRWGxpMAmEQFN2NAQJNCV0mI6GIIEO47hlQ0ORQLd0nL+hoUjg1m6I1TRr8uYEAriBHLcVFQ5UEMiBe3XkTBEG04WXlGKGxPnMS305XQPA1Ocn2JiuAZwE66fxnKwBnDTuXxZTMq85lwW6kt5ndLqZPefiU1yvmktcUSooChJF2aMprhQlnKJQ5FxRKkcVRa+itNYU8Io2oVkY14w0NMWYlqft91Bj9VHq+ca3b43BxjWJmla0sfKohlfTVpPN+93L/yLQ/IjQ/O5Q/VR5HdL4D7mlxmjwVdELAAAAAElFTkSuQmCC',
  10 + base64Empty: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADIBAMAAABfdrOtAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAbUExURdvc3EdwTMLBwcjIyLSzs/Hx8ff39////19dXXz7IJEAAAAFdFJOU/4A6J9QDyyutAAAB5VJREFUeNrtnM1z4jYYxhUHkR4hdu9eU7Z75Ct7jgPbs9ZZmSuTrUWPmXTA186e+LMrf0uWLMtf2WkHXQgzln88et5XeiVMwPQdGrhCrpAr5Aq5Qv4TkJ07OGQFMLp1B4VYCz+kDblDQhJGeH4eEDLBYdLOHwaDWNBPIeHLYJAJ3meQ83IoCMTHDBKOBoKYGOeM8G0gyD0LObnDQB5ZSCtTNCBfsM9AboaBPLCQcDAIM1zht/dQEkMsd1DjI4hpw2YzMtBJeBbydWpCTJs3YDKGX62YgfGoVwi9KwtZJAzcYHHRm7sYCKD390nQSIoO5JGZIEOYxNoZ4+deISYLyeL5hLHbJ2QK98W0kudMgJe9Qh73odhO+KZHyNYGvgQS9gmJKhUigwSj3iBPUhXxePWmxBqHw0Mej9WQ3qILVjLC177yxNxXQ/7uK+Mn1aNVLsGsBTaWrSAPobYl0aUHt2fIs2Rgz7c9QYL0pSTkSzILLFtAJMH1cidN998T9E0/Sg73/pEEwrgkYRh86wlC949gJsR6EobBcz8hHOVgKYi2m6kZtodIkjEQvF3QjbGpmplB4/lRgJhxgRS2N15iijAvPmByDtCxfQhPJ8J4CR82rgCCBILarScw6X0OcMUyYrFVmbxErl0ZacFIoloOLdJAO42qY+NMDss2kKS8xmiZxcCpFKXWvpRGbQqJp5ixyRfJMmR6x0Fk+z29kmgWDYI5ziFbdug/84HxvduhWhLOJ2StPDQrMJPSjNANklh8QhB7dBO0yTGRwn1fkOk8rbQjiB8Ymww+JuiuN0icmSccK4naLMWYa/euL0+m23GyM8kgAc6sYeL4z04Qa4WjGepcKIliO8EUGSk7d9OGWOsoK31OSdy8TQZ59Y/hWbaV1IVs5/Ed6UzGK4nANAJiyGhRsZPUg2yzLe9hLyiJIyCaDU7udC2uy9pnkKvidlBUEltzFAqxRhBrBZm7HfZnjEQI3boqTsJq15PUDEaKZLgiJYc8OZtCtnM/4G93OFYooXpvdy0guwWWNQkEHl/j7Jw1XRmtlS9HYJkSPjk1IUnyyRqUKQn45NSDlP1mcg9i6En1ZU2IADnEtHF1Q+JwIcS/d5YakPuDUamEShGUHHikAz9oQCaE0CsrpYjDBVkEHQYdyK+EkKPhVErxqh1xbJ/oQf4gEeVsOIEc41WJNAwcd9GBfCZJezXsJhAvH+ImEEIOzlwXgpw5wQ0gH3MIOcsiQAahZuSD69/UQyxcQEggiQARQseVFO/ASAMCgM9gjkHZmhLENzi1AOhA7ullkMWUrfHKfpMiDBHtDIx6yCS6jseEnDUe7zcT6DGCtnrIY3olZw1hrPHkfucIAJa1EDu/lsVEyVmGGA67coKijeogFnMxlEaAV5ghRdDm1kDuuatZTJBGgJdOthIzsvZbDWRRuh6ScgR4EQLgagQvRQIxxQ4sxqcR4GE+c4CkjZQQW9YF89Y4OFAjOCki5KmiDxsBL3PlSJWlAFVogaoIePlYi2ClCJAHRa/cmre5eqTii4uvisqQJxqnip6pNd68DhEvyEs5xIyHBNdh4thCKhU++10kD7Gy1Up1A/o56FKuRJQWSFCuf8dpbisxhqHSKlSSgvG7VTaFKO5TzYD5VMPUxEB2YJNiqq3xYJ0KrroH8mq7xpoXqEZgfgNRUQsDtTVvUOk3sLUKbqrBr7YGvkCkQNC/9SA+vTYtvERrxiKEmcogk4ZqCLUd59MIEiFYHlIoxelCaJWDMmtOPIa80XVLbkb6hzaEwwTcPEmV4AIRlBGNIEmuJBFwLAZoHClJ36J8h+wxihpCqJosAnJrSKwEcQOFAFeWN4RQMYc0Ao4Jhg5gpASzyWcDvjpuDIlTkrGGJEro1rHIjHKR3wJCAj+z5oyi11gJBkXy9QFJIiAu78d+pgSjuWhGN0gUAZAcEncSJf4LRrZ8I94WEmcNCJJqBWYjVbE9bg2JxiyrViBWty6QvO56D8jPVWLA4ZX8dfkxvJJPl8t8aCX+pU/Iz1SCf7lc4OBK0OWfQaKLP0TKjj96VvIp+/BDZjwNKF2ItV2vN7sWStAl87oWkm3dZ+k3lEMoYXe8cT1eq2TOePJDD8KfQdxu6iEPxanUZa4HmZRq3dunGsj3BzFq6yD3wnZNX4n2emI2hXyXQpi6RRZdfSgxHNuxVZBFdyVeBPDmCsiksxKUiDAUEKuzkvRUEs0V08pjVyU2/yqFmF2VZGYop3peitdUiQd1pnrL7qTE01tPzE6eaEKm23dQwh2jNlbiay+/245zl94abw45CzNPyqYQ2++kxHGV1crWzg4A2yvR+BY7wziwnRLN7+O36aA54+ZKGjxZYK3txJpxQyUNn5GwtquII4+ACiWtnvawduu1A3SVtH5uhTvAVSpBG7fDYz6RQ+M6JWjmKm6g+RvTla9UMtspu+s+37VbVCupNqPx43CsNawSb1PbtcmDfQWmUILW7rRXSPHtSq5k5ur0a/hb7DQCUiW3G71ejX/wvV1kSoyNbp8Wvyqn1lCIKvl6gNDkNBYzt0GHdr+Pt9xGl1//ncAVcoVcIVfIFXKFXCFXyP8I8i8SyTW4yTz2lwAAAABJRU5ErkJggg==',
  11 + base64Error: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADIBAMAAABfdrOtAAAAJFBMVEVHcEzo6Oibm5ukpKSbm5uampqbm5ubm5u5ubnn5+fm5ub6+vpGpDPdAAAAC3RSTlMA/v4hb+u20dq8aQhnHL4AAATwSURBVHja7ZvNb+JGGMbdjjdVe3NPodzeMhj1ZMUGujkh28B9wKR7iwwBqafWSbPqsbm0uTWtVlrTS9v0Et9yqLQS/1zHNiTZMMB4bO92d+dRUITt8c/PvPPx2h4URUpKSkpKSkpK6m3K6lFN73Q+S/+es3W3fzabTh2Dl0FAXEM+BgrgeXxRsdILTDU9n7J0vz/+EsCYC9KEiSFc06pf5zouqAkjkGWo0OG5Fq6j2IwZ6I4/4DhyTxc20oUjAj5PRTTrwvGAZ9p+ADzlD4RDctCoLhb7JUP87xeLxS3BZUIQ+YNCFi8wRwc4GIqGRK/GkM+5ILV8kFflOmkkkH/LddJ4c05eSSfSyTvrZPEmnCw+UCeuk84QvTSnUF0uCL68fBle/swF+RL1QZ/EpU6gHtOsAM64pnjPwxgTLsjoBM58ODNaAXYBT5QeGdr0KwcEA8He0TkPBLCjUDNHpG4qlg8eTCzXht1FVd1MxTPHj5LTtUiSrKK+7iDf8wBGxk4If3arLv/HF4Tox0A2nlFIGp+CIA+LzSamgbp4TNvZjECtDAjyMcB5HybLO6NxsRA1vmFCNjguNXDGWygbRPXh/B+zn9zPWK5RCkT18QxA57YgAqE+HGS6/tAoD4JO0ts+M2tbyQJpc95a5oI0xXNhCZGQ/x8E0VSCkUZY6Z6CIE/qdO5eL+yPlW6tMMgefPs3o7Bdt8iguJj4DThlZSY/rJ0yB+RraLDK2jAQCHyr4zIhT9mQ7vowygMZjpgQG+CYUV2E1EWqixyzICr8eFFnBB5ba1Y4IIfeKQvysW7ssZrwQLEFmvCBM2U6oRkdI5Wgm1QnO8RUTDlASoiESIiESMh7BDHKhlhu/LbSNUuEqL3lu1p945vO3BArADiaum7vBGDUKQfSIjBykooyrRPQnTIglHFfSagHeqd4iErwa9duEebpckGQjx/VT4v5fC0XhJHAd1mPRvJAVMZiAeQzTpgHYrPKqkGnUEiX+dCoNS4UgniHMTnUS4iESIiE7IS0x+mnVAidglDwVcmQJpy2WQ8VC4UgogfbA1RE4Nuw3UghEBV2rKl7V5ygAJPSY9KGQbP01mVjA5Fa2f1kQN2U3k+M9POWB8gnJUNMZJioWTMzKwOklyxgDrCXVcMMEF90tXM9C2TiCqmfCdIRi/jeewNpyerKok9WkGuzfCdYC+fXRsmBxxpVGG2zY0ZBbieJKvPrDQce3lxppBhIjGFWGkVoxUEoZt0Mukn2XBQH0bTHZpaMIp2sU/6qasU70W6/eHjM09VmYSc6C6Jpvz+orKvVxot8kL3HkMr9IZ9qeZ2o6RrO9mOI9ufdIR9peZ2gNIW31yC/MpyI9ngUDNIsezPks3vIsWDGdYA7cZa9pbqUVeCr/neiaR3U3R4BfXPg75vwb8I/b7HjxChobDZCO+Ny4wuxxaVxPPowcoNnrzPmzGFlX3RJHz2FafbhJ41n8PLx2DCM7KkwQgpqka1DVzKdJNHfJwBe9l/n0eSZFsIPjVSY8xZKZpSXnogwled98wAx3xRcdBNq1f1fhFVdIcL5tvaDolC7XaqaWStEtLOJHkbhlSauMLrma4yHEa03AVUoIUs/M2NQFkchBZiGUPeKonAnqhLOo4hrKf0WTyZ1FcU0Ki0hVrSr+Mucnvya7jYUKSkpKSkpKSmpD0f/AXq+Umj5XnXDAAAAAElFTkSuQmCC',
  12 + base64BackToTop: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADIBAMAAABfdrOtAAAAElBMVEVRUVH+/v5HcEyZmZlRUVFRUVGm1ByOAAAABnRSTlPMzADMTZAJBBGsAAAEnElEQVR42t2cS27jMAyGf7/2U+QCQeDsbeQCgZDujaC5/1UmkzaJn+JDFGcw3LdfflKibJkkDnxrL7dbg7sNt6+L4O8OYBM+B0ys+QrGkHZG+OEEQ8g6go8Bx1GIGMdpNOQyIG6XdMgnSPtKhLQDGEZFBgYMkhKFtGBb0EIEjDgFRowoBVaMGAWpMedEfxMiZtwpUsgZCqtlkCNUdpVAWigtCCCDFtLwIWeoreZCWiRYYEKGFEjDg+yRZCUH0iLRAgNyToXUNCRZyMqWhGnUN2IPm3wSlwJ7IUspyCBkIQUZhCykIIeQuRTkEDKXAuM9srrtYbrZN7Y98giZSoFd+t1OxmMITG0dcrSFXFchZ1tIvQZpYWxhBbK3hpQrkMEa0iwh5t4a+QvZvDXyF7J5a+Qv5PPW21/I5623v5DPW29/IaO3Xv5Clrw1y1/Ikrdm+Qs5svw83yNnSJ5BQb4F/F7EIEJSnThGBAXxkFQfLOviQUE8JAUPsosHBfGQfDAtHhREQ1JxIV00KIgmrnRI84S0yAd5BAXxxJUck0f6Qnwr9qmr6xF5xLMjcwn/iudIEAdWnyjkEXlQKZiRVzoqRyLbgeUKKR8Q4alY7cSnoxzSf2ggsqehKr6YVpcXpOd7H93f60cKhOd7Re2LteUF4eLqiVS1mr0ge4io6C2+soaFkJ7MuuuQs1yITEp9hwwKISIpzR2iESKSIoT0rLNwuVHQqoSIpAQJpGce60vIUSdEIuUqgPTsJ5QFZK8UIpBS8iG94GFrDjlrhfCl8CG96Llxmle4kEr6vKWBPIVo9kqDQSRk9/3cWoikcCFPAd33v4dIChPyEvLzBA6RlEYWke4JEUnhKXkLeUEKxRHJFfKCQHGucIW8IdZSRkLeEGMpYyEjiK2UsZARxFTKRMgYYillImQMMZQyFTKB2EmZCplAuFLIHT8TMoWwpQwiIVMIUwqpZP5bp5CCvCTiQKr5f5lCQN+tPCBn2ZvVDFJwIDUP0m1BYAfZYRNSsCB7BqTbhoARePIxtZ9tgwWkoJcwCalmv3MBAemtO4R6dah2HaKQqj8Zvp9sQDjvJ21+SPCBHPJDDk6QITekEV7gqCC19CpKAym9IMfckKv4olMBCeIrWwVEfvkshzQekO9r9P1/ALk+IG1eSPCDiCJfyG+FyU+A6ZCa/piZDinpz7LpkCv5gdkAEshP5emQhv7onw6pGeULyZCSUYiRDAmMkpJkCKs4JhFSq8p8hJBSVbAkhARV6ZUQoisik0FqXTmcDHLVFfbJIEFXoiiCNMpiSxGkVJaNiiBBWQArgTTaUl4JpNQWJUsgQVteXQg+AKkLxQWFGKW+5J2+eVp4S168X3CF1CltCKdTJ8lb84YK2bUBO+wZW0Pqv9nk4tKu49N45NJC5dMM5tLW5tOg59Jq6NM06dL+abFXwr/RkuvTXJwae1abtE/Dt0/ruksTvs84AZ/BCC4jHnyGVfiM3VBQFANEXEah+Ax18RlP4zNox2dkkM/wI58xTn8yDCXGYCDV3W5RGSajtXyGhG1jbpbjzpwGt/0MJft8jqC7iUbQ/QZaxdnKqcIftwAAAABJRU5ErkJggg==',
  13 +}
... ...
garbage-removal/src/components/z-paging/js/z-paging-utils.js 0 → 100644
  1 +// [z-paging]工具类
  2 +
  3 +import zConfig from './z-paging-config'
  4 +import zLocalConfig from '../config/index'
  5 +import c from './z-paging-constant'
  6 +
  7 +const storageKey = 'Z-PAGING-REFRESHER-TIME-STORAGE-KEY';
  8 +let config = null;
  9 +const timeoutMap = {};
  10 +
  11 +/*
  12 +当z-paging未使用uni_modules管理时,控制台会有警告:WARNING: Module not found: Error: Can't resolve '@/uni_modules/z-paging'...
  13 +此时注释下方try中的代码即可
  14 +*/
  15 +// #ifdef VUE2
  16 +try {
  17 + const contextKeys = require.context('@/uni_modules/z-paging', false, /\z-paging-config$/).keys();
  18 + if (contextKeys.length) {
  19 + const suffix = '.js';
  20 + config = require('@/uni_modules/z-paging/z-paging-config' + suffix);
  21 + }
  22 +} catch (e) {}
  23 +// #endif
  24 +
  25 +//获取默认配置信息
  26 +function gc(key, defaultValue) {
  27 + if (!config) {
  28 + if (zLocalConfig && Object.keys(zLocalConfig).length) {
  29 + config = zLocalConfig;
  30 + } else {
  31 + const tempConfig = zConfig.getConfig();
  32 + if (zConfig && tempConfig) {
  33 + config = tempConfig;
  34 + }
  35 + }
  36 + }
  37 + if (!config) return defaultValue;
  38 + const value = config[_toKebab(key)];
  39 + return value === undefined ? defaultValue : value;
  40 +}
  41 +
  42 +
  43 +//获取最终的touch位置
  44 +function getTouch(e) {
  45 + let touch = null;
  46 + if (e.touches && e.touches.length) {
  47 + touch = e.touches[0];
  48 + } else if (e.changedTouches && e.changedTouches.length) {
  49 + touch = e.changedTouches[0];
  50 + } else if (e.datail && e.datail != {}) {
  51 + touch = e.datail;
  52 + } else {
  53 + return {
  54 + touchX: 0,
  55 + touchY: 0
  56 + }
  57 + }
  58 + return {
  59 + touchX: touch.clientX,
  60 + touchY: touch.clientY
  61 + };
  62 +}
  63 +
  64 +//判断当前手势是否在z-paging内触发
  65 +function getTouchFromZPaging(target) {
  66 + if (target && target.tagName && target.tagName !== 'BODY' && target.tagName !== 'UNI-PAGE-BODY') {
  67 + const classList = target.classList;
  68 + if (classList && classList.contains('z-paging-content')) {
  69 + return {
  70 + isFromZp: true,
  71 + isPageScroll: classList.contains('z-paging-content-page'),
  72 + isReachedTop: classList.contains('z-paging-reached-top')
  73 + };
  74 + } else {
  75 + return getTouchFromZPaging(target.parentNode);
  76 + }
  77 + } else {
  78 + return { isFromZp: false };
  79 + }
  80 +}
  81 +
  82 +//获取z-paging所在的parent
  83 +function getParent(parent) {
  84 + if (!parent) return null;
  85 + if (parent.$refs.paging) return parent;
  86 + return getParent(parent.$parent);
  87 +}
  88 +
  89 +//打印错误信息
  90 +function consoleErr(err) {
  91 + console.error(`[z-paging]${err}`);
  92 +}
  93 +
  94 +//延时操作,如果key存在,调用时根据key停止之前的延时操作
  95 +function delay(callback, ms = c.delayTime, key) {
  96 + const timeout = setTimeout(callback, ms);;
  97 + if (!!key) {
  98 + timeoutMap[key] && clearTimeout(timeoutMap[key]);
  99 + timeoutMap[key] = timeout;
  100 + }
  101 + return timeout;
  102 +}
  103 +
  104 +//设置下拉刷新时间
  105 +function setRefesrherTime(time, key) {
  106 + const datas = getRefesrherTime() || {};
  107 + datas[key] = time;
  108 + uni.setStorageSync(storageKey, datas);
  109 +}
  110 +
  111 +//获取下拉刷新时间
  112 +function getRefesrherTime() {
  113 + return uni.getStorageSync(storageKey);
  114 +}
  115 +
  116 +//通过下拉刷新标识key获取下拉刷新时间
  117 +function getRefesrherTimeByKey(key) {
  118 + const datas = getRefesrherTime();
  119 + return datas && datas[key] ? datas[key] : null;
  120 +}
  121 +
  122 +//通过下拉刷新标识key获取下拉刷新时间(格式化之后)
  123 +function getRefesrherFormatTimeByKey(key, textMap) {
  124 + const time = getRefesrherTimeByKey(key);
  125 + const timeText = time ? _timeFormat(time, textMap) : textMap.none;
  126 + return `${textMap.title}${timeText}`;
  127 +}
  128 +
  129 +//将文本的px或者rpx转为px的值
  130 +function convertToPx(text) {
  131 + const dataType = Object.prototype.toString.call(text);
  132 + if (dataType === '[object Number]') return text;
  133 + let isRpx = false;
  134 + if (text.indexOf('rpx') !== -1 || text.indexOf('upx') !== -1) {
  135 + text = text.replace('rpx', '').replace('upx', '');
  136 + isRpx = true;
  137 + } else if (text.indexOf('px') !== -1) {
  138 + text = text.replace('px', '');
  139 + }
  140 + if (!isNaN(text)) {
  141 + if (isRpx) return Number(uni.upx2px(text));
  142 + return Number(text);
  143 + }
  144 + return 0;
  145 +}
  146 +
  147 +//获取当前时间
  148 +function getTime() {
  149 + return (new Date()).getTime();
  150 +}
  151 +
  152 +//获取z-paging实例id
  153 +function getInstanceId() {
  154 + const s = [];
  155 + const hexDigits = "0123456789abcdef";
  156 + for (let i = 0; i < 10; i++) {
  157 + s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
  158 + }
  159 + return s.join('') + getTime();
  160 +}
  161 +
  162 +// 等待一段时间
  163 +function wait(ms) {
  164 + return new Promise(resolve => {
  165 + setTimeout(resolve, ms);
  166 + });
  167 +}
  168 +
  169 +//------------------ 私有方法 ------------------------
  170 +//时间格式化
  171 +function _timeFormat(time, textMap) {
  172 + const date = new Date(time);
  173 + const currentDate = new Date();
  174 + const dateDay = new Date(time).setHours(0, 0, 0, 0);
  175 + const currentDateDay = new Date().setHours(0, 0, 0, 0);
  176 + const disTime = dateDay - currentDateDay;
  177 + let dayStr = '';
  178 + const timeStr = _dateTimeFormat(date);
  179 + if (disTime === 0) {
  180 + dayStr = textMap.today;
  181 + } else if (disTime === -86400000) {
  182 + dayStr = textMap.yesterday;
  183 + } else {
  184 + dayStr = _dateDayFormat(date, date.getFullYear() !== currentDate.getFullYear());
  185 + }
  186 + return `${dayStr} ${timeStr}`;
  187 +}
  188 +
  189 +//date格式化为年月日
  190 +function _dateDayFormat(date, showYear = true) {
  191 + const year = date.getFullYear();
  192 + const month = date.getMonth() + 1;
  193 + const day = date.getDate();
  194 + return showYear ? `${year}-${_fullZeroToTwo(month)}-${_fullZeroToTwo(day)}` : `${_fullZeroToTwo(month)}-${_fullZeroToTwo(day)}`;
  195 +}
  196 +
  197 +//data格式化为时分
  198 +function _dateTimeFormat(date) {
  199 + const hour = date.getHours();
  200 + const minute = date.getMinutes();
  201 + return `${_fullZeroToTwo(hour)}:${_fullZeroToTwo(minute)}`;
  202 +}
  203 +
  204 +//不满2位在前面填充0
  205 +function _fullZeroToTwo(str) {
  206 + str = str.toString();
  207 + return str.length === 1 ? '0' + str : str;
  208 +}
  209 +
  210 +//驼峰转短横线
  211 +function _toKebab(value) {
  212 + return value.replace(/([A-Z])/g, "-$1").toLowerCase();
  213 +}
  214 +
  215 +export default {
  216 + gc,
  217 + setRefesrherTime,
  218 + getRefesrherFormatTimeByKey,
  219 + getTouch,
  220 + getTouchFromZPaging,
  221 + getParent,
  222 + convertToPx,
  223 + getTime,
  224 + getInstanceId,
  225 + consoleErr,
  226 + delay,
  227 + wait
  228 +};
... ...
garbage-removal/src/components/z-paging/wxs/z-paging-renderjs.js 0 → 100644
  1 +// [z-paging]使用renderjs在app-vue和h5中对touchmove事件冒泡进行处理
  2 +
  3 +import u from '../js/z-paging-utils'
  4 +const data = {
  5 + startY: 0,
  6 + isTouchFromZPaging: false,
  7 + isUsePageScroll: false,
  8 + isReachedTop: true,
  9 + isIosAndH5: false,
  10 + appLaunched: false
  11 +}
  12 +
  13 +export default {
  14 + mounted() {
  15 + if (window) {
  16 + this._handleTouch();
  17 + // #ifdef APP-VUE
  18 + this.$ownerInstance.callMethod('_handlePageLaunch');
  19 + // #endif
  20 + }
  21 + },
  22 + methods: {
  23 + //接收逻辑层发送的数据
  24 + renderPropIsIosAndH5Change(newVal) {
  25 + if (newVal === -1) return;
  26 + data.isIosAndH5 = newVal;
  27 + },
  28 + //拦截处理touch事件
  29 + _handleTouch() {
  30 + if (!window.$zPagingRenderJsInited) {
  31 + window.$zPagingRenderJsInited = true;
  32 + window.addEventListener('touchstart', this._handleTouchstart, { passive: true })
  33 + window.addEventListener('touchmove', this._handleTouchmove, { passive: false })
  34 + }
  35 + },
  36 + _handleTouchstart(e) {
  37 + const touch = u.getTouch(e);
  38 + data.startY = touch.touchY;
  39 + const touchResult = u.getTouchFromZPaging(e.target);
  40 + data.isTouchFromZPaging = touchResult.isFromZp;
  41 + data.isUsePageScroll = touchResult.isPageScroll;
  42 + data.isReachedTop = touchResult.isReachedTop;
  43 + },
  44 + _handleTouchmove(e) {
  45 + const touch = u.getTouch(e);
  46 + const moveY = touch.touchY - data.startY;
  47 + if (data.isTouchFromZPaging && ((data.isReachedTop && moveY > 0) || (data.isIosAndH5 && !data.isUsePageScroll && moveY < 0))) {
  48 + if (e.cancelable && !e.defaultPrevented) {
  49 + e.preventDefault();
  50 + }
  51 + }
  52 + },
  53 + _removeAllEventListener(){
  54 + window.removeEventListener('touchstart');
  55 + window.removeEventListener('touchmove');
  56 + }
  57 + }
  58 +};
... ...
garbage-removal/src/components/z-paging/wxs/z-paging-wxs.wxs 0 → 100644
  1 +// [z-paging]微信小程序、QQ小程序、app-vue、h5上使用wxs实现自定义下拉刷新,降低逻辑层与视图层的通信折损,提升性能
  2 +
  3 +var currentDis = 0;
  4 +var isPCFlag = -1;
  5 +var startY = -1;
  6 +
  7 +function propObserver(newValue, oldValue, ownerIns, ins) {
  8 + var state = ownerIns.getState() || {};
  9 + state.currentIns = ins;
  10 + var dataset = ins.getDataset();
  11 + var loading = dataset.loading == true;
  12 + if (newValue && newValue.indexOf('end') != -1) {
  13 + var transition = newValue.split('end')[0];
  14 + _setTransform('translateY(0px)', ins, false, transition);
  15 + state.moveDis = 0;
  16 + state.oldMoveDis = 0;
  17 + currentDis = 0;
  18 + } else if (newValue && newValue.indexOf('begin') != -1) {
  19 + var refresherThreshold = ins.getDataset().refresherthreshold;
  20 + _setTransformValue(refresherThreshold, ins, state, false);
  21 + }
  22 +}
  23 +
  24 +function touchstart(e, ownerIns) {
  25 + var ins = _getIns(ownerIns);
  26 + var state = {};
  27 + var dataset = {};
  28 + ownerIns.callMethod('_handleListTouchstart');
  29 + if (ins) {
  30 + state = ins.getState();
  31 + dataset = ins.getDataset();
  32 + if (_touchDisabled(e, ins, 0)) return;
  33 + }
  34 + var isTouchEnded = state.isTouchEnded;
  35 + state.oldMoveDis = 0;
  36 + var touch = _getTouch(e);
  37 + var loading = _isTrue(dataset.loading);
  38 + state.startY = touch.touchY;
  39 + startY = state.startY;
  40 + state.lastTouch = touch;
  41 + if (!loading && isTouchEnded) {
  42 + state.isTouchmoving = false;
  43 + }
  44 + state.isTouchEnded = false;
  45 + ownerIns.callMethod('_handleRefresherTouchstart', touch);
  46 +}
  47 +
  48 +function touchmove(e, ownerIns) {
  49 + var touch = _getTouch(e);
  50 + var ins = _getIns(ownerIns);
  51 + var dataset = ins.getDataset();
  52 + var refresherThreshold = dataset.refresherthreshold;
  53 + var isIos = _isTrue(dataset.isios);
  54 + var state = ins.getState();
  55 + var watchTouchDirectionChange = _isTrue(dataset.watchtouchdirectionchange);
  56 + var moveDisObj = {};
  57 + var moveDis = 0;
  58 + var prevent = false;
  59 + if (watchTouchDirectionChange) {
  60 + moveDisObj = _getMoveDis(e, ins);
  61 + moveDis = moveDisObj.currentDis;
  62 + prevent = moveDisObj.isDown;
  63 + var direction = prevent ? 'top' : 'bottom';
  64 + if (prevent == state.oldTouchDirection && prevent != state.oldEmitedTouchDirection) {
  65 + ownerIns.callMethod('_handleTouchDirectionChange', { direction: direction });
  66 + state.oldEmitedTouchDirection = prevent;
  67 + }
  68 + state.oldTouchDirection = prevent;
  69 + }
  70 + if (_touchDisabled(e, ins, 1)) {
  71 + _handlePullingDown(state, ownerIns, false);
  72 + return true;
  73 + }
  74 + if (!_getAngleIsInRange(e, touch, state, dataset)) {
  75 + _handlePullingDown(state, ownerIns, false);
  76 + return true;
  77 + }
  78 + moveDisObj = _getMoveDis(e, ins);
  79 + moveDis = moveDisObj.currentDis;
  80 + prevent = moveDisObj.isDown;
  81 + if (moveDis < 0) {
  82 + _setTransformValue(0, ins, state, false);
  83 + _handlePullingDown(state, ownerIns, false);
  84 + return true;
  85 + }
  86 + if (prevent && !state.disabledBounce) {
  87 + ownerIns.callMethod('_handleScrollViewDisableBounce', {bounce: false});
  88 + state.disabledBounce = true;
  89 + _handlePullingDown(state, ownerIns, prevent);
  90 + return !prevent;
  91 + }
  92 + _setTransformValue(moveDis, ins, state, false);
  93 + var oldRefresherStatus = state.refresherStatus;
  94 + var oldIsTouchmoving = _isTrue(dataset.oldistouchmoving);
  95 + var hasTouchmove = _isTrue(dataset.hastouchmove);
  96 + var isTouchmoving = state.isTouchmoving;
  97 + state.refresherStatus = moveDis >= refresherThreshold ? 1 : 0;
  98 + if (!isTouchmoving) {
  99 + state.isTouchmoving = true;
  100 + isTouchmoving = true;
  101 + }
  102 + if (state.isTouchEnded) {
  103 + state.isTouchEnded = false;
  104 + }
  105 + if (hasTouchmove) {
  106 + ownerIns.callMethod('_handleWxsPullingDown', { moveDis:moveDis, diffDis:moveDisObj.diffDis });
  107 + }
  108 + if (oldRefresherStatus == undefined || oldRefresherStatus != state.refresherStatus || oldIsTouchmoving != isTouchmoving) {
  109 + ownerIns.callMethod('_handleRefresherTouchmove', moveDis, touch);
  110 + }
  111 + _handlePullingDown(state, ownerIns, prevent);
  112 + return !prevent;
  113 +}
  114 +
  115 +function touchend(e, ownerIns) {
  116 + var touch = _getTouch(e);
  117 + var ins = _getIns(ownerIns);
  118 + var dataset = ins.getDataset();
  119 + var state = ins.getState();
  120 + if (_touchDisabled(e, ins, 2)) return;
  121 + state.reachMaxAngle = true;
  122 + state.hitReachMaxAngleCount = 0;
  123 + state.disabledBounce = false;
  124 + state.fixedIsTopHitCount = 0;
  125 + if (!state.isTouchmoving) return;
  126 + var oldRefresherStatus = state.refresherStatus;
  127 + var oldMoveDis = state.moveDis;
  128 + var refresherThreshold = ins.getDataset().refresherthreshold
  129 + var moveDis = _getMoveDis(e, ins).currentDis;
  130 + if (!(moveDis >= refresherThreshold && oldRefresherStatus === 1)) {
  131 + state.isTouchmoving = false;
  132 + }
  133 + ownerIns.callMethod('_handleRefresherTouchend', moveDis);
  134 + state.isTouchEnded = true;
  135 + if (oldMoveDis < refresherThreshold) return;
  136 + var animate = false;
  137 + if (moveDis >= refresherThreshold) {
  138 + moveDis = refresherThreshold;
  139 + animate = true;
  140 + }
  141 + _setTransformValue(moveDis, ins, state, animate);
  142 +}
  143 +
  144 +// #ifdef H5
  145 +function isPC() {
  146 + if (!navigator) return false;
  147 + if (isPCFlag != -1) return isPCFlag;
  148 + var agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
  149 + isPCFlag = agents.every(function(item) { return navigator.userAgent.indexOf(item) < 0 });
  150 + return isPCFlag;
  151 +}
  152 +
  153 +var movable = false;
  154 +
  155 +function mousedown(e, ins) {
  156 + if (!isPC()) return;
  157 + touchstart(e, ins);
  158 + movable = true;
  159 +}
  160 +
  161 +function mousemove(e, ins) {
  162 + if (!isPC() || !movable) return;
  163 + touchmove(e, ins);
  164 +}
  165 +
  166 +function mouseup(e, ins) {
  167 + if (!isPC()) return;
  168 + touchend(e, ins);
  169 + movable = false;
  170 +}
  171 +
  172 +function mouseleave(e, ins) {
  173 + if (!isPC()) return;
  174 + movable = false;
  175 +}
  176 +// #endif
  177 +
  178 +
  179 +function _setTransformValue(value, ins, state, animate) {
  180 + value = value || 0;
  181 + if (state.moveDis == value) return;
  182 + state.moveDis = value;
  183 + _setTransform('translateY(' + value + 'px)', ins, animate, '');
  184 +}
  185 +
  186 +function _setTransform(transform, ins, animate, transition) {
  187 + var dataset = ins.getDataset();
  188 + if (_isTrue(dataset.refreshernotransform)) return;
  189 + transform = transform == 'translateY(0px)' ? 'none' : transform;
  190 + ins.requestAnimationFrame(function() {
  191 + var stl = { 'transform': transform };
  192 + if (animate) {
  193 + stl['transition'] = 'transform .1s linear';
  194 + }
  195 + if (transition.length) {
  196 + stl['transition'] = transition;
  197 + }
  198 + ins.setStyle(stl);
  199 + })
  200 +}
  201 +
  202 +function _getMoveDis(e, ins) {
  203 + var state = ins.getState();
  204 + var refresherThreshold = parseFloat(ins.getDataset().refresherthreshold);
  205 + var refresherOutRate = parseFloat(ins.getDataset().refresheroutrate);
  206 + var refresherPullRate = parseFloat(ins.getDataset().refresherpullrate);
  207 + var touch = _getTouch(e);
  208 + var currentStartY = !state.startY || state.startY == 'NaN' ? startY : state.startY;
  209 + var moveDis = touch.touchY - currentStartY;
  210 + var oldMoveDis = state.oldMoveDis || 0;
  211 + state.oldMoveDis = moveDis;
  212 + var diffDis = moveDis - oldMoveDis;
  213 + if (diffDis > 0) {
  214 + diffDis = diffDis * refresherPullRate;
  215 + if (currentDis > refresherThreshold) {
  216 + diffDis = diffDis * (1 - refresherOutRate);
  217 + }
  218 + }
  219 + diffDis = diffDis > 100 ? diffDis / 100 : (diffDis > 20 ? diffDis / 1.2 : diffDis);
  220 + currentDis += diffDis;
  221 + currentDis = Math.max(0, currentDis);
  222 + return {
  223 + currentDis: currentDis,
  224 + diffDis: diffDis,
  225 + isDown: diffDis > 0
  226 + };
  227 +}
  228 +
  229 +function _getTouch(e) {
  230 + var touch = e;
  231 + if (e.touches && e.touches.length) {
  232 + touch = e.touches[0];
  233 + } else if (e.changedTouches && e.changedTouches.length) {
  234 + touch = e.changedTouches[0];
  235 + } else if (e.datail && e.datail != {}) {
  236 + touch = e.datail;
  237 + }
  238 + return {
  239 + touchX: touch.clientX,
  240 + touchY: touch.clientY
  241 + };
  242 +}
  243 +
  244 +function _getIns(ownerIns) {
  245 + var ins = ownerIns.getState().currentIns;
  246 + if (!ins) {
  247 + ownerIns.callMethod('_handlePropUpdate');
  248 + }
  249 + return ins;
  250 +}
  251 +
  252 +function _touchDisabled(e, ins, processTag) {
  253 + var dataset = ins.getDataset();
  254 + var state = ins.getState();
  255 + var loading = _isTrue(dataset.loading);
  256 + var useChatRecordMode = _isTrue(dataset.usechatrecordmode);
  257 + var refresherEnabled = _isTrue(dataset.refresherenabled);
  258 + var useCustomRefresher = _isTrue(dataset.usecustomrefresher);
  259 + var usePageScroll = _isTrue(dataset.usepagescroll);
  260 + var pageScrollTop = parseFloat(dataset.pagescrolltop);
  261 + var scrollTop = parseFloat(dataset.scrolltop);
  262 + var finalScrollTop = usePageScroll ? pageScrollTop : scrollTop;
  263 + var fixedIsTop = false;
  264 + var isIos = _isTrue(dataset.isios);
  265 + if (!isIos && finalScrollTop == (state.startScrollTop || 0) && finalScrollTop <= 105) {
  266 + fixedIsTop = true;
  267 + }
  268 + var fixedIsTopHitCount = state.fixedIsTopHitCount || 0;
  269 + if (fixedIsTop) {
  270 + fixedIsTopHitCount ++;
  271 + if (fixedIsTopHitCount <= 2) {
  272 + fixedIsTop = false;
  273 + }
  274 + state.fixedIsTopHitCount = fixedIsTopHitCount;
  275 + } else {
  276 + state.fixedIsTopHitCount = 0;
  277 + }
  278 + if (!isIos && processTag === 0) {
  279 + state.startScrollTop = finalScrollTop || 0;
  280 + }
  281 + if (!isIos && processTag === 2) {
  282 + fixedIsTop = true;
  283 + }
  284 + return loading || useChatRecordMode || !refresherEnabled || !useCustomRefresher ||
  285 + ((usePageScroll && useCustomRefresher && pageScrollTop > 5) && !fixedIsTop) ||
  286 + ((!usePageScroll && useCustomRefresher && scrollTop > 5) && !fixedIsTop);
  287 +}
  288 +
  289 +function _getAngleIsInRange(e, touch, state, dataset) {
  290 + var maxAngle = dataset.refreshermaxangle;
  291 + var refresherAecc = _isTrue(dataset.refresheraecc);
  292 + var lastTouch = state.lastTouch;
  293 + var reachMaxAngle = state.reachMaxAngle;
  294 + var moveDis = state.oldMoveDis;
  295 + if (!lastTouch) return true;
  296 + if (maxAngle >= 0 && maxAngle <= 90 && lastTouch) {
  297 + if ((!moveDis || moveDis < 1) && !refresherAecc && reachMaxAngle != null && !reachMaxAngle) return false;
  298 + var x = Math.abs(touch.touchX - lastTouch.touchX);
  299 + var y = Math.abs(touch.touchY - lastTouch.touchY);
  300 + var z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
  301 + if ((x || y) && x > 1) {
  302 + var angle = Math.asin(y / z) / Math.PI * 180;
  303 + if (angle < maxAngle) {
  304 + var hitReachMaxAngleCount = state.hitReachMaxAngleCount || 0;
  305 + state.hitReachMaxAngleCount = ++hitReachMaxAngleCount;
  306 + if (state.hitReachMaxAngleCount > 2) {
  307 + state.lastTouch = touch;
  308 + state.reachMaxAngle = false;
  309 + }
  310 + return false;
  311 + }
  312 + }
  313 + }
  314 + state.lastTouch = touch;
  315 + return true;
  316 +}
  317 +
  318 +function _handlePullingDown(state, ins, onPullingDown) {
  319 + var oldOnPullingDown = state.onPullingDown || false;
  320 + if (oldOnPullingDown != onPullingDown) {
  321 + ins.callMethod('_handleWxsPullingDownStatusChange', onPullingDown);
  322 + }
  323 + state.onPullingDown = onPullingDown;
  324 +}
  325 +
  326 +function _isTrue(value) {
  327 + value = (typeof(value) === 'string' ? JSON.parse(value) : value) || false;
  328 + return value == true || value == 'true';
  329 +}
  330 +
  331 +module.exports = {
  332 + touchstart: touchstart,
  333 + touchmove: touchmove,
  334 + touchend: touchend,
  335 + mousedown: mousedown,
  336 + mousemove: mousemove,
  337 + mouseup: mouseup,
  338 + mouseleave: mouseleave,
  339 + propObserver: propObserver
  340 +}
... ...
garbage-removal/src/components/z-paging/z-paging.vue 0 → 100644
  1 + <!-- _
  2 + ____ _ __ __ _ __ _(_)_ __ __ _
  3 + |_ /____| '_ \ / _` |/ _` | | '_ \ / _` |
  4 + / /_____| |_) | (_| | (_| | | | | | (_| |
  5 + /___| | .__/ \__,_|\__, |_|_| |_|\__, |
  6 + |_| |___/ |___/
  7 +v2.6.2 (2023-10-31)
  8 +by ZXLee
  9 +-->
  10 +<!-- 文档地址:https://z-paging.zxlee.cn -->
  11 +<!-- github地址:https://github.com/SmileZXLee/uni-z-paging -->
  12 +<!-- dcloud地址:https://ext.dcloud.net.cn/plugin?id=3935 -->
  13 +<!-- 反馈QQ群:790460711(已满)、371624008 -->
  14 +
  15 +<template name="z-paging">
  16 + <!-- #ifndef APP-NVUE -->
  17 + <view :class="{'z-paging-content':true,'z-paging-content-fixed':!usePageScroll&&fixed,'z-paging-content-page':usePageScroll,'z-paging-reached-top':renderPropScrollTop<1}" :style="[finalPagingStyle]">
  18 + <!-- #ifndef APP-PLUS -->
  19 + <view v-if="cssSafeAreaInsetBottom===-1" class="zp-safe-area-inset-bottom"></view>
  20 + <!-- #endif -->
  21 + <!-- 顶部固定的slot -->
  22 + <slot v-if="!usePageScroll&&zSlots.top" name="top" />
  23 + <view class="zp-page-top" @touchmove.stop.prevent v-else-if="usePageScroll&&zSlots.top" :style="[{'top':`${windowTop}px`,'z-index':topZIndex}]">
  24 + <slot name="top" />
  25 + </view>
  26 + <view :class="{'zp-view-super':true,'zp-scroll-view-super':!usePageScroll}" :style="[finalScrollViewStyle]">
  27 + <view v-if="zSlots.left" :class="{'zp-page-left':true,'zp-absoulte':finalIsOldWebView}">
  28 + <slot name="left" />
  29 + </view>
  30 + <view :class="{'zp-scroll-view-container':true,'zp-absoulte':finalIsOldWebView}" :style="[scrollViewContainerStyle]">
  31 + <scroll-view
  32 + ref="zp-scroll-view" :class="{'zp-scroll-view':true,'zp-scroll-view-absolute':!usePageScroll,'zp-scroll-view-hide-scrollbar':!showScrollbar}"
  33 + :scroll-top="scrollTop" :scroll-x="scrollX"
  34 + :scroll-y="scrollable&&!usePageScroll&&scrollEnable&&(refresherCompleteScrollable?true:refresherStatus!==R.Complete)" :enable-back-to-top="finalEnableBackToTop"
  35 + :show-scrollbar="showScrollbar" :scroll-with-animation="finalScrollWithAnimation"
  36 + :scroll-into-view="scrollIntoView" :lower-threshold="finalLowerThreshold" :upper-threshold="5"
  37 + :refresher-enabled="finalRefresherEnabled&&!useCustomRefresher" :refresher-threshold="finalRefresherThreshold"
  38 + :refresher-default-style="finalRefresherDefaultStyle" :refresher-background="refresherBackground"
  39 + :refresher-triggered="finalRefresherTriggered" @scroll="_scroll" @scrolltolower="_onScrollToLower"
  40 + @scrolltoupper="_onScrollToUpper" @refresherrestore="_onRestore" @refresherrefresh="_onRefresh(true)"
  41 + >
  42 + <view class="zp-paging-touch-view"
  43 + <!-- #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5 -->
  44 + @touchstart="_refresherTouchstart" @touchmove="_refresherTouchmove" @touchend="_refresherTouchend" @touchcancel="_refresherTouchend"
  45 + <!-- #endif -->
  46 + <!-- #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5 -->
  47 + @touchstart="pagingWxs.touchstart" @touchmove="pagingWxs.touchmove" @touchend="pagingWxs.touchend" @touchcancel="pagingWxs.touchend"
  48 + @mousedown="pagingWxs.mousedown" @mousemove="pagingWxs.mousemove" @mouseup="pagingWxs.mouseup" @mouseleave="pagingWxs.mouseleave"
  49 + <!-- #endif -->
  50 + >
  51 + <view v-if="finalRefresherFixedBacHeight>0" class="zp-fixed-bac-view" :style="[{'background': refresherFixedBackground,'height': `${finalRefresherFixedBacHeight}px`}]"></view>
  52 + <view class="zp-paging-main" :style="[scrollViewInStyle,{'transform': finalRefresherTransform,'transition': refresherTransition}]"
  53 + <!-- #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5 -->
  54 + :change:prop="pagingWxs.propObserver" :prop="wxsPropType"
  55 + :data-refresherThreshold="finalRefresherThreshold" :data-isIos="isIos"
  56 + :data-loading="loading||isRefresherInComplete" :data-useChatRecordMode="useChatRecordMode"
  57 + :data-refresherEnabled="refresherEnabled" :data-useCustomRefresher="useCustomRefresher" :data-pageScrollTop="wxsPageScrollTop"
  58 + :data-scrollTop="wxsScrollTop" :data-refresherMaxAngle="refresherMaxAngle" :data-refresherNoTransform="refresherNoTransform"
  59 + :data-refresherAecc="refresherAngleEnableChangeContinued" :data-usePageScroll="usePageScroll" :data-watchTouchDirectionChange="watchTouchDirectionChange"
  60 + :data-oldIsTouchmoving="isTouchmoving" :data-refresherOutRate="finalRefresherOutRate" :data-refresherPullRate="finalRefresherPullRate" :data-hasTouchmove="hasTouchmove"
  61 + <!-- #endif -->
  62 + <!-- #ifdef APP-VUE || H5 -->
  63 + :change:renderPropIsIosAndH5="pagingRenderjs.renderPropIsIosAndH5Change" :renderPropIsIosAndH5="isIosAndH5"
  64 + <!-- #endif -->
  65 + >
  66 + <view v-if="showRefresher" class="zp-custom-refresher-view" :style="[{'margin-top': `-${finalRefresherThreshold+refresherThresholdUpdateTag}px`,'background': refresherBackground,'opacity': isTouchmoving ? 1 : 0}]">
  67 + <view class="zp-custom-refresher-container" :style="[{'height': `${finalRefresherThreshold}px`,'background': refresherBackground}]">
  68 + <view v-if="useRefresherStatusBarPlaceholder" class="zp-custom-refresher-status-bar-placeholder" :style="[{'height': `${statusBarHeight}px`}]" />
  69 + <!-- 下拉刷新view -->
  70 + <view class="zp-custom-refresher-slot-view">
  71 + <slot v-if="!(zSlots.refresherComplete&&refresherStatus===R.Complete)" :refresherStatus="refresherStatus" name="refresher" />
  72 + </view>
  73 + <slot v-if="zSlots.refresherComplete&&refresherStatus===R.Complete" name="refresherComplete" />
  74 + <z-paging-refresh ref="refresh" v-else-if="!showCustomRefresher" class="zp-custom-refresher-refresh" :style="[{'height': `${finalRefresherThreshold - finalRefresherThresholdPlaceholder}px`}]" :status="refresherStatus"
  75 + :defaultThemeStyle="finalRefresherThemeStyle" :defaultText="finalRefresherDefaultText"
  76 + :pullingText="finalRefresherPullingText" :refreshingText="finalRefresherRefreshingText" :completeText="finalRefresherCompleteText"
  77 + :defaultImg="refresherDefaultImg" :pullingImg="refresherPullingImg" :refreshingImg="refresherRefreshingImg" :completeImg="refresherCompleteImg" :refreshingAnimated="refresherRefreshingAnimated"
  78 + :showUpdateTime="showRefresherUpdateTime" :updateTimeKey="refresherUpdateTimeKey" :updateTimeTextMap="finalRefresherUpdateTimeTextMap"
  79 + :imgStyle="refresherImgStyle" :titleStyle="refresherTitleStyle" :updateTimeStyle="refresherUpdateTimeStyle" />
  80 + </view>
  81 + </view>
  82 + <view class="zp-paging-container">
  83 + <slot v-if="useChatRecordMode&&zSlots.chatLoading&&loadingStatus!==M.NoMore&&realTotalData.length" name="chatLoading" />
  84 + <view v-else-if="useChatRecordMode&&loadingStatus!==M.NoMore&&realTotalData.length" class="zp-chat-record-loading-container">
  85 + <text v-if="loadingStatus!==M.Loading" @click="_onScrollToUpper"
  86 + :class="defaultThemeStyle==='white'?'zp-loading-more-text zp-loading-more-text-white':'zp-loading-more-text zp-loading-more-text-black'">{{chatRecordLoadingMoreText}}</text>
  87 + <image v-else :src="base64Flower" class="zp-chat-record-loading-custom-image" />
  88 + </view>
  89 + <!-- 全屏Loading -->
  90 + <slot v-if="showLoading&&zSlots.loading&&!loadingFullFixed" name="loading" />
  91 + <!-- 主体内容 -->
  92 + <view class="zp-paging-container-content" :style="[{transform:virtualPlaceholderTopHeight>0?`translateY(${virtualPlaceholderTopHeight}px)`:'none'},finalPagingContentStyle]">
  93 + <slot />
  94 + <!-- 内置列表&虚拟列表 -->
  95 + <template v-if="finalUseInnerList">
  96 + <slot name="header"/>
  97 + <view class="zp-list-container" :style="[innerListStyle]">
  98 + <template v-if="finalUseVirtualList">
  99 + <view class="zp-list-cell" :style="[innerCellStyle]" :id="`zp-id-${item[virtualCellIndexKey]}`" v-for="(item,index) in virtualList" :key="item['zp_unique_index']" @click="_innerCellClick(item,virtualTopRangeIndex+index)">
  100 + <view v-if="useCompatibilityMode">使用兼容模式请在组件源码z-paging.vue第100行中注释这一行,并打开下面一行注释</view>
  101 + <!-- <zp-public-virtual-cell v-if="useCompatibilityMode" :extraData="extraData" :item="item" :index="virtualTopRangeIndex+index" /> -->
  102 + <slot v-else name="cell" :item="item" :index="virtualTopRangeIndex+index"/>
  103 + </view>
  104 + </template>
  105 + <template v-else>
  106 + <view class="zp-list-cell" v-for="(item,index) in realTotalData" :key="index" @click="_innerCellClick(item,index)">
  107 + <slot name="cell" :item="item" :index="index"/>
  108 + </view>
  109 + </template>
  110 + </view>
  111 + <slot name="footer"/>
  112 + </template>
  113 + <view v-if="useVirtualList" class="zp-virtual-placeholder" :style="[{height:virtualPlaceholderBottomHeight+'px'}]"/>
  114 + <!-- 上拉加载更多view -->
  115 + <!-- #ifndef MP-ALIPAY -->
  116 + <slot v-if="showLoadingMoreDefault" name="loadingMoreDefault" />
  117 + <slot v-else-if="showLoadingMoreLoading" name="loadingMoreLoading" />
  118 + <slot v-else-if="showLoadingMoreNoMore" name="loadingMoreNoMore" />
  119 + <slot v-else-if="showLoadingMoreFail" name="loadingMoreFail" />
  120 + <z-paging-load-more @doClick="_onLoadingMore('click')" v-else-if="showLoadingMoreCustom" :zConfig="zLoadMoreConfig" />
  121 + <!-- #endif -->
  122 + <!-- #ifdef MP-ALIPAY -->
  123 + <slot v-if="loadingStatus===M.Default&&zSlots.loadingMoreDefault&&showLoadingMore&&loadingMoreEnabled&&!useChatRecordMode" name="loadingMoreDefault" />
  124 + <slot v-else-if="loadingStatus===M.Loading&&zSlots.loadingMoreLoading&&showLoadingMore&&loadingMoreEnabled" name="loadingMoreLoading" />
  125 + <slot v-else-if="loadingStatus===M.NoMore&&zSlots.loadingMoreNoMore&&showLoadingMore&&showLoadingMoreNoMoreView&&loadingMoreEnabled&&!useChatRecordMode" name="loadingMoreNoMore" />
  126 + <slot v-else-if="loadingStatus===M.Fail&&zSlots.loadingMoreFail&&showLoadingMore&&loadingMoreEnabled&&!useChatRecordMode" name="loadingMoreFail" />
  127 + <z-paging-load-more @doClick="_onLoadingMore('click')" v-else-if="showLoadingMore&&showDefaultLoadingMoreText&&!(loadingStatus===M.NoMore&&!showLoadingMoreNoMoreView)&&loadingMoreEnabled&&!useChatRecordMode" :zConfig="zLoadMoreConfig" />
  128 + <!-- #endif -->
  129 + <view v-if="safeAreaInsetBottom&&useSafeAreaPlaceholder" class="zp-safe-area-placeholder" :style="[{height:safeAreaBottom+'px'}]" />
  130 + </view>
  131 + <!-- 空数据图 -->
  132 + <view v-if="showEmpty" :class="{'zp-empty-view':true,'zp-empty-view-center':emptyViewCenter}" :style="[emptyViewSuperStyle]">
  133 + <slot v-if="zSlots.empty" name="empty" :isLoadFailed="isLoadFailed"/>
  134 + <z-paging-empty-view v-else :emptyViewImg="finalEmptyViewImg" :emptyViewText="finalEmptyViewText" :showEmptyViewReload="finalShowEmptyViewReload"
  135 + :emptyViewReloadText="finalEmptyViewReloadText" :isLoadFailed="isLoadFailed" :emptyViewStyle="emptyViewStyle" :emptyViewTitleStyle="emptyViewTitleStyle"
  136 + :emptyViewImgStyle="emptyViewImgStyle" :emptyViewReloadStyle="emptyViewReloadStyle" :emptyViewZIndex="emptyViewZIndex" :emptyViewFixed="emptyViewFixed"
  137 + @reload="_emptyViewReload" @viewClick="_emptyViewClick" />
  138 + </view>
  139 + </view>
  140 + </view>
  141 + </view>
  142 + </scroll-view>
  143 + </view>
  144 + <view v-if="zSlots.right" :class="{'zp-page-right':true,'zp-absoulte zp-right':finalIsOldWebView}">
  145 + <slot name="right" />
  146 + </view>
  147 + </view>
  148 + <!-- 底部固定的slot -->
  149 + <slot v-if="!usePageScroll&&zSlots.bottom" name="bottom" />
  150 + <view class="zp-page-bottom" @touchmove.stop.prevent v-else-if="usePageScroll&&zSlots.bottom" :style="[{'bottom': `${windowBottom}px`}]">
  151 + <slot name="bottom" />
  152 + </view>
  153 + <!-- 点击返回顶部view -->
  154 + <view v-if="showBackToTopClass" :class="backToTopClass" :style="[finalBackToTopStyle]" @click.stop="_backToTopClick">
  155 + <slot v-if="zSlots.backToTop" name="backToTop" />
  156 + <image v-else class="zp-back-to-top-img" :src="backToTopImg.length?backToTopImg:base64BackToTop" />
  157 + </view>
  158 + <!-- 全屏Loading(铺满z-paging并固定) -->
  159 + <view v-if="showLoading&&zSlots.loading&&loadingFullFixed" class="zp-loading-fixed">
  160 + <slot name="loading" />
  161 + </view>
  162 + </view>
  163 + <!-- #endif -->
  164 + <!-- #ifdef APP-NVUE -->
  165 + <component :is="finalNvueSuperListIs" :style="[finalPagingStyle]" :class="{'z-paging-content-fixed':fixed&&!usePageScroll}" :scrollable="false">
  166 + <!-- 顶部固定的slot -->
  167 + <view ref="zp-page-top" v-if="zSlots.top" :class="{'zp-page-top':usePageScroll}" :style="[usePageScroll?{'top':`${windowTop}px`,'z-index':topZIndex}:{}]">
  168 + <slot name="top" />
  169 + </view>
  170 + <component :is="finalNvueSuperListIs" class="zp-n-list-container" :scrollable="false">
  171 + <view v-if="zSlots.left" class="zp-page-left">
  172 + <slot name="left" />
  173 + </view>
  174 + <component :is="finalNvueListIs" ref="zp-n-list" :id="nvueListId" :style="[{'flex': 1,'top':isIos?'0px':'-1px'},usePageScroll?scrollViewStyle:{},nChatRecordRotateStyle]" :alwaysScrollableVertical="true"
  175 + :fixFreezing="nFixFreezing" :show-scrollbar="showScrollbar&&!useChatRecordMode" :loadmoreoffset="finalLowerThreshold" :enable-back-to-top="enableBackToTop"
  176 + :scrollable="scrollable&&scrollEnable&&(refresherCompleteScrollable?true:refresherStatus!==R.Complete)" :bounce="nvueBounce" :column-count="nWaterfallColumnCount" :column-width="nWaterfallColumnWidth"
  177 + :column-gap="nWaterfallColumnGap" :left-gap="nWaterfallLeftGap" :right-gap="nWaterfallRightGap" :pagingEnabled="nvuePagingEnabled" :offset-accuracy="offsetAccuracy"
  178 + @loadmore="_nOnLoadmore" @scroll="_nOnScroll">
  179 + <refresh v-if="(zSlots.top?cacheTopHeight!==-1:true)&&finalNvueRefresherEnabled" class="zp-n-refresh" :style="[nvueRefresherStyle]" :display="nRefresherLoading?'show':'hide'" @refresh="_nOnRrefresh" @pullingdown="_nOnPullingdown">
  180 + <view ref="zp-n-refresh-container" class="zp-n-refresh-container" :style="[{background:refresherBackground,width:nRefresherWidth}]" id="zp-n-refresh-container">
  181 + <view v-if="useRefresherStatusBarPlaceholder" class="zp-custom-refresher-status-bar-placeholder" :style="[{'height': `${statusBarHeight}px`}]" />
  182 + <!-- 下拉刷新view -->
  183 + <slot v-if="zSlots.refresherComplete&&refresherStatus===R.Complete" name="refresherComplete" />
  184 + <slot v-else-if="(nScopedSlots?nScopedSlots:zSlots).refresher" :refresherStatus="refresherStatus" name="refresher" />
  185 + <z-paging-refresh ref="refresh" v-else :status="refresherStatus" :defaultThemeStyle="finalRefresherThemeStyle"
  186 + :defaultText="finalRefresherDefaultText" :pullingText="finalRefresherPullingText" :refreshingText="finalRefresherRefreshingText" :completeText="finalRefresherCompleteText"
  187 + :defaultImg="refresherDefaultImg" :pullingImg="refresherPullingImg" :refreshingImg="refresherRefreshingImg" :completeImg="refresherCompleteImg" :refreshingAnimated="refresherRefreshingAnimated"
  188 + :showUpdateTime="showRefresherUpdateTime" :updateTimeKey="refresherUpdateTimeKey" :updateTimeTextMap="finalRefresherUpdateTimeTextMap"
  189 + :imgStyle="refresherImgStyle" :titleStyle="refresherTitleStyle" :updateTimeStyle="refresherUpdateTimeStyle" />
  190 + </view>
  191 + </refresh>
  192 + <component :is="nViewIs" v-if="isIos&&!useChatRecordMode?oldScrollTop>10:true" ref="zp-n-list-top-tag" class="zp-n-list-top-tag" style="margin-top: -1rpx;" :style="[{height:finalNvueRefresherEnabled?'0px':'1px'}]"></component>
  193 + <component :is="nViewIs" v-if="nShowRefresherReveal" ref="zp-n-list-refresher-reveal" :style="[{transform:`translateY(-${nShowRefresherRevealHeight}px)`},{background:refresherBackground}]">
  194 + <view v-if="useRefresherStatusBarPlaceholder" class="zp-custom-refresher-status-bar-placeholder" :style="[{'height': `${statusBarHeight}px`}]" />
  195 + <!-- 下拉刷新view -->
  196 + <slot v-if="zSlots.refresherComplete&&refresherStatus===R.Complete" name="refresherComplete" />
  197 + <slot v-else-if="(nScopedSlots?nScopedSlots:$slots).refresher" :refresherStatus="R.Loading" name="refresher" />
  198 + <z-paging-refresh ref="refresh" v-else :status="R.Loading" :defaultThemeStyle="finalRefresherThemeStyle"
  199 + :defaultText="finalRefresherDefaultText" :pullingText="finalRefresherPullingText" :refreshingText="finalRefresherRefreshingText" :completeText="finalRefresherCompleteText"
  200 + :defaultImg="refresherDefaultImg" :pullingImg="refresherPullingImg" :refreshingImg="refresherRefreshingImg" :completeImg="refresherCompleteImg" :refreshingAnimated="refresherRefreshingAnimated"
  201 + :showUpdateTime="showRefresherUpdateTime" :updateTimeKey="refresherUpdateTimeKey" :updateTimeTextMap="finalRefresherUpdateTimeTextMap"
  202 + :imgStyle="refresherImgStyle" :titleStyle="refresherTitleStyle" :updateTimeStyle="refresherUpdateTimeStyle" />
  203 + </component>
  204 + <template v-if="finalUseInnerList">
  205 + <component :is="nViewIs">
  206 + <slot name="header"/>
  207 + </component>
  208 + <component :is="nViewIs" class="zp-list-cell" v-for="(item,index) in realTotalData" :key="finalCellKeyName.length?item[finalCellKeyName]:index">
  209 + <slot name="cell" :item="item" :index="index"/>
  210 + </component>
  211 + <component :is="nViewIs">
  212 + <slot name="footer"/>
  213 + </component>
  214 + </template>
  215 + <template v-else>
  216 + <slot />
  217 + </template>
  218 + <!-- 全屏Loading -->
  219 + <component :is="nViewIs" v-if="showLoading&&zSlots.loading&&!loadingFullFixed" :class="{'z-paging-content-fixed':usePageScroll}" style="flex:1" :style="[nChatRecordRotateStyle]">
  220 + <slot name="loading" />
  221 + </component>
  222 + <!-- 上拉加载更多view -->
  223 + <component :is="nViewIs" v-if="!refresherOnly&&loadingMoreEnabled&&!showEmpty">
  224 + <view v-if="useChatRecordMode">
  225 + <view v-if="loadingStatus!==M.NoMore&&realTotalData.length">
  226 + <slot v-if="zSlots.chatLoading" name="chatLoading" />
  227 + <view v-else class="zp-chat-record-loading-container">
  228 + <text v-if="loadingStatus!==M.Loading" @click="_onScrollToUpper"
  229 + :class="defaultThemeStyle==='white'?'zp-loading-more-text zp-loading-more-text-white':'zp-loading-more-text zp-loading-more-text-black'">{{chatRecordLoadingMoreText}}</text>
  230 + <view>
  231 + <loading-indicator v-if="loadingStatus===M.Loading" class="zp-line-loading-image" animating />
  232 + </view>
  233 + </view>
  234 + </view>
  235 + </view>
  236 + <view :style="nLoadingMoreFixedHeight?{height:loadingMoreCustomStyle&&loadingMoreCustomStyle.height?loadingMoreCustomStyle.height:'80rpx'}:{}">
  237 + <slot v-if="showLoadingMoreDefault" name="loadingMoreDefault" />
  238 + <slot v-else-if="showLoadingMoreLoading" name="loadingMoreLoading" />
  239 + <slot v-else-if="showLoadingMoreNoMore" name="loadingMoreNoMore" />
  240 + <slot v-else-if="showLoadingMoreFail" name="loadingMoreFail" />
  241 + <z-paging-load-more @doClick="_onLoadingMore('click')" v-else-if="showLoadingMoreCustom" :zConfig="zLoadMoreConfig" />
  242 + <view v-if="safeAreaInsetBottom&&useSafeAreaPlaceholder" class="zp-safe-area-placeholder" :style="[{height:safeAreaBottom+'px'}]" />
  243 + </view>
  244 + </component>
  245 + <!-- 空数据图 -->
  246 + <component :is="nViewIs" v-if="showEmpty" :class="{'z-paging-content-fixed':usePageScroll}" :style="[{flex:emptyViewCenter?1:0},emptyViewSuperStyle,nChatRecordRotateStyle]">
  247 + <view :class="{'zp-empty-view':true,'zp-empty-view-center':emptyViewCenter}">
  248 + <slot v-if="zSlots.empty" name="empty" :isLoadFailed="isLoadFailed" />
  249 + <z-paging-empty-view v-else :emptyViewImg="finalEmptyViewImg" :emptyViewText="finalEmptyViewText" :showEmptyViewReload="finalShowEmptyViewReload"
  250 + :emptyViewReloadText="finalEmptyViewReloadText" :isLoadFailed="isLoadFailed" :emptyViewStyle="emptyViewStyle" :emptyViewTitleStyle="emptyViewTitleStyle"
  251 + :emptyViewImgStyle="emptyViewImgStyle" :emptyViewReloadStyle="emptyViewReloadStyle" :emptyViewZIndex="emptyViewZIndex" :emptyViewFixed="emptyViewFixed"
  252 + @reload="_emptyViewReload" @viewClick="_emptyViewClick" />
  253 + </view>
  254 + </component>
  255 + <component is="header" v-if="!hideNvueBottomTag" ref="zp-n-list-bottom-tag" class="zp-n-list-bottom-tag"></component>
  256 + </component>
  257 + <view v-if="zSlots.right" class="zp-page-right">
  258 + <slot name="right" />
  259 + </view>
  260 + </component>
  261 + <!-- 底部固定的slot -->
  262 + <slot name="bottom" />
  263 + <!-- 点击返回顶部view -->
  264 + <view v-if="showBackToTopClass" :class="backToTopClass" :style="[finalBackToTopStyle]" @click.stop="_backToTopClick">
  265 + <slot v-if="zSlots.backToTop" name="backToTop" />
  266 + <image v-else class="zp-back-to-top-img" :src="backToTopImg.length?backToTopImg:base64BackToTop" />
  267 + </view>
  268 + <!-- 全屏Loading(铺满z-paging并固定) -->
  269 + <view v-if="showLoading&&zSlots.loading&&loadingFullFixed" class="zp-loading-fixed">
  270 + <slot name="loading" />
  271 + </view>
  272 + </component>
  273 + <!-- #endif -->
  274 +</template>
  275 +<!-- #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5 -->
  276 +<script src="./wxs/z-paging-wxs.wxs" module="pagingWxs" lang="wxs"></script>
  277 +<!-- #endif -->
  278 +<script module="pagingRenderjs" lang="renderjs">
  279 + import pagingRenderjs from './wxs/z-paging-renderjs.js';
  280 + /**
  281 + * z-paging 分页组件
  282 + * @description 高性能,全平台兼容。支持虚拟列表,支持nvue、vue3
  283 + * @tutorial https://z-paging.zxlee.cn
  284 + * @notice 以下仅为部分常用属性、方法和事件,完整文档请查阅z-paging官网
  285 + * @property {Number|String} default-page-no 自定义初始的pageNo,默认为1
  286 + * @property {Number|String} default-page-size 自定义pageSize,默认为10
  287 + * @property {Object} paging-style 设置z-paging的style,部分平台(如微信小程序)无法直接修改组件的style,可使用此属性代替
  288 + * @property {String} height z-paging的高度,优先级低于pagingStyle中设置的height,传字符串,如100px、100rpx、100%
  289 + * @property {String} width z-paging的宽度,优先级低于pagingStyle中设置的width,传字符串,如100px、100rpx、100%
  290 + * @property {Boolean} use-page-scroll 使用页面滚动,默认为否
  291 + * @property {Boolean} use-virtual-list 是否使用虚拟列表,默认为否
  292 + * @property {Boolean} fixed z-paging是否使用fixed布局,若使用fixed布局,则z-paging的父view无需固定高度,z-paging高度默认为100%,默认为是(当使用内置scroll-view滚动时有效)
  293 + * @property {Boolean} auto [z-paging]mounted后是否自动调用reload方法(mounted后自动调用接口),默认为是
  294 + * @property {Boolean} use-chat-record-mode 使用聊天记录模式,默认为否
  295 + * @event {Function} query 下拉刷新或滚动到底部时会自动触发此方法。z-paging加载时也会触发(若要禁止,请设置:auto="false")。pageNo和pageSize会自动计算好,直接传给服务器即可。
  296 + * @example <z-paging ref="paging" v-model="dataList" @query="queryList"></z-paging>
  297 + */
  298 + export default {
  299 + name:"z-paging",
  300 + // #ifdef APP-VUE || H5
  301 + mixins: [pagingRenderjs],
  302 + // #endif
  303 + }
  304 +</script>
  305 +<script src="./js/z-paging-main.js" />
  306 +
  307 +<style scoped>
  308 + @import "./css/z-paging-main.css";
  309 + @import "./css/z-paging-static.css";
  310 +</style>
... ...
garbage-removal/src/pages.json
... ... @@ -51,7 +51,9 @@
51 51 },{
52 52 "path": "pages/order/index",
53 53 "style": {
54   - "navigationBarTitleText": ""
  54 + "navigationBarTitleText": "订单详情",
  55 + "navigationBarTextStyle":"white",
  56 + "navigationBarBackgroundColor":"#53c21d"
55 57 }
56 58 },{
57 59 "path": "pages/wode/index",
... ...
garbage-removal/src/pages/home/address/addSite.vue
... ... @@ -28,7 +28,7 @@
28 28 <view class="set">设置默认地址</view>
29 29 </view>
30 30 <view class="right">
31   - <u-switch v-model="addressInfo.defaultFlag" size="40" activeColor="green"></u-switch>
  31 + <u-switch v-model="addressInfo.defaultFlag" size="40" activeColor="#a9e08f"></u-switch>
32 32 </view>
33 33 </view>
34 34 </view>
... ... @@ -154,7 +154,7 @@ onMounted(() =&gt; {
154 154 position: absolute;
155 155 bottom: 30rpx;
156 156 left: 80rpx;
157   - background-color: green;
  157 + background-color: #a9e08f;
158 158 border-radius: 60rpx;
159 159 font-size: 30rpx;
160 160  
... ...
garbage-removal/src/pages/home/address/index.vue
... ... @@ -150,7 +150,7 @@ onLoad(() =&gt; {
150 150 }
151 151  
152 152 .red {
153   - background-color: green
  153 + background-color: #a9e08f
154 154 }
155 155 }
156 156 }
... ... @@ -176,7 +176,7 @@ onLoad(() =&gt; {
176 176 line-height: 100rpx;
177 177 position: absolute;
178 178 bottom: 30rpx;
179   - background-color: green;
  179 + background-color: #a9e08f;
180 180 border-radius: 60rpx;
181 181 font-size: 30rpx;
182 182  
... ...
garbage-removal/src/pages/home/clean/company-detail/index.vue
... ... @@ -33,7 +33,7 @@
33 33 <view class="company-content-car-info-title">核准车辆信息</view>
34 34 <view class="company-content-car-info-sub-title">车牌号(车型)</view>
35 35 <view class="company-content-car-info-car-list">
36   - <view v-for="item in baseDataList" class="company-content-car-info-car-list-item">
  36 + <view v-for="(item, index) in baseDataList" :key="index" class="company-content-car-info-car-list-item">
37 37 浙B5S785<text class="car-type">(自卸车)</text>
38 38 </view>
39 39 </view>
... ... @@ -74,7 +74,7 @@
74 74 </view>
75 75 </view>
76 76 <view class="company-bottom-button-right">
77   - <u-button icon="car-fill" :custom-style="customStyle" @click="handleCleanGarbage(companyId)" type="success"
  77 + <u-button icon="car-fill" :custom-style="customStyle" @click="handleCleanGarbage(companyId, tel)" type="success"
78 78 :hairline="true" size="normal" shape="circle" text="垃圾清运"></u-button>
79 79 </view>
80 80 </view>
... ... @@ -99,10 +99,10 @@ const customStyle = ref({
99 99 })
100 100 const companyId = ref()
101 101 const tel = ref()
102   -const handleCleanGarbage = (companyId) => {
  102 +const handleCleanGarbage = (companyId, tel) => {
103 103 console.log("垃圾清运");
104 104 uni.$u.route({
105   - url: `pages/home/clean/index?companyId=${companyId}`,
  105 + url: `pages/home/clean/index?companyId=${companyId}&tel=${tel}`,
106 106 })
107 107 }
108 108  
... ...
garbage-removal/src/pages/home/clean/index.vue
1 1 <template>
2 2 <view class="company-clean-container">
3   - <view class="company-clean-container-header">
4   - <view class="company-clean-container-header-address">
5   - 宁波市海曙区昱湖街道上海
6   - </view>
7   - <view class="company-clean-container-header-base-info">
8   - 李云龙 189802245165
9   - </view>
10   - <view class="company-clean-container-header-reservation">
11   - <view class="company-clean-container-header-reservation-left">
12   - <u-icon name="calendar" size="40"></u-icon>
13   - 预约时间
  3 + <view class="company-clean-container-box">
  4 + <view class="company-clean-container-header">
  5 + <view class="company-clean-container-header-address">
  6 + 宁波市海曙区昱湖街道上海
14 7 </view>
15   - <view class="company-clean-container-header-reservation-right" @click="handleTimeChoose">
16   - <text style="margin-right: 10rpx;">请选择时间</text> <u-icon name="arrow-right" size="25"></u-icon>
  8 + <view class="company-clean-container-header-base-info">
  9 + 李云龙 189802245165
  10 + </view>
  11 + <view class="company-clean-container-header-reservation">
  12 + <view class="company-clean-container-header-reservation-left">
  13 + <u-icon name="calendar" size="40"></u-icon>
  14 + 预约时间
  15 + </view>
  16 + <view class="company-clean-container-header-reservation-right" @click="handleTimeChoose">
  17 + <text style="margin-right: 10rpx;">请选择时间</text> <u-icon name="arrow-right" size="25"></u-icon>
  18 + </view>
17 19 </view>
18   - </view>
19 20  
20   - </view>
21   - <view class="company-clean-container-car-main">
22   - <view class="company-clean-container-car-main-title">
23   - 自卸车
24 21 </view>
25   - <view class="company-clean-container-car-main-content">
26   - <view class="company-clean-container-car-main-content-img">
27   - <image class="company-clean-container-car-main-content-img" />
28   - </view>
29   - <view class="company-clean-container-car-main-content-remark">
30   - 箱体长4.2m宽1.1,高0.7,最多课容纳约110袋袋装修垃圾(75cm*45每袋)
  22 + <view class="company-clean-container-car-main">
  23 + <view class="company-clean-container-car-main-title">
  24 + 自卸车
31 25 </view>
32   - <view class="company-clean-container-car-main-content-type">
33   - <view class="company-clean-container-car-main-content-type-choose">
34   - <text style="margin-right: 10rpx;">6方车</text>
35   - <u-icon name="arrow-down" size="30" color="#ffffff"></u-icon>
  26 + <view class="company-clean-container-car-main-content">
  27 + <view class="company-clean-container-car-main-content-img">
  28 + <image class="company-clean-container-car-main-content-img" />
36 29 </view>
37   - <view class="company-clean-container-car-main-content-type-price-area">
38   - $5000元/车
  30 + <view class="company-clean-container-car-main-content-remark">
  31 + 箱体长4.2m宽1.1,高0.7,最多课容纳约110袋袋装修垃圾(75cm*45每袋)
39 32 </view>
40   - </view>
41   - <view class="company-clean-container-car-main-content-number">
42   - <view class="company-clean-container-car-main-content-number-txt">
43   - 添加车辆数量
  33 + <view class="company-clean-container-car-main-content-type">
  34 + <view class="company-clean-container-car-main-content-type-choose">
  35 + <text style="margin-right: 10rpx;">6方车</text>
  36 + <u-icon name="arrow-down" size="30" color="#ffffff"></u-icon>
  37 + </view>
  38 + <view class="company-clean-container-car-main-content-type-price-area">
  39 + $5000元/车
  40 + </view>
44 41 </view>
45   - <view class="company-clean-container-car-main-content-number-button">
46   - <u-number-box :min="1" integer buttonSize="46" v-model="paramFrom.carNumber"></u-number-box>
  42 + <view class="company-clean-container-car-main-content-number">
  43 + <view class="company-clean-container-car-main-content-number-txt">
  44 + 添加车辆数量
  45 + </view>
  46 + <view class="company-clean-container-car-main-content-number-button">
  47 + <u-number-box :min="1" integer buttonSize="46" v-model="paramFrom.carNumber"></u-number-box>
  48 + </view>
  49 + </view>
  50 + <view class="company-clean-container-car-main-content-prompt">
  51 + 温馨提示:垃圾类型不符合,有权拒绝清运。
47 52 </view>
48   - </view>
49   - <view class="company-clean-container-car-main-content-prompt">
50   - 温馨提示:垃圾类型不符合,有权拒绝清运。
51 53 </view>
52 54 </view>
53   - </view>
54 55  
55   - <view class="company-clean-container-site-image-info">
56   - <view class="company-clean-container-site-image-info-remark">
57   - <text style="color: red;">*</text>现场照片(最多上传10张)
58   - </view>
59   - <view class="company-clean-container-site-image-info-img">
60   - <u-upload :fileList="fileList" @afterRead="afterRead" @delete="deletePic" name="3" multiple :maxCount="10"
61   - :previewFullImage="true"></u-upload>
62   - </view>
63   - <view class="company-clean-container-site-image-info-input-remark">
64   - 填写备注
  56 + <view class="company-clean-container-site-image-info">
  57 + <view class="company-clean-container-site-image-info-remark">
  58 + <text style="color: red;">*</text>现场照片(最多上传10张)
  59 + </view>
  60 + <view class="company-clean-container-site-image-info-img">
  61 + <u-upload :fileList="fileList" @afterRead="afterRead" @delete="deletePic" name="3" multiple :maxCount="10"
  62 + :previewFullImage="true"></u-upload>
  63 + </view>
  64 + <view class="company-clean-container-site-image-info-input-remark">
  65 + 填写备注
  66 + </view>
  67 + <view class="company-clean-container-site-image-info-input-remark-box">
  68 + <u--textarea v-model="paramFrom.remark" placeholder="请输入内容"></u--textarea>
  69 + </view>
65 70 </view>
66   - <view class="company-clean-container-site-image-info-input-remark-box">
67   - <u--textarea v-model="paramFrom.remark" placeholder="请输入内容"></u--textarea>
  71 + <view class="company-clean-container-site-image-info-sure-button">
  72 + <view class="company-clean-container-site-image-info-sure-button-radio">
  73 + <u-radio-group v-model="paramFrom.sureReadFlag">
  74 + <u-radio activeColor="#a9e08f" size="27" labelSize="25" :labelDisabled="true" labelColor="#909399"
  75 + label="本人已确认信息真实有效,并将上述信息告知市容环境卫生主管部门。"></u-radio>
  76 + </u-radio-group>
  77 + </view>
68 78 </view>
69 79 </view>
70   - <view class="company-clean-container-site-image-info-sure-button">
71   - <u-radio-group v-model="paramFrom.sureReadFlag">
72   - <u-radio :labelDisabled="true" label="本人已确认信息真实有效,并将上述信息告知市容环境卫生主管部门。"></u-radio>
73   - </u-radio-group>
  80 + <view class="company-clean-bottom">
  81 + <movable-area ref="movableAreaElement" class="movableArea">
  82 + <movable-view class="movableView" :x="x" :y="y" direction="all" @change="onChange">
  83 + <view class="company-clean-call-box-container">
  84 + <u-icon @click="handleContactClick(tel)" name="phone-fill" color="#ffffff" size="50"></u-icon>
  85 + </view>
  86 + </movable-view>
  87 + </movable-area>
  88 + <view class="company-clean-bottom-box">
  89 + <view class="company-clean-bottom-left">
  90 + <u-icon @click="handleCarInfo" :stop="true" size="50" name="car-fill"></u-icon>
  91 + </view>
  92 + <view class="company-clean-bottom-right">
  93 + <u-button @click="handleOderSure" shape="circle" color="#a9e08f" text="立即下单"></u-button>
  94 + </view>
  95 + </view>
74 96 </view>
75 97 </view>
76 98 </template>
77 99  
78 100 <script setup>
79 101 import { onLoad } from '@dcloudio/uni-app';
80   -import { ref } from 'vue';
  102 +import { getCurrentInstance, onMounted, ref } from 'vue';
  103 +const { proxy } = getCurrentInstance();
  104 +const x = ref(5)
  105 +const y = ref()
  106 +const movableAreaElement = ref()
81 107 const companyId = ref()
82   -
  108 +const tel = ref()
83 109 const paramFrom = ref({
84 110 carNumber: 0,
85 111 remark: "",
... ... @@ -93,11 +119,26 @@ const fileList = ref([{
93 119 const handleTimeChoose = () => {
94 120 console.log("选择时间");
95 121 }
  122 +/**
  123 + * 初始化信息
  124 + */
96 125 onLoad((options) => {
97   - console.log(options.companyId);
98 126 companyId.value = options.companyId;
  127 + tel.value = options.tel;
  128 + console.log("tel:", tel);
  129 +
99 130 })
100 131  
  132 +/**
  133 + * 拨打电话回调
  134 + */
  135 +const handleContactClick = (val) => {
  136 + console.log("拨打电话");
  137 + uni.makePhoneCall({ phoneNumber: val }).then(res => {
  138 + console.log(res);
  139 + }).catch(err => { });
  140 +}
  141 +
101 142 // 删除图片
102 143 const deletePic = (event) => {
103 144 fileList.value.splice(event.index, 1);
... ... @@ -146,6 +187,33 @@ const uploadFilePromise = (url) =&gt; {
146 187 });
147 188 };
148 189  
  190 +/**
  191 + * 处理车子数量
  192 + */
  193 +const handleCarInfo = () => {
  194 + console.log("车子数量");
  195 +}
  196 +
  197 +/**
  198 + * 处理下单
  199 + */
  200 +const handleOderSure = () => {
  201 + console.log("下单了");
  202 +}
  203 +
  204 +onMounted(() => {
  205 + let areaHeight;
  206 + // select中的参数就如css选择器一样选择元素
  207 + let movableArea = uni.createSelectorQuery().in(proxy).select(".movableArea");
  208 + movableArea.boundingClientRect(function (data) {
  209 + // data - 包含元素的高度等信息
  210 + console.log("area:", data.height) // 获取元素宽度
  211 + areaHeight = data.height;
  212 + y.value = areaHeight;
  213 + }).exec(function (res) {
  214 + // 注意:exec方法必须执行,即便什么也不做,否则不会获取到任何数据
  215 + })
  216 +})
149 217  
150 218 </script>
151 219  
... ... @@ -153,179 +221,257 @@ const uploadFilePromise = (url) =&gt; {
153 221 $custom-marin-bottom: 20rpx;
154 222 $custom-page-padding: 20rpx;
155 223 $custom-border-radio: 20rpx;
  224 +$custom-bottom-height: 200rpx;
156 225  
157 226 .company-clean-container {
158 227 height: 100%;
159 228 width: 100%;
160 229 background-color: $u-info-light;
161   - padding: $custom-page-padding;
162 230 box-sizing: border-box;
  231 + overflow-y: scroll;
163 232  
164   - .company-clean-container-header {
  233 +
  234 + .company-clean-container-box {
  235 + height: 100%;
  236 + width: 100%;
165 237 padding: $custom-page-padding;
166 238 box-sizing: border-box;
167   - background-color: #ffffff;
168   - border-radius: $custom-border-radio;
169   - margin-bottom: $custom-marin-bottom;
170   -
171   - .company-clean-container-header-address {
172   - font-size: 30rpx;
173   - font-weight: bold;
174   - color: $u-main-color;
175   - }
176 239  
177   - .company-clean-container-header-base-info {
178   - font-size: 25rpx;
179   - color: $u-info;
180   - line-height: 80rpx;
181   - }
182   -
183   - .company-clean-container-header-reservation {
184   - display: flex;
185   - justify-content: space-between;
186   - font-size: 25rpx;
  240 + .company-clean-container-header {
  241 + padding: $custom-page-padding;
  242 + box-sizing: border-box;
  243 + background-color: #ffffff;
  244 + border-radius: $custom-border-radio;
  245 + margin-bottom: $custom-marin-bottom;
187 246  
  247 + .company-clean-container-header-address {
  248 + font-size: 30rpx;
  249 + font-weight: bold;
  250 + color: $u-main-color;
  251 + }
188 252  
189   - .company-clean-container-header-reservation-left {
190   - display: flex;
191   - align-items: center;
192   - color: $u-content-color;
  253 + .company-clean-container-header-base-info {
  254 + font-size: 25rpx;
  255 + color: $u-info;
  256 + line-height: 80rpx;
193 257 }
194 258  
195   - .company-clean-container-header-reservation-right {
  259 + .company-clean-container-header-reservation {
196 260 display: flex;
197   - align-items: center;
198   - color: $u-content-color;
199   - }
200   - }
  261 + justify-content: space-between;
  262 + font-size: 25rpx;
201 263  
202 264  
203   - }
  265 + .company-clean-container-header-reservation-left {
  266 + display: flex;
  267 + align-items: center;
  268 + color: $u-content-color;
  269 + }
  270 +
  271 + .company-clean-container-header-reservation-right {
  272 + display: flex;
  273 + align-items: center;
  274 + color: $u-content-color;
  275 + }
  276 + }
204 277  
205   - .company-clean-container-car-main {
206   - padding: $custom-page-padding;
207   - border-radius: $custom-border-radio;
208   - box-sizing: border-box;
209   - background-color: #ffffff;
210   - margin-bottom: $custom-marin-bottom;
211 278  
212   - .company-clean-container-car-main-title {
213   - font-size: 30rpx;
214   - font-weight: bold;
215   - color: green;
216   - display: flex;
217   - justify-content: center;
218 279 }
219 280  
220   - .company-clean-container-car-main-content {
221   - width: 100%;
222   - display: flex;
223   - flex-direction: column;
224   - justify-content: center;
  281 + .company-clean-container-car-main {
  282 + padding: $custom-page-padding;
  283 + border-radius: $custom-border-radio;
  284 + box-sizing: border-box;
  285 + background-color: #ffffff;
  286 + margin-bottom: $custom-marin-bottom;
  287 +
  288 + .company-clean-container-car-main-title {
  289 + font-size: 30rpx;
  290 + font-weight: bold;
  291 + color: #a9e08f;
  292 + display: flex;
  293 + justify-content: center;
  294 + }
225 295  
226   - .company-clean-container-car-main-content-img {
227   - width: 600rpx;
228   - height: 400rpx;
  296 + .company-clean-container-car-main-content {
  297 + width: 100%;
  298 + display: flex;
  299 + flex-direction: column;
  300 + justify-content: center;
229 301  
230 302 .company-clean-container-car-main-content-img {
231 303 width: 600rpx;
232 304 height: 400rpx;
233   - }
234   - }
235 305  
236   - .company-clean-container-car-main-content-remark {
237   - color: $u-tips-color;
238   - font-size: 23rpx;
239   - line-height: 30rpx;
240   - padding: $custom-page-padding;
241   - background-color: $u-info-light;
242   - word-break: break-all;
243   - }
  306 + .company-clean-container-car-main-content-img {
  307 + width: 600rpx;
  308 + height: 400rpx;
  309 + }
  310 + }
244 311  
245   - .company-clean-container-car-main-content-type {
246   - margin-top: $custom-marin-bottom;
247   - margin-bottom: $custom-marin-bottom;
248   - display: flex;
249   - justify-content: space-between;
250   - border-radius: $custom-border-radio;
251   - background-color: $u-info-light;
252   - box-sizing: border-box;
253   - font-size: 30rpx;
  312 + .company-clean-container-car-main-content-remark {
  313 + color: $u-tips-color;
  314 + font-size: 23rpx;
  315 + line-height: 30rpx;
  316 + padding: $custom-page-padding;
  317 + background-color: $u-info-light;
  318 + word-break: break-all;
  319 + }
254 320  
255   - .company-clean-container-car-main-content-type-choose {
256   - width: 230rpx;
257   - color: #ffffff;
  321 + .company-clean-container-car-main-content-type {
  322 + margin-top: $custom-marin-bottom;
  323 + margin-bottom: $custom-marin-bottom;
258 324 display: flex;
259   - justify-content: center;
260   - align-items: center;
261   - background-color: green;
262   - padding: 30rpx $custom-page-padding 30rpx $custom-page-padding;
  325 + justify-content: space-between;
  326 + border-radius: $custom-border-radio;
  327 + background-color: $u-info-light;
263 328 box-sizing: border-box;
264   - border-radius: $custom-border-radio 0 0 $custom-border-radio;
  329 + font-size: 30rpx;
  330 +
  331 + .company-clean-container-car-main-content-type-choose {
  332 + width: 230rpx;
  333 + color: #ffffff;
  334 + display: flex;
  335 + justify-content: center;
  336 + align-items: center;
  337 + background-color: #a9e08f;
  338 + padding: 30rpx $custom-page-padding 30rpx $custom-page-padding;
  339 + box-sizing: border-box;
  340 + border-radius: $custom-border-radio 0 0 $custom-border-radio;
  341 + }
  342 +
  343 + .company-clean-container-car-main-content-type-price-area {
  344 + width: 100%;
  345 + display: flex;
  346 + justify-content: flex-end;
  347 + align-items: center;
  348 + box-sizing: border-box;
  349 + color: $u-tips-color;
  350 + padding-right: $custom-page-padding;
  351 + }
265 352 }
266 353  
267   - .company-clean-container-car-main-content-type-price-area {
268   - width: 100%;
  354 + .company-clean-container-car-main-content-number {
269 355 display: flex;
270   - justify-content: flex-end;
271   - align-items: center;
272   - box-sizing: border-box;
  356 + justify-content: space-between;
  357 + font-size: 28rpx;
273 358 color: $u-tips-color;
274   - padding-right: $custom-page-padding;
  359 + font-weight: small;
  360 + align-items: center;
  361 +
  362 + .company-clean-container-car-main-content-number-txt {
  363 + line-height: 80rpx;
  364 + }
  365 +
  366 + .company-clean-container-car-main-content-number-button {}
275 367 }
276 368 }
277 369  
278   - .company-clean-container-car-main-content-number {
279   - display: flex;
280   - justify-content: space-between;
281   - font-size: 28rpx;
282   - color: $u-tips-color;
283   - font-weight: small;
284   - align-items: center;
285 370  
286   - .company-clean-container-car-main-content-number-txt {
287   - line-height: 80rpx;
288   - }
  371 + }
  372 +
  373 + .company-clean-container-car-main-content-prompt {
  374 + color: $u-tips-color;
  375 + font-size: 23rpx;
  376 + line-height: 30rpx;
  377 + padding: $custom-page-padding;
  378 + word-break: break-all;
  379 + text-align: center;
  380 + }
  381 +
  382 + .company-clean-container-site-image-info {
  383 + padding: $custom-page-padding;
  384 + background-color: #ffffff;
  385 + border-radius: $custom-border-radio;
  386 + color: $u-info;
  387 + font-size: 28rpx;
  388 + margin-bottom: $custom-marin-bottom;
289 389  
290   - .company-clean-container-car-main-content-number-button {}
  390 + .company-clean-container-site-image-info-remark {
  391 + line-height: 80rpx;
  392 +
  393 + }
  394 +
  395 + .company-clean-container-site-image-info-img {}
  396 +
  397 + .company-clean-container-site-image-info-input-remark {
  398 + line-height: 80rpx;
291 399 }
  400 +
  401 + .company-clean-container-site-image-info-input-remark-box {}
292 402 }
293 403  
  404 + .company-clean-container-site-image-info-sure-button {
  405 + padding-bottom: $custom-bottom-height;
  406 + font-size: 28rpx;
  407 +
  408 + .company-clean-container-site-image-info-sure-button-radio {
  409 + padding: $custom-page-padding;
  410 + box-sizing: border-box;
  411 + display: flex;
  412 + flex-flow: row wrap;
  413 + }
  414 + }
294 415  
295   - }
296 416  
297   - .company-clean-container-car-main-content-prompt {
298   - color: $u-tips-color;
299   - font-size: 23rpx;
300   - line-height: 30rpx;
301   - padding: $custom-page-padding;
302   - word-break: break-all;
303   - text-align: center;
304 417 }
305 418  
306   - .company-clean-container-site-image-info {
307   - padding: $custom-page-padding;
308   - background-color: #ffffff;
309   - border-radius: $custom-border-radio;
310   - color: $u-info;
311   - font-size: 28rpx;
312 419  
313   - .company-clean-container-site-image-info-remark {
314   - line-height: 80rpx;
315 420  
  421 +
  422 + .company-clean-bottom {
  423 + position: absolute;
  424 + width: 100%;
  425 + // height: 100%;
  426 + bottom: 0;
  427 + left: 0;
  428 +
  429 + .movableArea {
  430 + pointer-events: none;
  431 + position: fixed;
  432 + left: 0;
  433 + top: 0;
  434 + width: 100%;
  435 + height: calc(100% - $custom-bottom-height);
  436 + z-index: 999;
  437 +
  438 + .movableView {
  439 + pointer-events: auto;
  440 + min-height: 60rpx;
  441 + min-width: 60rpx;
  442 +
  443 + .company-clean-call-box-container {
  444 + min-height: 60rpx;
  445 + min-width: 60rpx;
  446 + display: flex;
  447 + align-items: center;
  448 + justify-content: center;
  449 + background-color: #a9e08f;
  450 + border-radius: 100%;
  451 + }
  452 + }
316 453 }
317 454  
318   - .company-clean-container-site-image-info-img {}
  455 + .company-clean-bottom-box {
  456 + height: $custom-bottom-height;
  457 + background-color: #ffffff;
  458 + padding: 50rpx;
  459 + box-sizing: border-box;
  460 + display: flex;
  461 + justify-content: space-between;
  462 + align-items: center;
319 463  
320   - .company-clean-container-site-image-info-input-remark {
321   - line-height: 80rpx;
  464 + .company-clean-bottom-left {
  465 + transform: rotateY(180deg);
  466 + }
  467 +
  468 + .company-clean-bottom-right {
  469 + min-width: 200rpx;
  470 + }
322 471 }
323 472  
324   - .company-clean-container-site-image-info-input-remark-box {}
325 473 }
326 474  
327 475  
328   -
329   - .company-clean-container-site-image-info-sure-button {}
330 476 }
331 477 </style>
... ...
garbage-removal/src/pages/home/index.vue
... ... @@ -52,8 +52,8 @@
52 52 <view class="company-list-item-main-right-score">
53 53 <text class="company-list-item-main-right-text">评分:</text>
54 54 <view class="company-list-item-main-right-score-start">
55   - <u-icon v-for="todo in maxStar" :name="item.score > todo ? 'star-fill' : 'star'" color="#f9ae3d"
56   - size="28"></u-icon>
  55 + <u-icon v-for="todo in maxStar" :name="item.score > todo ? 'star-fill' : 'star'" :key="todo"
  56 + color="#f9ae3d" size="28"></u-icon>
57 57 </view>
58 58 <text class="company-list-item-main-right-text" style="color: #fd5d00;">5分</text>
59 59 </view>
... ... @@ -74,8 +74,8 @@
74 74 :hairline="true" shape="circle" text="联系公司"></u-button>
75 75 </view>
76 76 <view class="company-list-item-bottom-button-clean">
77   - <u-button @click="handleCleanGarbage(item.companyId)" type="success" :hairline="true" size="normal"
78   - shape="circle" text="垃圾清运"></u-button>
  77 + <u-button @click="handleCleanGarbage(item.companyId, item.tel)" type="success" :hairline="true"
  78 + size="normal" shape="circle" text="垃圾清运"></u-button>
79 79 </view>
80 80 </view>
81 81 </view>
... ... @@ -197,10 +197,10 @@ function handleDetailClick(companyId, tel) {
197 197 /**
198 198 * 清运跳转
199 199 */
200   -const handleCleanGarbage = (companyId) => {
  200 +const handleCleanGarbage = (companyId, tel) => {
201 201 console.log("垃圾清运");
202 202 uni.$u.route({
203   - url: `pages/home/clean/index?companyId=${companyId}`,
  203 + url: `pages/home/clean/index?companyId=${companyId}&tel=${tel}`,
204 204 })
205 205 }
206 206  
... ...
garbage-removal/src/pages/order/index.vue
1 1 <template>
2   - <view>
3   - order
4   - </view>
  2 + <z-paging-swiper>
  3 + <template v-slot:top>
  4 + <u-tabs lineWidth="40" lineColor="#ffffff" lineHeight="6"
  5 + :activeStyle="{ 'color': '#ffffff', 'font-weight': 'bolder' }" :inactiveStyle="{ color: '#ffffff' }"
  6 + ref="uTabsElement" :list="list" :current="current" @change="tabsChange" :scrollable="false"></u-tabs>
  7 + </template>
  8 + <swiper class="swiper" :current="swiperCurrent" @translation="translation" @animationfinish="animationfinish">
  9 + <swiper-item class="swiper-item" v-for="(item, index) in list" :key="index">
  10 + <swiper-list-item :tabIndex="index" :currentIndex="swiperCurrent"></swiper-list-item>
  11 + </swiper-item>
  12 + </swiper>
  13 + </z-paging-swiper>
5 14 </template>
6   -
7 15 <script setup>
8   -
  16 +import { ref } from 'vue';
  17 +import swiperListItem from './swiper-list-item/index.vue';
  18 +const list = ref([{ name: '待清运' }, { name: '清运中' }, { name: '全部' }, { name: '待支付' }, { name: '已完成' }])
  19 +const current = ref(0);
  20 +const swiperCurrent = ref(0)
  21 +const uTabsElement = ref()
  22 +const tabsChange = (el) => {
  23 + swiperCurrent.value = Number(el.index)
  24 +}
  25 +const animationfinish = (e) => {
  26 + current.value = e.detail.current
  27 + swiperCurrent.value = e.detail.current
  28 +}
  29 +const translation = (e) => {
  30 + uTabsElement.value.setDx(e.detail.dx)
  31 +}
9 32 </script>
10   -
11 33 <style lang="scss" scoped>
  34 +::v-deep .u-tabs__wrapper__scroll-view {
  35 + background-color: #53c21d;
  36 +}
  37 +
  38 +.swiper {
  39 + height: 100%;
  40 + background: linear-gradient(to bottom, $u-success-dark, #ffffff, #ffffff, #ffffff, #ffffff, #ffffff, #ffffff);
  41 +}
12 42 </style>
... ...
garbage-removal/src/pages/order/swiper-list-item/index.vue 0 → 100644
  1 +<template>
  2 + <view class="content-container">
  3 + <z-paging ref="paging" v-model="dataList" @query="queryList">
  4 + <empty-view slot:empty></empty-view>
  5 + <view class="item" v-for="(item, index) in dataList">
  6 + <view class="item-title">{{ item }}</view>
  7 + </view>
  8 + </z-paging>
  9 + </view>
  10 +</template>
  11 +
  12 +<script setup>
  13 +import { onMounted, ref } from 'vue';
  14 +
  15 +const props = defineProps({
  16 + tabIndex: {
  17 + type: Number
  18 + },
  19 + currentIndex: {
  20 + type: Number
  21 + }
  22 +})
  23 +const paging = ref(null)
  24 +const dataList = ref([])
  25 +const count = ref(0)
  26 +const queryList = (pageNo, pageSize) => {
  27 + //这里的pageNo和pageSize会自动计算好,直接传给服务器即可
  28 + //这里的请求只是演示,请替换成自己的项目的网络请求,并在网络请求回调中通过paging.value.complete(请求回来的数组)将请求结果传给z-paging
  29 + // request.queryList({ pageNo, pageSize }).then(res => {
  30 + // //请勿在网络请求回调中给dataList赋值!!只需要调用complete就可以了
  31 + if (props.tabIndex == 3) {
  32 + paging.value.complete([])
  33 + return
  34 + }
  35 + if (++count.value < 3) {
  36 +
  37 + }
  38 + setInterval(() => {
  39 + paging.value.complete([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
  40 + }, 500);
  41 + paging.value.complete([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
  42 + // }).catch(res => {
  43 + // //如果请求失败写paging.value.complete(false),会自动展示错误页面
  44 + // //注意,每次都需要在catch中写这句话很麻烦,z-paging提供了方案可以全局统一处理
  45 + // //在底层的网络请求抛出异常时,写uni.$emit('z-paging-error-emit');即可
  46 + // paging.value.complete(false);
  47 + // })
  48 +}
  49 +
  50 +onMounted(() => {
  51 + console.log("tabIndex:", props.tabIndex);
  52 + console.log("currentIndex:", props.currentIndex);
  53 +})
  54 +</script>
  55 +
  56 +<style lang="scss" scoped>
  57 +.content-container {
  58 + height: 100%;
  59 +}
  60 +</style>
... ...
garbage-removal/src/uview-plus/components/u-radio-group/u-radio-group.vue
1 1 <template>
2   - <view
3   - class="u-radio-group"
4   - :class="bemClass"
5   - >
  2 + <view class="u-radio-group" :class="bemClass">
6 3 <slot></slot>
7 4 </view>
8 5 </template>
9 6  
10 7 <script>
11   - import props from './props.js';
12   - import mpMixin from '../../libs/mixin/mpMixin.js';
13   - import mixin from '../../libs/mixin/mixin.js';
  8 +import mixin from '../../libs/mixin/mixin.js';
  9 +import mpMixin from '../../libs/mixin/mpMixin.js';
  10 +import props from './props.js';
  11 +
  12 +/**
  13 + * radioRroup 单选框父组件
  14 + * @description 单选框用于有一个选择,用户只能选择其中一个的场景。搭配u-radio使用
  15 + * @tutorial https://ijry.github.io/uview-plus/components/radio.html
  16 + * @property {String | Number | Boolean} value 绑定的值
  17 + * @property {Boolean} disabled 是否禁用所有radio(默认 false )
  18 + * @property {String} shape 外观形状,shape-方形,circle-圆形(默认 circle )
  19 + * @property {String} activeColor 选中时的颜色,应用到所有子Radio组件(默认 '#2979ff' )
  20 + * @property {String} inactiveColor 未选中的颜色 (默认 '#c8c9cc' )
  21 + * @property {String} name 标识符
  22 + * @property {String | Number} size 组件整体的大小,单位px(默认 18 )
  23 + * @property {String} placement 布局方式,row-横向,column-纵向 (默认 'row' )
  24 + * @property {String} label 文本
  25 + * @property {String} labelColor label的颜色 (默认 '#303133' )
  26 + * @property {String | Number} labelSize label的字体大小,px单位 (默认 14 )
  27 + * @property {Boolean} labelDisabled 是否禁止点击文本操作checkbox(默认 false )
  28 + * @property {String} iconColor 图标颜色 (默认 '#ffffff' )
  29 + * @property {String | Number} iconSize 图标的大小,单位px (默认 12 )
  30 + * @property {Boolean} borderBottom placement为row时,是否显示下边框 (默认 false )
  31 + * @property {String} iconPlacement 图标与文字的对齐方式 (默认 'left' )
  32 + * @property {Object} customStyle 组件的样式,对象形式
  33 + * @event {Function} change 任一个radio状态发生变化时触发
  34 + * @example <u-radio-group v-model="value"></u-radio-group>
  35 + */
  36 +export default {
  37 + name: 'u-radio-group',
  38 + mixins: [mpMixin, mixin, props],
  39 + computed: {
  40 + // 这里computed的变量,都是子组件u-radio需要用到的,由于头条小程序的兼容性差异,子组件无法实时监听父组件参数的变化
  41 + // 所以需要手动通知子组件,这里返回一个parentData变量,供watch监听,在其中去通知每一个子组件重新从父组件(u-radio-group)
  42 + // 拉取父组件新的变化后的参数
  43 + parentData() {
  44 + // #ifdef VUE3
  45 + return [this.modelValue, this.disabled, this.inactiveColor, this.activeColor, this.size, this.labelDisabled, this.shape,
  46 + this.iconSize, this.borderBottom, this.placement
  47 + ]
  48 + // #endif
14 49  
15   - /**
16   - * radioRroup 单选框父组件
17   - * @description 单选框用于有一个选择,用户只能选择其中一个的场景。搭配u-radio使用
18   - * @tutorial https://ijry.github.io/uview-plus/components/radio.html
19   - * @property {String | Number | Boolean} value 绑定的值
20   - * @property {Boolean} disabled 是否禁用所有radio(默认 false )
21   - * @property {String} shape 外观形状,shape-方形,circle-圆形(默认 circle )
22   - * @property {String} activeColor 选中时的颜色,应用到所有子Radio组件(默认 '#2979ff' )
23   - * @property {String} inactiveColor 未选中的颜色 (默认 '#c8c9cc' )
24   - * @property {String} name 标识符
25   - * @property {String | Number} size 组件整体的大小,单位px(默认 18 )
26   - * @property {String} placement 布局方式,row-横向,column-纵向 (默认 'row' )
27   - * @property {String} label 文本
28   - * @property {String} labelColor label的颜色 (默认 '#303133' )
29   - * @property {String | Number} labelSize label的字体大小,px单位 (默认 14 )
30   - * @property {Boolean} labelDisabled 是否禁止点击文本操作checkbox(默认 false )
31   - * @property {String} iconColor 图标颜色 (默认 '#ffffff' )
32   - * @property {String | Number} iconSize 图标的大小,单位px (默认 12 )
33   - * @property {Boolean} borderBottom placement为row时,是否显示下边框 (默认 false )
34   - * @property {String} iconPlacement 图标与文字的对齐方式 (默认 'left' )
35   - * @property {Object} customStyle 组件的样式,对象形式
36   - * @event {Function} change 任一个radio状态发生变化时触发
37   - * @example <u-radio-group v-model="value"></u-radio-group>
38   - */
39   - export default {
40   - name: 'u-radio-group',
41   - mixins: [mpMixin, mixin, props],
42   - computed: {
43   - // 这里computed的变量,都是子组件u-radio需要用到的,由于头条小程序的兼容性差异,子组件无法实时监听父组件参数的变化
44   - // 所以需要手动通知子组件,这里返回一个parentData变量,供watch监听,在其中去通知每一个子组件重新从父组件(u-radio-group)
45   - // 拉取父组件新的变化后的参数
46   - parentData() {
47   - // #ifdef VUE3
48   - return [this.modelValue, this.disabled, this.inactiveColor, this.activeColor, this.size, this.labelDisabled, this.shape,
49   - this.iconSize, this.borderBottom, this.placement
50   - ]
51   - // #endif
52   - // #ifdef VUE2
53   - return [this.value, this.disabled, this.inactiveColor, this.activeColor, this.size, this.labelDisabled, this.shape,
54   - this.iconSize, this.borderBottom, this.placement
55   - ]
56   - // #endif
57   -
58   - },
59   - bemClass() {
60   - // this.bem为一个computed变量,在mixin中
61   - return this.bem('radio-group', ['placement'])
62   - },
63   - },
64   - watch: {
65   - // 当父组件需要子组件需要共享的参数发生了变化,手动通知子组件
66   - parentData() {
67   - if (this.children.length) {
68   - this.children.map(child => {
69   - // 判断子组件(u-radio)如果有init方法的话,就就执行(执行的结果是子组件重新从父组件拉取了最新的值)
70   - typeof(child.init) === 'function' && child.init()
71   - })
72   - }
73   - },
74   - },
75   - data() {
76   - return {
77   - }
78 50 },
79   - created() {
80   - this.children = []
  51 + bemClass() {
  52 + // this.bem为一个computed变量,在mixin中
  53 + return this.bem('radio-group', ['placement'])
81 54 },
82   - // #ifdef VUE3
83   - emits: ['update:modelValue', 'change'],
84   - // #endif
85   - methods: {
86   - // 将其他的radio设置为未选中的状态
87   - unCheckedOther(childInstance) {
  55 + },
  56 + watch: {
  57 + // 当父组件需要子组件需要共享的参数发生了变化,手动通知子组件
  58 + parentData() {
  59 + if (this.children.length) {
88 60 this.children.map(child => {
89   - // 所有子radio中,被操作组件实例的checked的值无需修改
90   - if (childInstance !== child) {
91   - child.checked = false
92   - }
  61 + // 判断子组件(u-radio)如果有init方法的话,就就执行(执行的结果是子组件重新从父组件拉取了最新的值)
  62 + typeof (child.init) === 'function' && child.init()
93 63 })
94   - const {
95   - name
96   - } = childInstance
97   - // 通过emit事件,设置父组件通过v-model双向绑定的值
98   - // #ifdef VUE3
99   - this.$emit("update:modelValue", name);
100   - // #endif
101   - // #ifdef VUE2
102   - this.$emit("input", name);
103   - // #endif
104   - // 发出事件
105   - this.$emit('change', name)
106   - },
  64 + }
  65 + },
  66 + },
  67 + data() {
  68 + return {
107 69 }
  70 + },
  71 + created() {
  72 + this.children = []
  73 + },
  74 + // #ifdef VUE3
  75 + emits: ['update:modelValue', 'change'],
  76 + // #endif
  77 + methods: {
  78 + // 将其他的radio设置为未选中的状态
  79 + unCheckedOther(childInstance) {
  80 + this.children.map(child => {
  81 + // 所有子radio中,被操作组件实例的checked的值无需修改
  82 + if (childInstance !== child) {
  83 + child.checked = false
  84 + }
  85 + })
  86 + const {
  87 + name
  88 + } = childInstance
  89 + // 通过emit事件,设置父组件通过v-model双向绑定的值
  90 + // #ifdef VUE3
  91 + this.$emit("update:modelValue", name);
  92 + // #endif
  93 + // #ifdef VUE2
  94 + this.$emit("input", name);
  95 + // #endif
  96 + // 发出事件
  97 + this.$emit('change', name)
  98 + },
108 99 }
  100 +}
109 101 </script>
110 102  
111 103 <style lang="scss" scoped>
112   - @import "../../libs/css/components.scss";
  104 +@import "../../libs/css/components.scss";
113 105  
114   - .u-radio-group {
115   - flex: 1;
  106 +.u-radio-group {
  107 + flex: 1;
116 108  
117   - &--row {
118   - /* #ifndef APP-NVUE */
119   - display: flex;
120   - /* #endif */
121   - flex-flow: row wrap;
122   - }
  109 + &--row {
  110 + /* #ifndef APP-NVUE */
  111 + display: flex;
  112 + /* #endif */
  113 + // flex-flow: row wrap;
  114 + }
123 115  
124   - &--column {
125   - @include flex(column);
126   - }
  116 + &--column {
  117 + @include flex(column);
127 118 }
  119 +}
128 120 </style>
... ...
garbage-removal/src/uview-plus/components/u-radio/u-radio.vue
1 1 <template>
2   - <view
3   - class="u-radio"
4   - @tap.stop="wrapperClickHandler"
5   - :style="[radioStyle]"
6   - :class="[`u-radio-label--${parentData.iconPlacement}`, parentData.borderBottom && parentData.placement === 'column' && 'u-border-bottom']"
7   - >
8   - <view
9   - class="u-radio__icon-wrap"
10   - @tap.stop="iconClickHandler"
11   - :class="iconClasses"
12   - :style="[iconWrapStyle]"
13   - >
  2 + <view class="u-radio" @tap.stop="wrapperClickHandler" :style="[radioStyle]"
  3 + :class="[`u-radio-label--${parentData.iconPlacement}`, parentData.borderBottom && parentData.placement === 'column' && 'u-border-bottom']">
  4 + <view class="u-radio__icon-wrap" @tap.stop="iconClickHandler" :class="iconClasses" :style="[iconWrapStyle]">
14 5 <slot name="icon">
15   - <u-icon
16   - class="u-radio__icon-wrap__icon"
17   - name="checkbox-mark"
18   - :size="elIconSize"
19   - :color="elIconColor"
20   - />
  6 + <u-icon class="u-radio__icon-wrap__icon" name="checkbox-mark" :size="elIconSize" :color="elIconColor" />
21 7 </slot>
22 8 </view>
23   - <text
24   - class="u-radio__text"
25   - @tap.stop="labelClickHandler"
26   - :style="{
27   - color: elDisabled ? elInactiveColor : elLabelColor,
28   - fontSize: elLabelSize,
29   - lineHeight: elLabelSize
30   - }"
31   - >{{label}}</text>
  9 + <text class="u-radio__text" @tap.stop="labelClickHandler" :style="{
  10 + color: elDisabled ? elInactiveColor : elLabelColor,
  11 + fontSize: elLabelSize,
  12 + lineHeight: elLabelSize
  13 + }">{{ label }}</text>
32 14 </view>
33 15 </template>
34 16  
35 17 <script>
36   - import props from './props.js';
37   - import mpMixin from '../../libs/mixin/mpMixin.js';
38   - import mixin from '../../libs/mixin/mixin.js';
39   - /**
40   - * radio 单选框
41   - * @description 单选框用于有一个选择,用户只能选择其中一个的场景。搭配u-radio-group使用
42   - * @tutorial https://ijry.github.io/uview-plus/components/radio.html
43   - * @property {String | Number} name radio的名称
44   - * @property {String} shape 形状,square为方形,circle为圆型
45   - * @property {Boolean} disabled 是否禁用
46   - * @property {String | Boolean} labelDisabled 是否禁止点击提示语选中单选框
47   - * @property {String} activeColor 选中时的颜色,如设置parent的active-color将失效
48   - * @property {String} inactiveColor 未选中的颜色
49   - * @property {String | Number} iconSize 图标大小,单位px
50   - * @property {String | Number} labelSize label字体大小,单位px
51   - * @property {String | Number} label label提示文字,因为nvue下,直接slot进来的文字,由于特殊的结构,无法修改样式
52   - * @property {String | Number} size 整体的大小
53   - * @property {String} iconColor 图标颜色
54   - * @property {String} labelColor label的颜色
55   - * @property {Object} customStyle 组件的样式,对象形式
56   - *
57   - * @event {Function} change 某个radio状态发生变化时触发(选中状态)
58   - * @example <u-radio :labelDisabled="false">门掩黄昏,无计留春住</u-radio>
59   - */
60   - export default {
61   - name: "u-radio",
62   -
63   - mixins: [mpMixin, mixin,props],
64   - data() {
65   - return {
66   - checked: false,
67   - // 当你看到这段代码的时候,
68   - // 父组件的默认值,因为头条小程序不支持在computed中使用this.parent.shape的形式
69   - // 故只能使用如此方法
70   - parentData: {
71   - iconSize: 12,
72   - labelDisabled: null,
73   - disabled: null,
74   - shape: null,
75   - activeColor: null,
76   - inactiveColor: null,
77   - size: 18,
78   - value: null,
79   - modelValue: null,
80   - iconColor: null,
81   - placement: 'row',
82   - borderBottom: false,
83   - iconPlacement: 'left'
84   - }
  18 +import mixin from '../../libs/mixin/mixin.js';
  19 +import mpMixin from '../../libs/mixin/mpMixin.js';
  20 +import props from './props.js';
  21 +/**
  22 + * radio 单选框
  23 + * @description 单选框用于有一个选择,用户只能选择其中一个的场景。搭配u-radio-group使用
  24 + * @tutorial https://ijry.github.io/uview-plus/components/radio.html
  25 + * @property {String | Number} name radio的名称
  26 + * @property {String} shape 形状,square为方形,circle为圆型
  27 + * @property {Boolean} disabled 是否禁用
  28 + * @property {String | Boolean} labelDisabled 是否禁止点击提示语选中单选框
  29 + * @property {String} activeColor 选中时的颜色,如设置parent的active-color将失效
  30 + * @property {String} inactiveColor 未选中的颜色
  31 + * @property {String | Number} iconSize 图标大小,单位px
  32 + * @property {String | Number} labelSize label字体大小,单位px
  33 + * @property {String | Number} label label提示文字,因为nvue下,直接slot进来的文字,由于特殊的结构,无法修改样式
  34 + * @property {String | Number} size 整体的大小
  35 + * @property {String} iconColor 图标颜色
  36 + * @property {String} labelColor label的颜色
  37 + * @property {Object} customStyle 组件的样式,对象形式
  38 + *
  39 + * @event {Function} change 某个radio状态发生变化时触发(选中状态)
  40 + * @example <u-radio :labelDisabled="false">门掩黄昏,无计留春住</u-radio>
  41 + */
  42 +export default {
  43 + name: "u-radio",
  44 +
  45 + mixins: [mpMixin, mixin, props],
  46 + data() {
  47 + return {
  48 + checked: false,
  49 + // 当你看到这段代码的时候,
  50 + // 父组件的默认值,因为头条小程序不支持在computed中使用this.parent.shape的形式
  51 + // 故只能使用如此方法
  52 + parentData: {
  53 + iconSize: 12,
  54 + labelDisabled: null,
  55 + disabled: null,
  56 + shape: null,
  57 + activeColor: null,
  58 + inactiveColor: null,
  59 + size: 18,
  60 + value: null,
  61 + modelValue: null,
  62 + iconColor: null,
  63 + placement: 'row',
  64 + borderBottom: false,
  65 + iconPlacement: 'left'
85 66 }
  67 + }
  68 + },
  69 + computed: {
  70 + // 是否禁用,如果父组件u-raios-group禁用的话,将会忽略子组件的配置
  71 + elDisabled() {
  72 + return this.disabled !== '' ? this.disabled : this.parentData.disabled !== null ? this.parentData.disabled : false;
  73 + },
  74 + // 是否禁用label点击
  75 + elLabelDisabled() {
  76 + return this.labelDisabled !== '' ? this.labelDisabled : this.parentData.labelDisabled !== null ? this.parentData.labelDisabled :
  77 + false;
  78 + },
  79 + // 组件尺寸,对应size的值,默认值为21px
  80 + elSize() {
  81 + return this.size ? this.size : (this.parentData.size ? this.parentData.size : 21);
  82 + },
  83 + // 组件的勾选图标的尺寸,默认12px
  84 + elIconSize() {
  85 + return this.iconSize ? this.iconSize : (this.parentData.iconSize ? this.parentData.iconSize : 12);
  86 + },
  87 + // 组件选中激活时的颜色
  88 + elActiveColor() {
  89 + return this.activeColor ? this.activeColor : (this.parentData.activeColor ? this.parentData.activeColor : '#2979ff');
  90 + },
  91 + // 组件选未中激活时的颜色
  92 + elInactiveColor() {
  93 + return this.inactiveColor ? this.inactiveColor : (this.parentData.inactiveColor ? this.parentData.inactiveColor :
  94 + '#c8c9cc');
86 95 },
87   - computed: {
88   - // 是否禁用,如果父组件u-raios-group禁用的话,将会忽略子组件的配置
89   - elDisabled() {
90   - return this.disabled !== '' ? this.disabled : this.parentData.disabled !== null ? this.parentData.disabled : false;
91   - },
92   - // 是否禁用label点击
93   - elLabelDisabled() {
94   - return this.labelDisabled !== '' ? this.labelDisabled : this.parentData.labelDisabled !== null ? this.parentData.labelDisabled :
95   - false;
96   - },
97   - // 组件尺寸,对应size的值,默认值为21px
98   - elSize() {
99   - return this.size ? this.size : (this.parentData.size ? this.parentData.size : 21);
100   - },
101   - // 组件的勾选图标的尺寸,默认12px
102   - elIconSize() {
103   - return this.iconSize ? this.iconSize : (this.parentData.iconSize ? this.parentData.iconSize : 12);
104   - },
105   - // 组件选中激活时的颜色
106   - elActiveColor() {
107   - return this.activeColor ? this.activeColor : (this.parentData.activeColor ? this.parentData.activeColor : '#2979ff');
108   - },
109   - // 组件选未中激活时的颜色
110   - elInactiveColor() {
111   - return this.inactiveColor ? this.inactiveColor : (this.parentData.inactiveColor ? this.parentData.inactiveColor :
112   - '#c8c9cc');
113   - },
114   - // label的颜色
115   - elLabelColor() {
116   - return this.labelColor ? this.labelColor : (this.parentData.labelColor ? this.parentData.labelColor : '#606266')
117   - },
  96 + // label的颜色
  97 + elLabelColor() {
  98 + return this.labelColor ? this.labelColor : (this.parentData.labelColor ? this.parentData.labelColor : '#606266')
  99 + },
  100 + // 组件的形状
  101 + elShape() {
  102 + return this.shape ? this.shape : (this.parentData.shape ? this.parentData.shape : 'circle');
  103 + },
  104 + // label大小
  105 + elLabelSize() {
  106 + return uni.$u.addUnit(this.labelSize ? this.labelSize : (this.parentData.labelSize ? this.parentData.labelSize :
  107 + '15'))
  108 + },
  109 + elIconColor() {
  110 + const iconColor = this.iconColor ? this.iconColor : (this.parentData.iconColor ? this.parentData.iconColor :
  111 + '#ffffff');
  112 + // 图标的颜色
  113 + if (this.elDisabled) {
  114 + // disabled状态下,已勾选的radio图标改为elInactiveColor
  115 + return this.checked ? this.elInactiveColor : 'transparent'
  116 + } else {
  117 + return this.checked ? iconColor : 'transparent'
  118 + }
  119 + },
  120 + iconClasses() {
  121 + let classes = []
118 122 // 组件的形状
119   - elShape() {
120   - return this.shape ? this.shape : (this.parentData.shape ? this.parentData.shape : 'circle');
121   - },
122   - // label大小
123   - elLabelSize() {
124   - return uni.$u.addUnit(this.labelSize ? this.labelSize : (this.parentData.labelSize ? this.parentData.labelSize :
125   - '15'))
126   - },
127   - elIconColor() {
128   - const iconColor = this.iconColor ? this.iconColor : (this.parentData.iconColor ? this.parentData.iconColor :
129   - '#ffffff');
130   - // 图标的颜色
131   - if (this.elDisabled) {
132   - // disabled状态下,已勾选的radio图标改为elInactiveColor
133   - return this.checked ? this.elInactiveColor : 'transparent'
134   - } else {
135   - return this.checked ? iconColor : 'transparent'
136   - }
137   - },
138   - iconClasses() {
139   - let classes = []
140   - // 组件的形状
141   - classes.push('u-radio__icon-wrap--' + this.elShape)
142   - if (this.elDisabled) {
143   - classes.push('u-radio__icon-wrap--disabled')
144   - }
145   - if (this.checked && this.elDisabled) {
146   - classes.push('u-radio__icon-wrap--disabled--checked')
147   - }
148   - // 支付宝,头条小程序无法动态绑定一个数组类名,否则解析出来的结果会带有",",而导致失效
149   - // #ifdef MP-ALIPAY || MP-TOUTIAO
150   - classes = classes.join(' ')
151   - // #endif
152   - return classes
153   - },
154   - iconWrapStyle() {
155   - // radio的整体样式
156   - const style = {}
157   - style.backgroundColor = this.checked && !this.elDisabled ? this.elActiveColor : '#ffffff'
158   - style.borderColor = this.checked && !this.elDisabled ? this.elActiveColor : this.elInactiveColor
159   - style.width = uni.$u.addUnit(this.elSize)
160   - style.height = uni.$u.addUnit(this.elSize)
161   - // 如果是图标在右边的话,移除它的右边距
162   - if (this.parentData.iconPlacement === 'right') {
163   - style.marginRight = 0
164   - }
165   - return style
166   - },
167   - radioStyle() {
168   - const style = {}
169   - if(this.parentData.borderBottom && this.parentData.placement === 'row') {
170   - uni.$u.error('检测到您将borderBottom设置为true,需要同时将u-radio-group的placement设置为column才有效')
171   - }
172   - // 当父组件设置了显示下边框并且排列形式为纵向时,给内容和边框之间加上一定间隔
173   - if(this.parentData.borderBottom && this.parentData.placement === 'column') {
174   - // ios像素密度高,需要多一点的距离
175   - style.paddingBottom = uni.$u.os() === 'ios' ? '12px' : '8px'
176   - }
177   - return uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle))
  123 + classes.push('u-radio__icon-wrap--' + this.elShape)
  124 + if (this.elDisabled) {
  125 + classes.push('u-radio__icon-wrap--disabled')
  126 + }
  127 + if (this.checked && this.elDisabled) {
  128 + classes.push('u-radio__icon-wrap--disabled--checked')
178 129 }
  130 + // 支付宝,头条小程序无法动态绑定一个数组类名,否则解析出来的结果会带有",",而导致失效
  131 + // #ifdef MP-ALIPAY || MP-TOUTIAO
  132 + classes = classes.join(' ')
  133 + // #endif
  134 + return classes
179 135 },
180   - mounted() {
181   - this.init()
  136 + iconWrapStyle() {
  137 + // radio的整体样式
  138 + const style = {}
  139 + style.backgroundColor = this.checked && !this.elDisabled ? this.elActiveColor : '#ffffff'
  140 + style.borderColor = this.checked && !this.elDisabled ? this.elActiveColor : this.elInactiveColor
  141 + style.width = uni.$u.addUnit(this.elSize)
  142 + style.height = uni.$u.addUnit(this.elSize)
  143 + // 如果是图标在右边的话,移除它的右边距
  144 + if (this.parentData.iconPlacement === 'right') {
  145 + style.marginRight = 0
  146 + }
  147 + return style
182 148 },
  149 + radioStyle() {
  150 + const style = {}
  151 + if (this.parentData.borderBottom && this.parentData.placement === 'row') {
  152 + uni.$u.error('检测到您将borderBottom设置为true,需要同时将u-radio-group的placement设置为column才有效')
  153 + }
  154 + // 当父组件设置了显示下边框并且排列形式为纵向时,给内容和边框之间加上一定间隔
  155 + if (this.parentData.borderBottom && this.parentData.placement === 'column') {
  156 + // ios像素密度高,需要多一点的距离
  157 + style.paddingBottom = uni.$u.os() === 'ios' ? '12px' : '8px'
  158 + }
  159 + return uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle))
  160 + }
  161 + },
  162 + mounted() {
  163 + this.init()
  164 + },
183 165  
184   - methods: {
185   - init() {
186   - // 支付宝小程序不支持provide/inject,所以使用这个方法获取整个父组件,在created定义,避免循环引用
187   - this.updateParentData()
188   - if (!this.parent) {
189   - uni.$u.error('u-radio必须搭配u-radio-group组件使用')
190   - }
191   - // 设置初始化时,是否默认选中的状态
192   - // #ifdef VUE3
193   - this.checked = this.name === this.parentData.modelValue
194   - // #endif
195   - // #ifdef VUE2
196   - this.checked = this.name === this.parentData.value
197   - // #endif
198   - },
199   - updateParentData() {
200   - this.getParentData('u-radio-group')
201   - },
202   - // 点击图标
203   - iconClickHandler(e) {
204   - this.preventEvent(e)
205   - // 如果整体被禁用,不允许被点击
206   - if (!this.elDisabled) {
207   - this.setRadioCheckedStatus()
208   - }
209   - },
210   - // 横向两端排列时,点击组件即可触发选中事件
211   - wrapperClickHandler(e) {
212   - this.parentData.iconPlacement === 'right' && this.iconClickHandler(e)
213   - },
214   - // 点击label
215   - labelClickHandler(e) {
216   - this.preventEvent(e)
217   - // 如果按钮整体被禁用或者label被禁用,则不允许点击文字修改状态
218   - if (!this.elLabelDisabled && !this.elDisabled) {
219   - this.setRadioCheckedStatus()
220   - }
221   - },
222   - emitEvent() {
223   - // u-radio的checked不为true时(意味着未选中),才发出事件,避免多次点击触发事件
224   - if (!this.checked) {
225   - this.$emit('change', this.name)
226   - // 尝试调用u-form的验证方法,进行一定延迟,否则微信小程序更新可能会不及时
227   - this.$nextTick(() => {
228   - uni.$u.formValidate(this, 'change')
229   - })
230   - }
231   - },
232   - // 改变组件选中状态
233   - // 这里的改变的依据是,更改本组件的checked值为true,同时通过父组件遍历所有u-radio实例
234   - // 将本组件外的其他u-radio的checked都设置为false(都被取消选中状态),因而只剩下一个为选中状态
235   - setRadioCheckedStatus() {
236   - this.emitEvent()
237   - // 将本组件标记为选中状态
238   - this.checked = true
239   - typeof this.parent.unCheckedOther === 'function' && this.parent.unCheckedOther(this)
  166 + methods: {
  167 + init() {
  168 + // 支付宝小程序不支持provide/inject,所以使用这个方法获取整个父组件,在created定义,避免循环引用
  169 + this.updateParentData()
  170 + if (!this.parent) {
  171 + uni.$u.error('u-radio必须搭配u-radio-group组件使用')
  172 + }
  173 + // 设置初始化时,是否默认选中的状态
  174 + // #ifdef VUE3
  175 + this.checked = this.name === this.parentData.modelValue
  176 + // #endif
  177 + // #ifdef VUE2
  178 + this.checked = this.name === this.parentData.value
  179 + // #endif
  180 + },
  181 + updateParentData() {
  182 + this.getParentData('u-radio-group')
  183 + },
  184 + // 点击图标
  185 + iconClickHandler(e) {
  186 + this.preventEvent(e)
  187 + // 如果整体被禁用,不允许被点击
  188 + if (!this.elDisabled) {
  189 + this.setRadioCheckedStatus()
  190 + }
  191 + },
  192 + // 横向两端排列时,点击组件即可触发选中事件
  193 + wrapperClickHandler(e) {
  194 + this.parentData.iconPlacement === 'right' && this.iconClickHandler(e)
  195 + },
  196 + // 点击label
  197 + labelClickHandler(e) {
  198 + this.preventEvent(e)
  199 + // 如果按钮整体被禁用或者label被禁用,则不允许点击文字修改状态
  200 + if (!this.elLabelDisabled && !this.elDisabled) {
  201 + this.setRadioCheckedStatus()
  202 + }
  203 + },
  204 + emitEvent() {
  205 + // u-radio的checked不为true时(意味着未选中),才发出事件,避免多次点击触发事件
  206 + if (!this.checked) {
  207 + this.$emit('change', this.name)
  208 + // 尝试调用u-form的验证方法,进行一定延迟,否则微信小程序更新可能会不及时
  209 + this.$nextTick(() => {
  210 + uni.$u.formValidate(this, 'change')
  211 + })
240 212 }
  213 + },
  214 + // 改变组件选中状态
  215 + // 这里的改变的依据是,更改本组件的checked值为true,同时通过父组件遍历所有u-radio实例
  216 + // 将本组件外的其他u-radio的checked都设置为false(都被取消选中状态),因而只剩下一个为选中状态
  217 + setRadioCheckedStatus() {
  218 + this.emitEvent()
  219 + // 将本组件标记为选中状态
  220 + this.checked = true
  221 + typeof this.parent.unCheckedOther === 'function' && this.parent.unCheckedOther(this)
241 222 }
242 223 }
  224 +}
243 225 </script>
244 226  
245 227 <style lang="scss" scoped>
246   - @import "../../libs/css/components.scss";
247   - $u-radio-wrap-margin-right:6px !default;
248   - $u-radio-wrap-font-size:20px !default;
249   - $u-radio-wrap-border-width:1px !default;
250   - $u-radio-wrap-border-color: #c8c9cc !default;
251   - $u-radio-line-height:0 !default;
252   - $u-radio-circle-border-radius:100% !default;
253   - $u-radio-square-border-radius:3px !default;
254   - $u-radio-checked-color:#fff !default;
255   - $u-radio-checked-background-color:red !default;
256   - $u-radio-checked-border-color: #2979ff !default;
257   - $u-radio-disabled-background-color:#ebedf0 !default;
258   - $u-radio-disabled--checked-color:#c8c9cc !default;
259   - $u-radio-label-margin-left: 5px !default;
260   - $u-radio-label-margin-right:12px !default;
261   - $u-radio-label-color:$u-content-color !default;
262   - $u-radio-label-font-size:15px !default;
263   - $u-radio-label-disabled-color:#c8c9cc !default;
264   -
265   - .u-radio {
  228 +@import "../../libs/css/components.scss";
  229 +$u-radio-wrap-margin-right: 6px !default;
  230 +$u-radio-wrap-font-size: 20px !default;
  231 +$u-radio-wrap-border-width: 1px !default;
  232 +$u-radio-wrap-border-color: #c8c9cc !default;
  233 +$u-radio-line-height: 0 !default;
  234 +$u-radio-circle-border-radius: 100% !default;
  235 +$u-radio-square-border-radius: 3px !default;
  236 +$u-radio-checked-color: #fff !default;
  237 +$u-radio-checked-background-color: red !default;
  238 +$u-radio-checked-border-color: #2979ff !default;
  239 +$u-radio-disabled-background-color: #ebedf0 !default;
  240 +$u-radio-disabled--checked-color: #c8c9cc !default;
  241 +$u-radio-label-margin-left: 5px !default;
  242 +$u-radio-label-margin-right: 12px !default;
  243 +$u-radio-label-color: $u-content-color !default;
  244 +$u-radio-label-font-size: 15px !default;
  245 +$u-radio-label-disabled-color: #c8c9cc !default;
  246 +
  247 +.u-radio {
  248 + /* #ifndef APP-NVUE */
  249 + // @include flex(row);
  250 + /* #endif */
  251 + // overflow: hidden;
  252 + flex-direction: row;
  253 + // align-items: center;
  254 + // margin-bottom: 5px;
  255 + // margin-top: 5px;
  256 +
  257 + &-label--left {
  258 + flex-direction: row
  259 + }
  260 +
  261 + &-label--right {
  262 + flex-direction: row-reverse;
  263 + justify-content: space-between
  264 + }
  265 +
  266 + &__icon-wrap {
266 267 /* #ifndef APP-NVUE */
267   - @include flex(row);
  268 + box-sizing: border-box;
  269 + // nvue下,border-color过渡有问题
  270 + transition-property: border-color, background-color, color;
  271 + transition-duration: 0.2s;
268 272 /* #endif */
269   - overflow: hidden;
270   - flex-direction: row;
  273 + color: $u-content-color;
  274 + @include flex;
271 275 align-items: center;
272   - margin-bottom: 5px;
273   - margin-top: 5px;
274   -
275   - &-label--left {
276   - flex-direction: row
277   - }
  276 + justify-content: center;
  277 + color: transparent;
  278 + text-align: center;
  279 + margin-right: $u-radio-wrap-margin-right;
  280 + font-size: $u-radio-wrap-font-size;
  281 + border-width: $u-radio-wrap-border-width;
  282 + border-color: $u-radio-wrap-border-color;
  283 + border-style: solid;
278 284  
279   - &-label--right {
280   - flex-direction: row-reverse;
281   - justify-content: space-between
  285 + /* #ifdef MP-TOUTIAO */
  286 + // 头条小程序兼容性问题,需要设置行高为0,否则图标偏下
  287 + &__icon {
  288 + line-height: $u-radio-line-height;
282 289 }
283 290  
284   - &__icon-wrap {
285   - /* #ifndef APP-NVUE */
286   - box-sizing: border-box;
287   - // nvue下,border-color过渡有问题
288   - transition-property: border-color, background-color, color;
289   - transition-duration: 0.2s;
290   - /* #endif */
291   - color: $u-content-color;
292   - @include flex;
293   - align-items: center;
294   - justify-content: center;
295   - color: transparent;
296   - text-align: center;
297   - margin-right: $u-radio-wrap-margin-right;
298   - font-size: $u-radio-wrap-font-size;
299   - border-width: $u-radio-wrap-border-width;
300   - border-color: $u-radio-wrap-border-color;
301   - border-style: solid;
302   -
303   - /* #ifdef MP-TOUTIAO */
304   - // 头条小程序兼容性问题,需要设置行高为0,否则图标偏下
305   - &__icon {
306   - line-height: $u-radio-line-height;
307   - }
308   -
309   - /* #endif */
  291 + /* #endif */
310 292  
311   - &--circle {
312   - border-radius: $u-radio-circle-border-radius;
313   - }
  293 + &--circle {
  294 + border-radius: $u-radio-circle-border-radius;
  295 + }
314 296  
315   - &--square {
316   - border-radius: $u-radio-square-border-radius;
317   - }
  297 + &--square {
  298 + border-radius: $u-radio-square-border-radius;
  299 + }
318 300  
319   - &--checked {
320   - color: $u-radio-checked-color;
321   - background-color: $u-radio-checked-background-color;
322   - border-color: $u-radio-checked-border-color;
323   - }
  301 + &--checked {
  302 + color: $u-radio-checked-color;
  303 + background-color: $u-radio-checked-background-color;
  304 + border-color: $u-radio-checked-border-color;
  305 + }
324 306  
325   - &--disabled {
326   - background-color: $u-radio-disabled-background-color !important;
327   - }
  307 + &--disabled {
  308 + background-color: $u-radio-disabled-background-color !important;
  309 + }
328 310  
329   - &--disabled--checked {
330   - color: $u-radio-disabled--checked-color !important;
331   - }
  311 + &--disabled--checked {
  312 + color: $u-radio-disabled--checked-color !important;
332 313 }
  314 + }
333 315  
334   - &__label {
335   - /* #ifndef APP-NVUE */
336   - word-wrap: break-word;
337   - /* #endif */
338   - margin-left: $u-radio-label-margin-left;
339   - margin-right: $u-radio-label-margin-right;
340   - color: $u-radio-label-color;
341   - font-size: $u-radio-label-font-size;
  316 + &__label {
  317 + /* #ifndef APP-NVUE */
  318 + word-wrap: break-word;
  319 + /* #endif */
  320 + margin-left: $u-radio-label-margin-left;
  321 + margin-right: $u-radio-label-margin-right;
  322 + color: $u-radio-label-color;
  323 + font-size: $u-radio-label-font-size;
342 324  
343   - &--disabled {
344   - color: $u-radio-label-disabled-color;
345   - }
  325 + &--disabled {
  326 + color: $u-radio-label-disabled-color;
346 327 }
347 328 }
  329 +}
348 330 </style>
... ...
garbage-removal/src/uview-plus/components/u-upload/u-upload.vue
1 1 <template>
2 2 <view class="u-upload" :style="[$u.addStyle(customStyle)]">
3   - <view class="u-upload__wrap" >
  3 + <view class="u-upload__wrap">
4 4 <template v-if="previewImage">
5   - <view
6   - class="u-upload__wrap__preview"
7   - v-for="(item, index) in lists"
8   - :key="index"
9   - >
10   - <image
11   - v-if="item.isImage || (item.type && item.type === 'image')"
12   - :src="item.thumb || item.url"
13   - :mode="imageMode"
14   - class="u-upload__wrap__preview__image"
15   - @tap="onPreviewImage(item)"
16   - :style="[{
  5 + <view class="u-upload__wrap__preview" v-for="(item, index) in lists" :key="index">
  6 + <image v-if="item.isImage || (item.type && item.type === 'image')" :src="item.thumb || item.url"
  7 + :mode="imageMode" class="u-upload__wrap__preview__image" @tap="onPreviewImage(item)" :style="[{
17 8 width: $u.addUnit(width),
18 9 height: $u.addUnit(height)
19   - }]"
20   - />
21   - <view
22   - v-else
23   - class="u-upload__wrap__preview__other"
24   - >
25   - <u-icon
26   - color="#80CBF9"
27   - size="26"
28   - :name="item.isVideo || (item.type && item.type === 'video') ? 'movie' : 'folder'"
29   - ></u-icon>
30   - <text class="u-upload__wrap__preview__other__text">{{item.isVideo || (item.type && item.type === 'video') ? '视频' : '文件'}}</text>
  10 + }]" />
  11 + <view v-else class="u-upload__wrap__preview__other">
  12 + <u-icon color="#80CBF9" size="26"
  13 + :name="item.isVideo || (item.type && item.type === 'video') ? 'movie' : 'folder'"></u-icon>
  14 + <text class="u-upload__wrap__preview__other__text">{{ item.isVideo || (item.type && item.type === 'video') ?
  15 + '视频' : '文件' }}</text>
31 16 </view>
32   - <view
33   - class="u-upload__status"
34   - v-if="item.status === 'uploading' || item.status === 'failed'"
35   - >
  17 + <view class="u-upload__status" v-if="item.status === 'uploading' || item.status === 'failed'">
36 18 <view class="u-upload__status__icon">
37   - <u-icon
38   - v-if="item.status === 'failed'"
39   - name="close-circle"
40   - color="#ffffff"
41   - size="25"
42   - />
43   - <u-loading-icon
44   - size="22"
45   - mode="circle"
46   - color="#ffffff"
47   - v-else
48   - />
  19 + <u-icon v-if="item.status === 'failed'" name="close-circle" color="#ffffff" size="25" />
  20 + <u-loading-icon size="22" mode="circle" color="#ffffff" v-else />
49 21 </view>
50   - <text
51   - v-if="item.message"
52   - class="u-upload__status__message"
53   - >{{ item.message }}</text>
  22 + <text v-if="item.message" class="u-upload__status__message">{{ item.message }}</text>
54 23 </view>
55   - <view
56   - class="u-upload__deletable"
57   - v-if="item.status !== 'uploading' && (deletable || item.deletable)"
58   - @tap.stop="deleteItem(index)"
59   - >
  24 + <view class="u-upload__deletable" v-if="item.status !== 'uploading' && (deletable || item.deletable)"
  25 + @tap.stop="deleteItem(index)">
60 26 <view class="u-upload__deletable__icon">
61   - <u-icon
62   - name="close"
63   - color="#ffffff"
64   - size="10"
65   - ></u-icon>
  27 + <u-icon name="close" color="#ffffff" size="25"></u-icon>
66 28 </view>
67 29 </view>
68   - <view
69   - class="u-upload__success"
70   - v-if="item.status === 'success'"
71   - >
  30 + <view class="u-upload__success" v-if="item.status === 'success'">
72 31 <!-- #ifdef APP-NVUE -->
73   - <image
74   - :src="successIcon"
75   - class="u-upload__success__icon"
76   - ></image>
  32 + <image :src="successIcon" class="u-upload__success__icon"></image>
77 33 <!-- #endif -->
78 34 <!-- #ifndef APP-NVUE -->
79 35 <view class="u-upload__success__icon">
80   - <u-icon
81   - name="checkmark"
82   - color="#ffffff"
83   - size="12"
84   - ></u-icon>
  36 + <u-icon name="checkmark" color="#ffffff" size="12"></u-icon>
85 37 </view>
86 38 <!-- #endif -->
87 39 </view>
88 40 </view>
89   -
  41 +
90 42 </template>
91   -
  43 +
92 44 <template v-if="isInCount">
93   - <view
94   - v-if="$slots.default || $slots.$default"
95   - @tap="chooseFile"
96   - >
  45 + <view v-if="$slots.default || $slots.$default" @tap="chooseFile">
97 46 <slot />
98 47 </view>
99   - <view
100   - v-else
101   - class="u-upload__button"
102   - :hover-class="!disabled ? 'u-upload__button--hover' : ''"
103   - hover-stay-time="150"
104   - @tap="chooseFile"
105   - :class="[disabled && 'u-upload__button--disabled']"
106   - :style="[{
  48 + <view v-else class="u-upload__button" :hover-class="!disabled ? 'u-upload__button--hover' : ''"
  49 + hover-stay-time="150" @tap="chooseFile" :class="[disabled && 'u-upload__button--disabled']" :style="[{
107 50 width: $u.addUnit(width),
108 51 height: $u.addUnit(height)
109   - }]"
110   - >
111   - <u-icon
112   - :name="uploadIcon"
113   - size="26"
114   - :color="uploadIconColor"
115   - ></u-icon>
116   - <text
117   - v-if="uploadText"
118   - class="u-upload__button__text"
119   - >{{ uploadText }}</text>
  52 + }]">
  53 + <u-icon :name="uploadIcon" size="26" :color="uploadIconColor"></u-icon>
  54 + <text v-if="uploadText" class="u-upload__button__text">{{ uploadText }}</text>
120 55 </view>
121 56 </template>
122 57 </view>
... ... @@ -125,440 +60,440 @@
125 60 </template>
126 61  
127 62 <script>
128   - import {
129   - chooseFile
130   - } from './utils';
131   - import mixinUp from './mixin.js';
132   - import props from './props.js';
133   - import mpMixin from '../../libs/mixin/mpMixin.js';
134   - import mixin from '../../libs/mixin/mixin.js';
  63 +import mixin from '../../libs/mixin/mixin.js';
  64 +import mpMixin from '../../libs/mixin/mpMixin.js';
  65 +import mixinUp from './mixin.js';
  66 +import props from './props.js';
  67 +import {
  68 + chooseFile
  69 +} from './utils';
135 70  
136   - /**
137   - * upload 上传
138   - * @description 该组件用于上传图片场景
139   - * @tutorial https://uviewui.com/components/upload.html
140   - * @property {String} accept 接受的文件类型, 可选值为all media image file video (默认 'image' )
141   - * @property {String | Array} capture 图片或视频拾取模式,当accept为image类型时设置capture可选额外camera可以直接调起摄像头(默认 ['album', 'camera'] )
142   - * @property {Boolean} compressed 当accept为video时生效,是否压缩视频,默认为true(默认 true )
143   - * @property {String} camera 当accept为video时生效,可选值为back或front(默认 'back' )
144   - * @property {Number} maxDuration 当accept为video时生效,拍摄视频最长拍摄时间,单位秒(默认 60 )
145   - * @property {String} uploadIcon 上传区域的图标,只能内置图标(默认 'camera-fill' )
146   - * @property {String} uploadIconColor 上传区域的图标的字体颜色,只能内置图标(默认 #D3D4D6 )
147   - * @property {Boolean} useBeforeRead 是否开启文件读取前事件(默认 false )
148   - * @property {Boolean} previewFullImage 是否显示组件自带的图片预览功能(默认 true )
149   - * @property {String | Number} maxCount 最大上传数量(默认 52 )
150   - * @property {Boolean} disabled 是否启用(默认 false )
151   - * @property {String} imageMode 预览上传的图片时的裁剪模式,和image组件mode属性一致(默认 'aspectFill' )
152   - * @property {String} name 标识符,可以在回调函数的第二项参数中获取
153   - * @property {Array} sizeType 所选的图片的尺寸, 可选值为original compressed(默认 ['original', 'compressed'] )
154   - * @property {Boolean} multiple 是否开启图片多选,部分安卓机型不支持 (默认 false )
155   - * @property {Boolean} deletable 是否展示删除按钮(默认 true )
156   - * @property {String | Number} maxSize 文件大小限制,单位为byte (默认 Number.MAX_VALUE )
157   - * @property {Array} fileList 显示已上传的文件列表
158   - * @property {String} uploadText 上传区域的提示文字
159   - * @property {String | Number} width 内部预览图片区域和选择图片按钮的区域宽度(默认 80 )
160   - * @property {String | Number} height 内部预览图片区域和选择图片按钮的区域高度(默认 80 )
161   - * @property {Object} customStyle 组件的样式,对象形式
162   - * @event {Function} afterRead 读取后的处理函数
163   - * @event {Function} beforeRead 读取前的处理函数
164   - * @event {Function} oversize 文件超出大小限制
165   - * @event {Function} clickPreview 点击预览图片
166   - * @event {Function} delete 删除图片
167   - * @example <u-upload :action="action" :fileList="fileList" ></u-upload>
168   - */
169   - export default {
170   - name: "u-upload",
171   - mixins: [mpMixin, mixin, mixinUp, props],
172   - data() {
173   - return {
174   - // #ifdef APP-NVUE
175   - successIcon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAKKADAAQAAAABAAAAKAAAAAB65masAAACP0lEQVRYCc3YXygsURwH8K/dpcWyG3LF5u/6/+dKVylSypuUl6uUPMifKMWL8oKEB1EUT1KeUPdR3uTNUsSLxb2udG/cbvInNuvf2rVnazZ/ZndmZ87snjM1Z+Z3zpzfp9+Z5mEAhlvjRtZgCKs+gnPAOcAkkMOR4jEHfItjDvgRxxSQD8cM0BuOCaAvXNCBQrigAsXgggYUiwsK0B9cwIH+4gIKlIILGFAqLiBAOTjFgXJxigJp4BQD0sIpAqSJow6kjSNAFTnRaHJwLenD6Mud52VQAcrBfTd2oyq+HtGaGGWAcnAVcXWoM3bCZrdi+ncPfaAcXE5UKVpdW/vitGPqqAtn98d0gXJwX7Qp6MmegUYVhvmTIezdmHlxJCjpHRTCFerLkRRu4k0aqdajN3sWOo0BK//msHa+xDuPC/oNFMKRhTtM4xjIX0SCNpXL4+7VIaHuyiWEp2L7ahWLf8fejfPdqPmC3mJicORZUp1CQzm+GiphvljGk+PBvWRbxii+xVTj5M6CiZ/tsDufvaXyxEUDxeLIyvu3m0iOyEFWVAkydcVYdyFrE9tQk9iMq6f/GNlvwt3LjQfh60LUrw9/cFyyMJUW/XkLSNMV4Mi6C5ML+ui4x5ClAX9sB9w0wV6wglJwJCv5fOxcr6EstgbGiEw4XcfUry4cWrcEUW8n+ARKxXEJHhw2WG43UKSvwI/TSZgvl7kh0b3XLZaLEy0QmMgLZAVH7J+ALOE+AVnDvQOyiPMAWcW5gSzjCPAV+78S5WE0GrQAAAAASUVORK5CYII=',
176   - // #endif
177   - lists: [],
178   - isInCount: true,
179   - }
180   - },
181   - watch: {
182   - // 监听文件列表的变化,重新整理内部数据
183   - fileList: {
184   - handler() {
185   - this.formatFileList()
186   - },
187   - immediate: true,
188   - deep: true,
  71 +/**
  72 + * upload 上传
  73 + * @description 该组件用于上传图片场景
  74 + * @tutorial https://uviewui.com/components/upload.html
  75 + * @property {String} accept 接受的文件类型, 可选值为all media image file video (默认 'image' )
  76 + * @property {String | Array} capture 图片或视频拾取模式,当accept为image类型时设置capture可选额外camera可以直接调起摄像头(默认 ['album', 'camera'] )
  77 + * @property {Boolean} compressed 当accept为video时生效,是否压缩视频,默认为true(默认 true )
  78 + * @property {String} camera 当accept为video时生效,可选值为back或front(默认 'back' )
  79 + * @property {Number} maxDuration 当accept为video时生效,拍摄视频最长拍摄时间,单位秒(默认 60 )
  80 + * @property {String} uploadIcon 上传区域的图标,只能内置图标(默认 'camera-fill' )
  81 + * @property {String} uploadIconColor 上传区域的图标的字体颜色,只能内置图标(默认 #D3D4D6 )
  82 + * @property {Boolean} useBeforeRead 是否开启文件读取前事件(默认 false )
  83 + * @property {Boolean} previewFullImage 是否显示组件自带的图片预览功能(默认 true )
  84 + * @property {String | Number} maxCount 最大上传数量(默认 52 )
  85 + * @property {Boolean} disabled 是否启用(默认 false )
  86 + * @property {String} imageMode 预览上传的图片时的裁剪模式,和image组件mode属性一致(默认 'aspectFill' )
  87 + * @property {String} name 标识符,可以在回调函数的第二项参数中获取
  88 + * @property {Array} sizeType 所选的图片的尺寸, 可选值为original compressed(默认 ['original', 'compressed'] )
  89 + * @property {Boolean} multiple 是否开启图片多选,部分安卓机型不支持 (默认 false )
  90 + * @property {Boolean} deletable 是否展示删除按钮(默认 true )
  91 + * @property {String | Number} maxSize 文件大小限制,单位为byte (默认 Number.MAX_VALUE )
  92 + * @property {Array} fileList 显示已上传的文件列表
  93 + * @property {String} uploadText 上传区域的提示文字
  94 + * @property {String | Number} width 内部预览图片区域和选择图片按钮的区域宽度(默认 80 )
  95 + * @property {String | Number} height 内部预览图片区域和选择图片按钮的区域高度(默认 80 )
  96 + * @property {Object} customStyle 组件的样式,对象形式
  97 + * @event {Function} afterRead 读取后的处理函数
  98 + * @event {Function} beforeRead 读取前的处理函数
  99 + * @event {Function} oversize 文件超出大小限制
  100 + * @event {Function} clickPreview 点击预览图片
  101 + * @event {Function} delete 删除图片
  102 + * @example <u-upload :action="action" :fileList="fileList" ></u-upload>
  103 + */
  104 +export default {
  105 + name: "u-upload",
  106 + mixins: [mpMixin, mixin, mixinUp, props],
  107 + data() {
  108 + return {
  109 + // #ifdef APP-NVUE
  110 + successIcon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAKKADAAQAAAABAAAAKAAAAAB65masAAACP0lEQVRYCc3YXygsURwH8K/dpcWyG3LF5u/6/+dKVylSypuUl6uUPMifKMWL8oKEB1EUT1KeUPdR3uTNUsSLxb2udG/cbvInNuvf2rVnazZ/ZndmZ87snjM1Z+Z3zpzfp9+Z5mEAhlvjRtZgCKs+gnPAOcAkkMOR4jEHfItjDvgRxxSQD8cM0BuOCaAvXNCBQrigAsXgggYUiwsK0B9cwIH+4gIKlIILGFAqLiBAOTjFgXJxigJp4BQD0sIpAqSJow6kjSNAFTnRaHJwLenD6Mud52VQAcrBfTd2oyq+HtGaGGWAcnAVcXWoM3bCZrdi+ncPfaAcXE5UKVpdW/vitGPqqAtn98d0gXJwX7Qp6MmegUYVhvmTIezdmHlxJCjpHRTCFerLkRRu4k0aqdajN3sWOo0BK//msHa+xDuPC/oNFMKRhTtM4xjIX0SCNpXL4+7VIaHuyiWEp2L7ahWLf8fejfPdqPmC3mJicORZUp1CQzm+GiphvljGk+PBvWRbxii+xVTj5M6CiZ/tsDufvaXyxEUDxeLIyvu3m0iOyEFWVAkydcVYdyFrE9tQk9iMq6f/GNlvwt3LjQfh60LUrw9/cFyyMJUW/XkLSNMV4Mi6C5ML+ui4x5ClAX9sB9w0wV6wglJwJCv5fOxcr6EstgbGiEw4XcfUry4cWrcEUW8n+ARKxXEJHhw2WG43UKSvwI/TSZgvl7kh0b3XLZaLEy0QmMgLZAVH7J+ALOE+AVnDvQOyiPMAWcW5gSzjCPAV+78S5WE0GrQAAAAASUVORK5CYII=',
  111 + // #endif
  112 + lists: [],
  113 + isInCount: true,
  114 + }
  115 + },
  116 + watch: {
  117 + // 监听文件列表的变化,重新整理内部数据
  118 + fileList: {
  119 + handler() {
  120 + this.formatFileList()
189 121 },
  122 + immediate: true,
  123 + deep: true,
190 124 },
191   - // #ifdef VUE3
192   - emits: ['error', 'beforeRead', 'oversize', 'afterRead', 'delete', 'clickPreview'],
193   - // #endif
194   - methods: {
195   - formatFileList() {
196   - const {
197   - fileList = [], maxCount
198   - } = this;
199   - const lists = fileList.map((item) =>
200   - Object.assign(Object.assign({}, item), {
201   - // 如果item.url为本地选择的blob文件的话,无法判断其为video还是image,此处优先通过accept做判断处理
202   - isImage: this.accept === 'image' || uni.$u.test.image(item.url || item.thumb),
203   - isVideo: this.accept === 'video' || uni.$u.test.video(item.url || item.thumb),
204   - deletable: typeof(item.deletable) === 'boolean' ? item.deletable : this.deletable,
205   - })
206   - );
207   - this.lists = lists
208   - this.isInCount = lists.length < maxCount
209   - },
210   - chooseFile() {
211   - const {
212   - maxCount,
213   - multiple,
214   - lists,
215   - disabled
216   - } = this;
217   - if (disabled) return;
218   - // 如果用户传入的是字符串,需要格式化成数组
219   - let capture;
220   - try {
221   - capture = uni.$u.test.array(this.capture) ? this.capture : this.capture.split(',');
222   - }catch(e) {
223   - capture = [];
224   - }
225   - chooseFile(
226   - Object.assign({
227   - accept: this.accept,
228   - multiple: this.multiple,
229   - capture: capture,
230   - compressed: this.compressed,
231   - maxDuration: this.maxDuration,
232   - sizeType: this.sizeType,
233   - camera: this.camera,
234   - }, {
235   - maxCount: maxCount - lists.length,
  125 + },
  126 + // #ifdef VUE3
  127 + emits: ['error', 'beforeRead', 'oversize', 'afterRead', 'delete', 'clickPreview'],
  128 + // #endif
  129 + methods: {
  130 + formatFileList() {
  131 + const {
  132 + fileList = [], maxCount
  133 + } = this;
  134 + const lists = fileList.map((item) =>
  135 + Object.assign(Object.assign({}, item), {
  136 + // 如果item.url为本地选择的blob文件的话,无法判断其为video还是image,此处优先通过accept做判断处理
  137 + isImage: this.accept === 'image' || uni.$u.test.image(item.url || item.thumb),
  138 + isVideo: this.accept === 'video' || uni.$u.test.video(item.url || item.thumb),
  139 + deletable: typeof (item.deletable) === 'boolean' ? item.deletable : this.deletable,
  140 + })
  141 + );
  142 + this.lists = lists
  143 + this.isInCount = lists.length < maxCount
  144 + },
  145 + chooseFile() {
  146 + const {
  147 + maxCount,
  148 + multiple,
  149 + lists,
  150 + disabled
  151 + } = this;
  152 + if (disabled) return;
  153 + // 如果用户传入的是字符串,需要格式化成数组
  154 + let capture;
  155 + try {
  156 + capture = uni.$u.test.array(this.capture) ? this.capture : this.capture.split(',');
  157 + } catch (e) {
  158 + capture = [];
  159 + }
  160 + chooseFile(
  161 + Object.assign({
  162 + accept: this.accept,
  163 + multiple: this.multiple,
  164 + capture: capture,
  165 + compressed: this.compressed,
  166 + maxDuration: this.maxDuration,
  167 + sizeType: this.sizeType,
  168 + camera: this.camera,
  169 + }, {
  170 + maxCount: maxCount - lists.length,
  171 + })
  172 + )
  173 + .then((res) => {
  174 + this.onBeforeRead(multiple ? res : res[0]);
  175 + })
  176 + .catch((error) => {
  177 + this.$emit('error', error);
  178 + });
  179 + },
  180 + // 文件读取之前
  181 + onBeforeRead(file) {
  182 + const {
  183 + beforeRead,
  184 + useBeforeRead,
  185 + } = this;
  186 + let res = true
  187 + // beforeRead是否为一个方法
  188 + if (uni.$u.test.func(beforeRead)) {
  189 + // 如果用户定义了此方法,则去执行此方法,并传入读取的文件回调
  190 + res = beforeRead(file, this.getDetail());
  191 + }
  192 + if (useBeforeRead) {
  193 + res = new Promise((resolve, reject) => {
  194 + this.$emit(
  195 + 'beforeRead',
  196 + Object.assign(Object.assign({
  197 + file
  198 + }, this.getDetail()), {
  199 + callback: (ok) => {
  200 + ok ? resolve() : reject();
  201 + },
236 202 })
237   - )
238   - .then((res) => {
239   - this.onBeforeRead(multiple ? res : res[0]);
240   - })
241   - .catch((error) => {
242   - this.$emit('error', error);
243   - });
244   - },
245   - // 文件读取之前
246   - onBeforeRead(file) {
247   - const {
248   - beforeRead,
249   - useBeforeRead,
250   - } = this;
251   - let res = true
252   - // beforeRead是否为一个方法
253   - if (uni.$u.test.func(beforeRead)) {
254   - // 如果用户定义了此方法,则去执行此方法,并传入读取的文件回调
255   - res = beforeRead(file, this.getDetail());
256   - }
257   - if (useBeforeRead) {
258   - res = new Promise((resolve, reject) => {
259   - this.$emit(
260   - 'beforeRead',
261   - Object.assign(Object.assign({
262   - file
263   - }, this.getDetail()), {
264   - callback: (ok) => {
265   - ok ? resolve() : reject();
266   - },
267   - })
268   - );
269   - });
270   - }
271   - if (!res) {
272   - return;
273   - }
274   - if (uni.$u.test.promise(res)) {
275   - res.then((data) => this.onAfterRead(data || file));
276   - } else {
277   - this.onAfterRead(file);
278   - }
279   - },
280   - getDetail(index) {
281   - return {
282   - name: this.name,
283   - index: index == null ? this.fileList.length : index,
284   - };
285   - },
286   - onAfterRead(file) {
287   - const {
288   - maxSize,
289   - afterRead
290   - } = this;
291   - const oversize = Array.isArray(file) ?
292   - file.some((item) => item.size > maxSize) :
293   - file.size > maxSize;
294   - if (oversize) {
295   - this.$emit('oversize', Object.assign({
296   - file
297   - }, this.getDetail()));
298   - return;
299   - }
300   - if (typeof afterRead === 'function') {
301   - afterRead(file, this.getDetail());
302   - }
303   - this.$emit('afterRead', Object.assign({
  203 + );
  204 + });
  205 + }
  206 + if (!res) {
  207 + return;
  208 + }
  209 + if (uni.$u.test.promise(res)) {
  210 + res.then((data) => this.onAfterRead(data || file));
  211 + } else {
  212 + this.onAfterRead(file);
  213 + }
  214 + },
  215 + getDetail(index) {
  216 + return {
  217 + name: this.name,
  218 + index: index == null ? this.fileList.length : index,
  219 + };
  220 + },
  221 + onAfterRead(file) {
  222 + const {
  223 + maxSize,
  224 + afterRead
  225 + } = this;
  226 + const oversize = Array.isArray(file) ?
  227 + file.some((item) => item.size > maxSize) :
  228 + file.size > maxSize;
  229 + if (oversize) {
  230 + this.$emit('oversize', Object.assign({
304 231 file
305 232 }, this.getDetail()));
306   - },
307   - deleteItem(index) {
308   - this.$emit(
309   - 'delete',
310   - Object.assign(Object.assign({}, this.getDetail(index)), {
311   - file: this.fileList[index],
312   - })
313   - );
314   - },
315   - // 预览图片
316   - onPreviewImage(item) {
317   - if (!item.isImage || !this.previewFullImage) return
318   - uni.previewImage({
319   - // 先filter找出为图片的item,再返回filter结果中的图片url
320   - urls: this.lists.filter((item) => this.accept === 'image' || uni.$u.test.image(item.url || item.thumb)).map((item) => item.url || item.thumb),
321   - current: item.url || item.thumb,
322   - fail() {
323   - uni.$u.toast('预览图片失败')
324   - },
325   - });
326   - },
327   - onPreviewVideo(event) {
328   - if (!this.data.previewFullImage) return;
329   - const {
330   - index
331   - } = event.currentTarget.dataset;
332   - const {
333   - lists
334   - } = this.data;
335   - wx.previewMedia({
336   - sources: lists
337   - .filter((item) => isVideoFile(item))
338   - .map((item) =>
339   - Object.assign(Object.assign({}, item), {
340   - type: 'video'
341   - })
342   - ),
343   - current: index,
344   - fail() {
345   - uni.$u.toast('预览视频失败')
346   - },
347   - });
348   - },
349   - onClickPreview(event) {
350   - const {
351   - index
352   - } = event.currentTarget.dataset;
353   - const item = this.data.lists[index];
354   - this.$emit(
355   - 'clickPreview',
356   - Object.assign(Object.assign({}, item), this.getDetail(index))
357   - );
  233 + return;
  234 + }
  235 + if (typeof afterRead === 'function') {
  236 + afterRead(file, this.getDetail());
358 237 }
  238 + this.$emit('afterRead', Object.assign({
  239 + file
  240 + }, this.getDetail()));
  241 + },
  242 + deleteItem(index) {
  243 + this.$emit(
  244 + 'delete',
  245 + Object.assign(Object.assign({}, this.getDetail(index)), {
  246 + file: this.fileList[index],
  247 + })
  248 + );
  249 + },
  250 + // 预览图片
  251 + onPreviewImage(item) {
  252 + if (!item.isImage || !this.previewFullImage) return
  253 + uni.previewImage({
  254 + // 先filter找出为图片的item,再返回filter结果中的图片url
  255 + urls: this.lists.filter((item) => this.accept === 'image' || uni.$u.test.image(item.url || item.thumb)).map((item) => item.url || item.thumb),
  256 + current: item.url || item.thumb,
  257 + fail() {
  258 + uni.$u.toast('预览图片失败')
  259 + },
  260 + });
  261 + },
  262 + onPreviewVideo(event) {
  263 + if (!this.data.previewFullImage) return;
  264 + const {
  265 + index
  266 + } = event.currentTarget.dataset;
  267 + const {
  268 + lists
  269 + } = this.data;
  270 + wx.previewMedia({
  271 + sources: lists
  272 + .filter((item) => isVideoFile(item))
  273 + .map((item) =>
  274 + Object.assign(Object.assign({}, item), {
  275 + type: 'video'
  276 + })
  277 + ),
  278 + current: index,
  279 + fail() {
  280 + uni.$u.toast('预览视频失败')
  281 + },
  282 + });
  283 + },
  284 + onClickPreview(event) {
  285 + const {
  286 + index
  287 + } = event.currentTarget.dataset;
  288 + const item = this.data.lists[index];
  289 + this.$emit(
  290 + 'clickPreview',
  291 + Object.assign(Object.assign({}, item), this.getDetail(index))
  292 + );
359 293 }
360 294 }
  295 +}
361 296 </script>
362 297  
363 298 <style lang="scss" scoped>
364   - @import '../../libs/css/components.scss';
365   - $u-upload-preview-border-radius: 2px !default;
366   - $u-upload-preview-margin: 0 8px 8px 0 !default;
367   - $u-upload-image-width:80px !default;
368   - $u-upload-image-height:$u-upload-image-width;
369   - $u-upload-other-bgColor: rgb(242, 242, 242) !default;
370   - $u-upload-other-flex:1 !default;
371   - $u-upload-text-font-size:11px !default;
372   - $u-upload-text-color:$u-tips-color !default;
373   - $u-upload-text-margin-top:2px !default;
374   - $u-upload-deletable-right:0 !default;
375   - $u-upload-deletable-top:0 !default;
376   - $u-upload-deletable-bgColor:rgb(55, 55, 55) !default;
377   - $u-upload-deletable-height:14px !default;
378   - $u-upload-deletable-width:$u-upload-deletable-height;
379   - $u-upload-deletable-boder-bottom-left-radius:100px !default;
380   - $u-upload-deletable-zIndex:3 !default;
381   - $u-upload-success-bottom:0 !default;
382   - $u-upload-success-right:0 !default;
383   - $u-upload-success-border-style:solid !default;
384   - $u-upload-success-border-top-color:transparent !default;
385   - $u-upload-success-border-left-color:transparent !default;
386   - $u-upload-success-border-bottom-color: $u-success !default;
387   - $u-upload-success-border-right-color:$u-upload-success-border-bottom-color;
388   - $u-upload-success-border-width:9px !default;
389   - $u-upload-icon-top:0px !default;
390   - $u-upload-icon-right:0px !default;
391   - $u-upload-icon-h5-top:1px !default;
392   - $u-upload-icon-h5-right:0 !default;
393   - $u-upload-icon-width:16px !default;
394   - $u-upload-icon-height:$u-upload-icon-width;
395   - $u-upload-success-icon-bottom:-10px !default;
396   - $u-upload-success-icon-right:-10px !default;
397   - $u-upload-status-right:0 !default;
398   - $u-upload-status-left:0 !default;
399   - $u-upload-status-bottom:0 !default;
400   - $u-upload-status-top:0 !default;
401   - $u-upload-status-bgColor:rgba(0, 0, 0, 0.5) !default;
402   - $u-upload-status-icon-Zindex:1 !default;
403   - $u-upload-message-font-size:12px !default;
404   - $u-upload-message-color:#FFFFFF !default;
405   - $u-upload-message-margin-top:5px !default;
406   - $u-upload-button-width:80px !default;
407   - $u-upload-button-height:$u-upload-button-width;
408   - $u-upload-button-bgColor:rgb(244, 245, 247) !default;
409   - $u-upload-button-border-radius:2px !default;
410   - $u-upload-botton-margin: 0 8px 8px 0 !default;
411   - $u-upload-text-font-size:11px !default;
412   - $u-upload-text-color:$u-tips-color !default;
413   - $u-upload-text-margin-top: 2px !default;
414   - $u-upload-hover-bgColor:rgb(230, 231, 233) !default;
415   - $u-upload-disabled-opacity:.5 !default;
  299 +@import '../../libs/css/components.scss';
  300 +$u-upload-preview-border-radius: 2px !default;
  301 +$u-upload-preview-margin: 0 8px 8px 0 !default;
  302 +$u-upload-image-width: 80px !default;
  303 +$u-upload-image-height: $u-upload-image-width;
  304 +$u-upload-other-bgColor: rgb(242, 242, 242) !default;
  305 +$u-upload-other-flex: 1 !default;
  306 +$u-upload-text-font-size: 11px !default;
  307 +$u-upload-text-color: $u-tips-color !default;
  308 +$u-upload-text-margin-top: 2px !default;
  309 +$u-upload-deletable-right: 0 !default;
  310 +$u-upload-deletable-top: 0 !default;
  311 +$u-upload-deletable-bgColor: rgb(55, 55, 55) !default;
  312 +$u-upload-deletable-height: 14px !default;
  313 +$u-upload-deletable-width: $u-upload-deletable-height;
  314 +$u-upload-deletable-boder-bottom-left-radius: 100px !default;
  315 +$u-upload-deletable-zIndex: 3 !default;
  316 +$u-upload-success-bottom: 0 !default;
  317 +$u-upload-success-right: 0 !default;
  318 +$u-upload-success-border-style: solid !default;
  319 +$u-upload-success-border-top-color: transparent !default;
  320 +$u-upload-success-border-left-color: transparent !default;
  321 +$u-upload-success-border-bottom-color: $u-success !default;
  322 +$u-upload-success-border-right-color: $u-upload-success-border-bottom-color;
  323 +$u-upload-success-border-width: 9px !default;
  324 +$u-upload-icon-top: 0px !default;
  325 +$u-upload-icon-right: 0px !default;
  326 +$u-upload-icon-h5-top: 1px !default;
  327 +$u-upload-icon-h5-right: 0 !default;
  328 +$u-upload-icon-width: 16px !default;
  329 +$u-upload-icon-height: $u-upload-icon-width;
  330 +$u-upload-success-icon-bottom: -10px !default;
  331 +$u-upload-success-icon-right: -10px !default;
  332 +$u-upload-status-right: 0 !default;
  333 +$u-upload-status-left: 0 !default;
  334 +$u-upload-status-bottom: 0 !default;
  335 +$u-upload-status-top: 0 !default;
  336 +$u-upload-status-bgColor: rgba(0, 0, 0, 0.5) !default;
  337 +$u-upload-status-icon-Zindex: 1 !default;
  338 +$u-upload-message-font-size: 12px !default;
  339 +$u-upload-message-color: #FFFFFF !default;
  340 +$u-upload-message-margin-top: 5px !default;
  341 +$u-upload-button-width: 80px !default;
  342 +$u-upload-button-height: $u-upload-button-width;
  343 +$u-upload-button-bgColor: rgb(244, 245, 247) !default;
  344 +$u-upload-button-border-radius: 2px !default;
  345 +$u-upload-botton-margin: 0 8px 8px 0 !default;
  346 +$u-upload-text-font-size: 11px !default;
  347 +$u-upload-text-color: $u-tips-color !default;
  348 +$u-upload-text-margin-top: 2px !default;
  349 +$u-upload-hover-bgColor: rgb(230, 231, 233) !default;
  350 +$u-upload-disabled-opacity: .5 !default;
416 351  
417   - .u-upload {
418   - @include flex(column);
  352 +.u-upload {
  353 + @include flex(column);
  354 + flex: 1;
  355 +
  356 + &__wrap {
  357 + @include flex;
  358 + flex-wrap: wrap;
419 359 flex: 1;
420 360  
421   - &__wrap {
  361 + &__preview {
  362 + border-radius: $u-upload-preview-border-radius;
  363 + margin: $u-upload-preview-margin;
  364 + position: relative;
  365 + overflow: hidden;
422 366 @include flex;
423   - flex-wrap: wrap;
424   - flex: 1;
425   -
426   - &__preview {
427   - border-radius: $u-upload-preview-border-radius;
428   - margin: $u-upload-preview-margin;
429   - position: relative;
430   - overflow: hidden;
431   - @include flex;
432 367  
433   - &__image {
434   - width: $u-upload-image-width;
435   - height: $u-upload-image-height;
436   - }
  368 + &__image {
  369 + width: $u-upload-image-width;
  370 + height: $u-upload-image-height;
  371 + }
437 372  
438   - &__other {
439   - width: $u-upload-image-width;
440   - height: $u-upload-image-height;
441   - background-color: $u-upload-other-bgColor;
442   - flex: $u-upload-other-flex;
443   - @include flex(column);
444   - justify-content: center;
445   - align-items: center;
  373 + &__other {
  374 + width: $u-upload-image-width;
  375 + height: $u-upload-image-height;
  376 + background-color: $u-upload-other-bgColor;
  377 + flex: $u-upload-other-flex;
  378 + @include flex(column);
  379 + justify-content: center;
  380 + align-items: center;
446 381  
447   - &__text {
448   - font-size: $u-upload-text-font-size;
449   - color: $u-upload-text-color;
450   - margin-top: $u-upload-text-margin-top;
451   - }
  382 + &__text {
  383 + font-size: $u-upload-text-font-size;
  384 + color: $u-upload-text-color;
  385 + margin-top: $u-upload-text-margin-top;
452 386 }
453 387 }
454 388 }
  389 + }
455 390  
456   - &__deletable {
457   - position: absolute;
458   - top: $u-upload-deletable-top;
459   - right: $u-upload-deletable-right;
460   - background-color: $u-upload-deletable-bgColor;
461   - height: $u-upload-deletable-height;
462   - width: $u-upload-deletable-width;
463   - @include flex;
464   - border-bottom-left-radius: $u-upload-deletable-boder-bottom-left-radius;
465   - align-items: center;
466   - justify-content: center;
467   - z-index: $u-upload-deletable-zIndex;
  391 + &__deletable {
  392 + position: absolute;
  393 + top: $u-upload-deletable-top;
  394 + right: $u-upload-deletable-right;
  395 + background-color: $u-upload-deletable-bgColor;
  396 + height: $u-upload-deletable-height;
  397 + width: $u-upload-deletable-width;
  398 + @include flex;
  399 + border-bottom-left-radius: $u-upload-deletable-boder-bottom-left-radius;
  400 + align-items: center;
  401 + justify-content: center;
  402 + z-index: $u-upload-deletable-zIndex;
468 403  
469   - &__icon {
470   - position: absolute;
471   - transform: scale(0.7);
472   - top: $u-upload-icon-top;
473   - right: $u-upload-icon-right;
474   - /* #ifdef H5 */
475   - top: $u-upload-icon-h5-top;
476   - right: $u-upload-icon-h5-right;
477   - /* #endif */
478   - }
  404 + &__icon {
  405 + position: absolute;
  406 + transform: scale(0.7);
  407 + top: $u-upload-icon-top;
  408 + right: $u-upload-icon-right;
  409 + /* #ifdef H5 */
  410 + top: $u-upload-icon-h5-top;
  411 + right: $u-upload-icon-h5-right;
  412 + /* #endif */
479 413 }
  414 + }
480 415  
481   - &__success {
482   - position: absolute;
483   - bottom: $u-upload-success-bottom;
484   - right: $u-upload-success-right;
485   - @include flex;
486   - // 由于weex(nvue)为阿里巴巴的KPI(部门业绩考核)的laji产物,不支持css绘制三角形
487   - // 所以在nvue下使用图片,非nvue下使用css实现
  416 + &__success {
  417 + position: absolute;
  418 + bottom: $u-upload-success-bottom;
  419 + right: $u-upload-success-right;
  420 + @include flex;
  421 + // 由于weex(nvue)为阿里巴巴的KPI(部门业绩考核)的laji产物,不支持css绘制三角形
  422 + // 所以在nvue下使用图片,非nvue下使用css实现
  423 + /* #ifndef APP-NVUE */
  424 + border-style: $u-upload-success-border-style;
  425 + border-top-color: $u-upload-success-border-top-color;
  426 + border-left-color: $u-upload-success-border-left-color;
  427 + border-bottom-color: $u-upload-success-border-bottom-color;
  428 + border-right-color: $u-upload-success-border-right-color;
  429 + border-width: $u-upload-success-border-width;
  430 + align-items: center;
  431 + justify-content: center;
  432 + /* #endif */
  433 +
  434 + &__icon {
488 435 /* #ifndef APP-NVUE */
489   - border-style: $u-upload-success-border-style;
490   - border-top-color: $u-upload-success-border-top-color;
491   - border-left-color: $u-upload-success-border-left-color;
492   - border-bottom-color: $u-upload-success-border-bottom-color;
493   - border-right-color: $u-upload-success-border-right-color;
494   - border-width: $u-upload-success-border-width;
495   - align-items: center;
496   - justify-content: center;
  436 + position: absolute;
  437 + transform: scale(0.7);
  438 + bottom: $u-upload-success-icon-bottom;
  439 + right: $u-upload-success-icon-right;
  440 + /* #endif */
  441 + /* #ifdef APP-NVUE */
  442 + width: $u-upload-icon-width;
  443 + height: $u-upload-icon-height;
497 444 /* #endif */
498   -
499   - &__icon {
500   - /* #ifndef APP-NVUE */
501   - position: absolute;
502   - transform: scale(0.7);
503   - bottom: $u-upload-success-icon-bottom;
504   - right: $u-upload-success-icon-right;
505   - /* #endif */
506   - /* #ifdef APP-NVUE */
507   - width: $u-upload-icon-width;
508   - height: $u-upload-icon-height;
509   - /* #endif */
510   - }
511 445 }
  446 + }
512 447  
513   - &__status {
514   - position: absolute;
515   - top: $u-upload-status-top;
516   - bottom: $u-upload-status-bottom;
517   - left: $u-upload-status-left;
518   - right: $u-upload-status-right;
519   - background-color: $u-upload-status-bgColor;
520   - @include flex(column);
521   - align-items: center;
522   - justify-content: center;
  448 + &__status {
  449 + position: absolute;
  450 + top: $u-upload-status-top;
  451 + bottom: $u-upload-status-bottom;
  452 + left: $u-upload-status-left;
  453 + right: $u-upload-status-right;
  454 + background-color: $u-upload-status-bgColor;
  455 + @include flex(column);
  456 + align-items: center;
  457 + justify-content: center;
523 458  
524   - &__icon {
525   - position: relative;
526   - z-index: $u-upload-status-icon-Zindex;
527   - }
  459 + &__icon {
  460 + position: relative;
  461 + z-index: $u-upload-status-icon-Zindex;
  462 + }
528 463  
529   - &__message {
530   - font-size: $u-upload-message-font-size;
531   - color: $u-upload-message-color;
532   - margin-top: $u-upload-message-margin-top;
533   - }
  464 + &__message {
  465 + font-size: $u-upload-message-font-size;
  466 + color: $u-upload-message-color;
  467 + margin-top: $u-upload-message-margin-top;
534 468 }
  469 + }
535 470  
536   - &__button {
537   - @include flex(column);
538   - align-items: center;
539   - justify-content: center;
540   - width: $u-upload-button-width;
541   - height: $u-upload-button-height;
542   - background-color: $u-upload-button-bgColor;
543   - border-radius: $u-upload-button-border-radius;
544   - margin: $u-upload-botton-margin;
545   - /* #ifndef APP-NVUE */
546   - box-sizing: border-box;
547   - /* #endif */
  471 + &__button {
  472 + @include flex(column);
  473 + align-items: center;
  474 + justify-content: center;
  475 + width: $u-upload-button-width;
  476 + height: $u-upload-button-height;
  477 + background-color: $u-upload-button-bgColor;
  478 + border-radius: $u-upload-button-border-radius;
  479 + margin: $u-upload-botton-margin;
  480 + /* #ifndef APP-NVUE */
  481 + box-sizing: border-box;
  482 + /* #endif */
548 483  
549   - &__text {
550   - font-size: $u-upload-text-font-size;
551   - color: $u-upload-text-color;
552   - margin-top: $u-upload-text-margin-top;
553   - }
  484 + &__text {
  485 + font-size: $u-upload-text-font-size;
  486 + color: $u-upload-text-color;
  487 + margin-top: $u-upload-text-margin-top;
  488 + }
554 489  
555   - &--hover {
556   - background-color: $u-upload-hover-bgColor;
557   - }
  490 + &--hover {
  491 + background-color: $u-upload-hover-bgColor;
  492 + }
558 493  
559   - &--disabled {
560   - opacity: $u-upload-disabled-opacity;
561   - }
  494 + &--disabled {
  495 + opacity: $u-upload-disabled-opacity;
562 496 }
563 497 }
  498 +}
564 499 </style>
... ...
garbage-removal/src/z-paging/changelog.md 0 → 100644
  1 +## 2.6.2(2023-10-31)
  2 +1.`修复` 在源码中有异常字符导致的在vue3中编译报错的问题。
  3 +2.`修复` 在微信小程序中`z-paging-refresh`的height无效的问题(by xiaohe0601)。
  4 +近期更新:
  5 +=============================
  6 +1.`新增` 手动更新自定义下拉刷新view高度方法。
  7 +2.`新增` 点击返回顶部按钮添加事件监听&支持拦截。
  8 +3.`新增` 是否开启下拉刷新状态栏占位,适用于隐藏导航栏时,下拉刷新需要避开状态栏高度的情况。
  9 +4.`新增` 支持配置网络请求失败触发`reject`。
  10 +5.`修复` 显示空数据图时,滚动到底部依然可以加载更多的问题。
  11 +6.`修复` 在vue2中底部加载更多相关`slot`使用`template`插入无效的问题。
  12 +7.`修复` `complete`的`Promise`可能无效的问题。
  13 +8.`优化` `hooks`判断`z-paging`为空则不调用。
  14 +
  15 +
  16 +
... ...
garbage-removal/src/z-paging/package.json 0 → 100644
  1 +{
  2 + "id": "z-paging",
  3 + "name": "z-paging",
  4 + "displayName": "【z-paging下拉刷新、上拉加载】高性能,全平台兼容。支持虚拟列表,支持nvue、vue3",
  5 + "version": "2.6.2",
  6 + "description": "超简单、低耦合!使用wxs+renderjs实现。支持长列表优化,支持自定义下拉刷新、上拉加载更多,支持自动管理空数据图、点击返回顶部,支持聊天分页、本地分页,支持国际化等100+项配置",
  7 + "keywords": [
  8 + "下拉刷新",
  9 + "上拉加载",
  10 + "分页器",
  11 + "nvue",
  12 + "虚拟列表"
  13 +],
  14 + "repository": "https://github.com/SmileZXLee/uni-z-paging",
  15 + "engines": {
  16 + "HBuilderX": "^3.0.7"
  17 + },
  18 +"dcloudext": {
  19 + "sale": {
  20 + "regular": {
  21 + "price": "0.00"
  22 + },
  23 + "sourcecode": {
  24 + "price": "0.00"
  25 + }
  26 + },
  27 + "contact": {
  28 + "qq": "393727164"
  29 + },
  30 + "declaration": {
  31 + "ads": "无",
  32 + "data": "无",
  33 + "permissions": "无"
  34 + },
  35 + "npmurl": "https://www.npmjs.com/package/z-paging",
  36 + "type": "component-vue"
  37 + },
  38 + "uni_modules": {
  39 + "dependencies": [],
  40 + "encrypt": [],
  41 + "platforms": {
  42 + "cloud": {
  43 + "tcb": "y",
  44 + "aliyun": "y"
  45 + },
  46 + "client": {
  47 + "App": {
  48 + "app-vue": "y",
  49 + "app-nvue": "y"
  50 + },
  51 + "H5-mobile": {
  52 + "Safari": "y",
  53 + "Android Browser": "y",
  54 + "微信浏览器(Android)": "y",
  55 + "QQ浏览器(Android)": "y"
  56 + },
  57 + "H5-pc": {
  58 + "Chrome": "y",
  59 + "IE": "y",
  60 + "Edge": "y",
  61 + "Firefox": "y",
  62 + "Safari": "y"
  63 + },
  64 + "小程序": {
  65 + "微信": "y",
  66 + "阿里": "y",
  67 + "百度": "y",
  68 + "字节跳动": "y",
  69 + "QQ": "y",
  70 + "钉钉": "y",
  71 + "快手": "y",
  72 + "飞书": "y",
  73 + "京东": "y"
  74 + },
  75 + "快应用": {
  76 + "华为": "y",
  77 + "联盟": "y"
  78 + },
  79 + "Vue": {
  80 + "vue2": "y",
  81 + "vue3": "y"
  82 + }
  83 + }
  84 + }
  85 + }
  86 +}
0 87 \ No newline at end of file
... ...
garbage-removal/src/z-paging/readme.md 0 → 100644
  1 +# z-paging
  2 +
  3 +<p align="center">
  4 + <img alt="logo" src="https://z-paging.zxlee.cn/img/title-logo.png" height="100" style="margin-bottom: 50px;">
  5 +</p>
  6 +
  7 +[![version](https://img.shields.io/badge/version-2.6.2-blue)](https://github.com/SmileZXLee/uni-z-paging)
  8 +[![license](https://img.shields.io/github/license/SmileZXLee/uni-z-paging)](https://en.wikipedia.org/wiki/MIT_License)
  9 +
  10 +### 文档地址:[https://z-paging.zxlee.cn](https://z-paging.zxlee.cn)
  11 +
  12 +### 更新组件前,请注意[版本差异](https://z-paging.zxlee.cn/start/upgrade-guide.html)
  13 +
  14 +***
  15 +### 功能&特点
  16 +* 【配置简单】仅需两步(绑定网络请求方法、绑定分页结果数组)轻松完成完整下拉刷新,上拉加载更多功能。
  17 +* 【低耦合,低侵入】分页自动管理。在page中无需处理任何分页相关逻辑,无需在data中定义任何分页相关变量,全由z-paging内部处理。
  18 +* 【超灵活,支持各种类型自定义】支持自定义下拉刷新,自定义上拉加载更多等各种自定义效果;支持使用内置自动分页,同时也支持通过监听下拉刷新和滚动到底部事件自行处理;支持使用自带全屏布局规范,同时也支持将z-paging自由放在任意容器中。
  19 +* 【功能丰富】支持国际化,支持自定义且自动管理空数据图,支持主题模式切换,支持本地分页,支持聊天分页模式,支持展示最后更新时间,支持吸顶效果,支持内部scroll-view滚动与页面滚动,支持一键滚动到顶部等诸多功能。
  20 +* 【全平台兼容】支持vue、nvue,vue2、vue3,支持h5、app及各家小程序。
  21 +* 【高性能】在app-vue、h5、微信小程序、QQ小程序上使用wxs+renderjs从视图层实现下拉刷新;支持虚拟列表,轻松渲染万级数据!
  22 +
  23 +***
  24 +### 反馈qq群
  25 +* 官方1群`已满`:[790460711](https://jq.qq.com/?_wv=1027&k=vU2fKZZH)
  26 +
  27 +* 官方2群:[371624008](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=avPmibADf2TNi4LxkIwjCE5vbfXpa-r1&authKey=dQ%2FVDAR87ONxI4b32Py%2BvmXbhnopjHN7%2FJPtdsqJdsCPFZB6zDQ17L06Uh0kITUZ&noverify=0&group_code=371624008)
  28 +
  29 +***
  30 +
  31 +### 预览
  32 +
  33 +***
  34 +
  35 +| 自定义下拉刷新效果演示 | 滑动切换选项卡+吸顶演示 |
  36 +| :----------------------------------------------------------: | :----------------------------------------------------------: |
  37 +| ![](https://z-paging.zxlee.cn/public/img/z-paging-demo5.gif) | ![](https://z-paging.zxlee.cn/public/img/z-paging-demo6.gif) |
  38 +
  39 +| 聊天记录模式演示 | 虚拟列表(流畅渲染1万+条)演示 |
  40 +| :----------------------------------------------------------: | :----------------------------------------------------------: |
  41 +| ![](https://z-paging.zxlee.cn/public/img/z-paging-demo7.gif) | ![](https://z-paging.zxlee.cn/public/img/z-paging-demo8.gif) |
  42 +
  43 +### 在线demo体验地址:
  44 +
  45 +* [https://demo.z-paging.zxlee.cn](https://demo.z-paging.zxlee.cn)
  46 +
  47 +| 扫码体验 |
  48 +| ------------------------------------------------------------ |
  49 +| ![](https://z-paging.zxlee.cn/public/img/code.png) |
  50 +
  51 +### demo下载
  52 +* 支持vue2&vue3的`选项式api`写法demo下载,请点击页面右上角的【使用HBuilderX导入示例项目】或【下载示例项目ZIP】。
  53 +* 支持vue3的`组合式api`写法demo下载,请访问[github](https://github.com/SmileZXLee/uni-z-paging)。
0 54 \ No newline at end of file
... ...