Browse Source

fix: infiniteloading 组件review内容修改 (#1904)

* fix: 修复 ImagePreview 在Taro编译成H5后报错的问题

* fix: 地址关闭时, Close 事件触发两次问题解决

* feat: 组件DatePicker 添加双向绑定

* docs: 组件Picker文档修改

* feat: 组件Picker与DatePicker新增属性safe-area-inset-bottom

* feat: imagepreview

* fix: 组件imagepreview点击视频遮罩关闭(#1729)

* fix: 解决 Picker 在微信小程序中无法使用问题 (#1774)

* fix: 修改 Picker 组件 v-model 失效问题

* fix: 组件NoticeBar修改height之后,垂直轮播会卡顿

* fix: 删除Datepicker Demo演示多余内容

* fix: 组件Picker在JD小程序上适配

* fix: 组件Address京东小程序适配

* feat: 京东小程序适配

* fix: 删除空格

* feat: 删除console

* fix: 京东小程序imagepreview适配

* fix: 修复 imagepreview 动态设置 initNo 显示不正确问题

* fix: 组件 InfiniteLoading 某些情况下会错误触发下拉刷新#1819

* fix: 删除pullrefresh

* feat: 组件 imagepreview瘦身

* feat: 组件Picker 瘦身

* fix: address线上问题修改

* fix: 完善imagepreview

* feat: 公共函数提取

* feat: 函数式改用 createComponent

* fix: 文件回撤

* feat: 单元测试修改

* fix: 组件popover样式问题修改

* feat: 新增 clamp 函数

* fix: 组件Infiniteloading Review 内容修改

* fix: 组件Infiniteloading问题更新
yangxiaolu1993 3 years ago
parent
commit
ac14c73f08

+ 4 - 2
src/config.json

@@ -708,14 +708,16 @@
         {
           "version": "3.0.0",
           "name": "InfiniteLoading",
-          "taro": true,
+          "taro": false,
           "tarodoc": true,
           "type": "component",
           "cName": "滚动加载",
           "desc": "列表滚动到底部自动加载更多数据",
           "sort": 15,
           "show": true,
-          "author": "yangxiaolu"
+          "author": "yangxiaolu",
+          "exportEmpty": false,
+          "exportEmptyTaro": false
         },
         {
           "version": "3.0.0",

+ 4 - 1
src/packages/__VUE/infiniteloading/doc.en-US.md

@@ -8,10 +8,12 @@ Scrolling to the bottom of the list automatically loads more data.
 
 ```javascript
   import { createApp } from 'vue';
-  import { InfiniteLoading } from '@nutui/nutui';
+  import { InfiniteLoading, Icon } from '@nutui/nutui';
 
   const app = createApp();
   app.use(InfiniteLoading);
+  app.use(Icon);
+  
 ```
 
 ### Basic Usage
@@ -274,5 +276,6 @@ Scrolling to the bottom of the list automatically loads more data.
 
 | Attribute | Description  | 
 |--------|----------------|
+| default  | Scroll content |
 | loading  | Loading text |
 | finished  | Finished text |

+ 4 - 1
src/packages/__VUE/infiniteloading/doc.md

@@ -8,10 +8,12 @@
 
 ```javascript
   import { createApp } from 'vue';
-  import { InfiniteLoading } from '@nutui/nutui';
+  import { InfiniteLoading, Icon } from '@nutui/nutui';
 
   const app = createApp();
   app.use(InfiniteLoading);
+  app.use(Icon);
+  
 ```
 
 ### 基础用法
@@ -269,5 +271,6 @@
 
 | 名称 | 说明           | 
 |--------|----------------|
+| default  | 自定义滚动列表 |
 | loading  | 自定义底部记载中提示 |
 | finished  | 自定义加载完成后的提示文案 |

+ 2 - 0
src/packages/__VUE/infiniteloading/index.scss

@@ -25,6 +25,8 @@
     justify-content: center;
     width: 100%;
     overflow: hidden;
+    transition-property: height;
+    transition-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1);
     .top-box {
       width: 100%;
       display: flex;

+ 0 - 228
src/packages/__VUE/infiniteloading/index.taro.vue

@@ -1,228 +0,0 @@
-<template>
-  <Nut-Scroll-View
-    :class="classes"
-    scrollY="true"
-    style="height: 100%"
-    id="scroller"
-    @scrolltolower="lower"
-    @scroll="scroll"
-    @touchstart="touchStart"
-    @touchmove="touchMove"
-    @touchend="touchEnd"
-  >
-    <view class="nut-infinite-top" :style="getStyle">
-      <view class="top-box" id="refreshTop">
-        <nut-icon class="top-img" v-bind="$attrs" :name="pullIcon"></nut-icon>
-        <view class="top-text">{{ pullTxt || translate('pullTxt') }}</view>
-      </view>
-    </view>
-
-    <view class="nut-infinite-container">
-      <slot></slot>
-    </view>
-
-    <view class="nut-infinite-bottom">
-      <template v-if="isInfiniting">
-        <view class="bottom-box">
-          <nut-icon class="bottom-img" v-bind="$attrs" :name="loadIcon"></nut-icon>
-          <view class="bottom-text">{{ loadTxt || translate('loading') }}</view>
-        </view>
-      </template>
-      <template v-else-if="!hasMore">
-        <view class="tips">{{ loadMoreTxt || translate('loadMoreTxt') }}</view>
-      </template>
-    </view>
-  </Nut-Scroll-View>
-</template>
-<script lang="ts">
-import { toRefs, onMounted, reactive, computed, CSSProperties } from 'vue';
-import { createComponent } from '@/packages/utils/create';
-import NutScrollView from '../scrollView/index.taro.vue';
-const { componentName, create, translate } = createComponent('infiniteloading');
-import Icon from '../icon/index.taro.vue';
-import Taro from '@tarojs/taro';
-export default create({
-  props: {
-    hasMore: {
-      type: Boolean,
-      default: true
-    },
-    threshold: {
-      type: Number,
-      default: 200
-    },
-    upperThreshold: {
-      type: Number,
-      default: 40
-    },
-    pullIcon: {
-      type: String,
-      default: 'https://img10.360buyimg.com/imagetools/jfs/t1/169863/6/4565/6306/60125948E7e92774e/40b3a0cf42852bcb.png'
-    },
-    pullTxt: {
-      type: String,
-      default: ''
-    },
-    loadIcon: {
-      type: String,
-      default: 'https://img10.360buyimg.com/imagetools/jfs/t1/169863/6/4565/6306/60125948E7e92774e/40b3a0cf42852bcb.png'
-    },
-    loadTxt: {
-      type: String,
-      default: ''
-    },
-    loadMoreTxt: {
-      type: String,
-      default: ''
-    },
-    useWindow: {
-      type: Boolean,
-      default: true
-    },
-    containerId: {
-      type: String,
-      default: ''
-    },
-    useCapture: {
-      type: Boolean,
-      default: false
-    },
-    isOpenRefresh: {
-      type: Boolean,
-      default: false
-    }
-  },
-  emits: ['scroll-change', 'load-more', 'refresh'],
-  components: {
-    'nut-icon': Icon,
-    NutScrollView
-  },
-  setup(props, { emit, slots }) {
-    const state = reactive({
-      scrollHeight: 0,
-      scrollTop: 0,
-      isInfiniting: false,
-      direction: 'down',
-      isTouching: false,
-      refreshMaxH: 0,
-      y: 0,
-      x: 0,
-      distance: 0
-    });
-
-    const classes = computed(() => {
-      const prefixCls = componentName;
-      return {
-        [prefixCls]: true
-      };
-    });
-
-    const getStyle = computed(() => {
-      const style: CSSProperties = {};
-      return {
-        height: state.distance < 0 ? `0px` : `${state.distance}px`,
-        transition: state.isTouching
-          ? `height 0s cubic-bezier(0.25,0.1,0.25,1)`
-          : `height 0.2s cubic-bezier(0.25,0.1,0.25,1)`
-      };
-    });
-    const getParentElement = (el) => {
-      return Taro.createSelectorQuery().select(!!props.containerId ? `#${props.containerId} #${el}` : `#${el}`);
-    };
-    /** 获取需要滚动的距离 */
-    const getScrollHeight = () => {
-      const parentElement = getParentElement('scroller');
-
-      parentElement
-        .boundingClientRect((rect) => {
-          state.scrollHeight = rect.height;
-        })
-        .exec();
-    };
-
-    /** 滚动到底部 */
-    const lower = () => {
-      if (state.direction == 'up' || !props.hasMore || state.isInfiniting) {
-        return false;
-      } else {
-        state.isInfiniting = true;
-        emit('load-more', infiniteDone);
-      }
-    };
-
-    const scroll = (e) => {
-      // 滚动方向
-      if (e.detail.scrollTop <= 0) {
-        // 滚动到最顶部
-        e.detail.scrollTop = 0;
-      } else if (e.detail.scrollTop >= state.scrollHeight) {
-        // 滚动到最底部
-        e.detail.scrollTop = state.scrollHeight;
-      }
-      if (e.detail.scrollTop > state.scrollTop || e.detail.scrollTop >= state.scrollHeight) {
-        state.direction = 'down';
-      } else {
-        state.direction = 'up';
-      }
-      state.scrollTop = e.detail.scrollTop;
-
-      emit('scroll-change', e.detail.scrollTop);
-    };
-
-    const infiniteDone = () => {
-      state.isInfiniting = false;
-    };
-
-    const touchStart = (event: TouchEvent) => {
-      if (state.scrollTop == 0 && !state.isTouching && props.isOpenRefresh) {
-        state.y = event.touches[0].pageY;
-        state.isTouching = true;
-      }
-    };
-
-    const touchMove = (event: TouchEvent) => {
-      state.distance = event.touches[0].pageY - state.y;
-
-      if (state.distance > 0 && state.isTouching) {
-        event.preventDefault();
-        if (state.distance >= state.refreshMaxH) state.distance = state.refreshMaxH;
-      } else {
-        state.distance = 0;
-        state.isTouching = false;
-      }
-    };
-
-    const touchEnd = () => {
-      if (state.distance < state.refreshMaxH) {
-        state.distance = 0;
-      } else {
-        emit('refresh', refreshDone);
-      }
-    };
-
-    const refreshDone = () => {
-      state.distance = 0;
-      state.isTouching = false;
-    };
-
-    onMounted(() => {
-      state.refreshMaxH = props.upperThreshold;
-      setTimeout(() => {
-        getScrollHeight();
-      }, 200);
-    });
-
-    return {
-      classes,
-      ...toRefs(state),
-      lower,
-      scroll,
-      touchStart,
-      touchMove,
-      touchEnd,
-      getStyle,
-      translate
-    };
-  }
-});
-</script>

+ 18 - 42
src/packages/__VUE/infiniteloading/index.vue

@@ -14,35 +14,27 @@
     <view class="nut-infinite-bottom">
       <template v-if="isInfiniting">
         <view class="bottom-box">
-          <template v-if="!slots.loading">
+          <slot name="loading">
             <nut-icon class="bottom-img" v-bind="$attrs" :name="loadIcon"></nut-icon>
             <view class="bottom-text">{{ loadTxt || translate('loading') }}</view>
-          </template>
-          <slot name="loading" v-else></slot>
+          </slot>
         </view>
       </template>
       <template v-else-if="!hasMore">
-        <view class="tips" v-if="!slots.finished">{{ loadMoreTxt || translate('loadMoreTxt') }}</view>
-        <slot name="finished" v-else></slot>
+        <slot name="finished">
+          <view class="tips">{{ loadMoreTxt || translate('loadMoreTxt') }}</view>
+        </slot>
       </template>
     </view>
   </view>
 </template>
 <script lang="ts">
-import {
-  toRefs,
-  onMounted,
-  onUnmounted,
-  reactive,
-  computed,
-  CSSProperties,
-  onActivated,
-  onDeactivated,
-  ref
-} from 'vue';
+import { toRefs, onMounted, onUnmounted, reactive, computed, onActivated, onDeactivated, ref } from 'vue';
 import { createComponent } from '@/packages/utils/create';
 const { componentName, create, translate } = createComponent('infiniteloading');
 import { useTouch } from '@/packages/utils/useTouch';
+import requestAniFrame from '@/packages/utils/raf';
+import { getScrollTopRoot } from '@/packages/utils/util';
 
 export default create({
   props: {
@@ -116,31 +108,12 @@ export default create({
     });
 
     const getStyle = computed(() => {
-      const style: CSSProperties = {};
       return {
         height: state.distance < 0 ? `0px` : `${state.distance}px`,
-        transition: state.isTouching
-          ? `height 0s cubic-bezier(0.25,0.1,0.25,1)`
-          : `height 0.2s cubic-bezier(0.25,0.1,0.25,1)`
+        transitionDuration: state.isTouching ? 0 : `0.2s`
       };
     });
 
-    const requestAniFrame = () => {
-      return (
-        window.requestAnimationFrame ||
-        window.webkitRequestAnimationFrame ||
-        function (callback) {
-          window.setTimeout(callback, 1000 / 60);
-        }
-      );
-    };
-
-    const getWindowScrollTop = () => {
-      return window.pageYOffset !== undefined
-        ? window.pageYOffset
-        : (document.documentElement || document.body.parentNode || document.body).scrollTop;
-    };
-
     const calculateTopPosition = (el: HTMLElement): number => {
       return !el ? 0 : el.offsetTop + calculateTopPosition(el.offsetParent as HTMLElement);
     };
@@ -149,8 +122,9 @@ export default create({
       let offsetDistance = 0;
       let resScrollTop = 0;
       let direction = 'down';
-      const windowScrollTop = getWindowScrollTop();
+
       if (props.useWindow) {
+        const windowScrollTop = getScrollTopRoot();
         if (state.scroller) {
           offsetDistance =
             calculateTopPosition(state.scroller) + state.scroller.offsetHeight - windowScrollTop - window.innerHeight;
@@ -181,7 +155,7 @@ export default create({
     };
 
     const handleScroll = () => {
-      requestAniFrame()(() => {
+      requestAniFrame(() => {
         if (!isScrollAtBottom() || !props.hasMore || state.isInfiniting) {
           return false;
         } else {
@@ -245,17 +219,19 @@ export default create({
       return !!props.containerId ? document.querySelector(`#${props.containerId}`) : el && el.parentNode;
     };
 
+    const removeScrollListener = () => {
+      state.scrollEl.removeEventListener('scroll', handleScroll, props.useCapture);
+    };
+
     onMounted(() => {
       const parentElement = getParentElement(state.scroller as HTMLElement) as Node & ParentNode;
       state.scrollEl = props.useWindow ? window : parentElement;
 
       scrollListener();
-
-      console.log(slots);
     });
 
     onUnmounted(() => {
-      state.scrollEl.removeEventListener('scroll', handleScroll, props.useCapture);
+      removeScrollListener();
     });
 
     const isKeepAlive = ref(false);
@@ -269,7 +245,7 @@ export default create({
 
     onDeactivated(() => {
       isKeepAlive.value = true;
-      state.scrollEl.removeEventListener('scroll', handleScroll, props.useCapture);
+      removeScrollListener();
     });
 
     return {

+ 4 - 0
src/packages/utils/util.ts

@@ -140,3 +140,7 @@ export const padZero = (num: number | string, length = 2): string => {
 };
 
 export const clamp = (num: number, min: number, max: number): number => Math.min(Math.max(num, min), max);
+
+export const getScrollTopRoot = (): number => {
+  return window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
+};

+ 0 - 1
src/sites/mobile-taro/vue/src/app.config.ts

@@ -58,7 +58,6 @@ const subPackages = [
       'pages/backtop/index',
       'pages/drag/index',
       'pages/dialog/index',
-      'pages/infiniteloading/index',
       'pages/notify/index',
       'pages/switch/index',
       'pages/toast/index'