Browse Source

feat: 优化下拉刷新方式&&添加Demo及文档

luobinbin 5 years ago
parent
commit
ceb81629ee

+ 2 - 2
src/config.json

@@ -421,8 +421,8 @@
         },
         {
             "version": "1.0.0",
-            "name": "Pullrefreshloadmore",
-            "sort": "3",
+            "name": "Scroll",
+            "sort": "0",
             "chnName": "下拉刷新&&无限加载",
             "desc": "下拉刷新&&无限加载",
             "type": "component",

+ 3 - 3
src/nutui.js

@@ -85,8 +85,8 @@ import Card from './packages/card/index.js';
 import './packages/card/card.scss';
 import Infiniteloading from './packages/infiniteloading/index.js';
 import './packages/infiniteloading/infiniteloading.scss';
-import Pullrefreshloadmore from './packages/pullrefreshloadmore/index.js';
-import './packages/pullrefreshloadmore/pullrefreshloadmore.scss';
+import Scroll from './packages/scroll/index.js';
+import './packages/scroll/scroll.scss';
 
 const packages = {
   Cell,
@@ -132,7 +132,7 @@ const packages = {
   Field: Field,
   Card,
   Infiniteloading,
-  Pullrefreshloadmore,
+  Scroll,
 };
 
 const components = {};

+ 0 - 5
src/packages/pullrefreshloadmore/__test__/pullrefreshloadmore.spec.js

@@ -1,5 +0,0 @@
-import { shallowMount, mount } from '@vue/test-utils';
-import Pullrefreshloadmore from '../pullrefreshloadmore.vue';
-import Vue from 'vue';
-
-describe('Pullrefreshloadmore.vue', () => {});

+ 0 - 77
src/packages/pullrefreshloadmore/demo.vue

@@ -1,77 +0,0 @@
-<template>
-  <div class="page has-navbar">
-    <nut-pullrefresh-loadmore class="page-content" :on-refresh="onRefresh" :on-infinite="onInfinite" ref="scroller">
-      <div
-        v-for="(item, index) in items"
-        :key="index"
-        @click="onItemClick(index)"
-        class="item item-borderless"
-        :class="{ 'item-stable': index % 2 == 0 }"
-      >
-        {{ item }}
-      </div>
-    </nut-pullrefresh-loadmore>
-  </div>
-</template>
-
-<script>
-export default {
-  data() {
-    return {
-      items: [],
-      menuButtonText: '<span class="assertive">更多</span>',
-    };
-  },
-
-  mounted() {
-    for (let i = 1; i <= 20; i++) {
-      this.items.push(i + ' - 塑像本来就在石头里,我只是把不要的部分去掉');
-    }
-    this.top = 1;
-    this.bottom = 20;
-    setTimeout(() => {
-      if (this.$refs.scroller) this.$refs.scroller.resize();
-    });
-  },
-
-  methods: {
-    onRefresh() {
-      setTimeout(() => {
-        let start = this.top - 1;
-        for (let i = start; i > start - 10; i--) {
-          this.items.splice(0, 0, i + ' - 塑像本来就在石头里,我只是把不要的部分去掉');
-        }
-        this.top = this.top - 10;
-
-        setTimeout(() => {
-          if (this.$refs.scroller) this.$refs.scroller.finishPullToRefresh();
-        });
-      }, 1500);
-    },
-
-    onInfinite() {
-      setTimeout(() => {
-        let start = this.bottom + 1;
-        for (let i = start; i < start + 10; i++) {
-          this.items.push(i + ' - 塑像本来就在石头里,我只是把不要的部分去掉');
-        }
-        this.bottom = this.bottom + 10;
-
-        setTimeout(() => {
-          if (this.$refs.scroller) this.$refs.scroller.finishInfinite();
-        });
-      }, 1500);
-    },
-
-    onItemClick(index) {
-      console.log(index);
-    },
-
-    clickFn() {
-      console.log('do click');
-    },
-  },
-};
-</script>
-
-<style lang="scss"></style>

+ 0 - 66
src/packages/pullrefreshloadmore/doc.md

@@ -1,66 +0,0 @@
-# Icon 图标
-
-## 基本用法
-
-```html
-<nut-icon 
-  type="top"
->
-</nut-icon>
-```
-## 自定义尺寸
-
-支持通过**size**设置图标大小,注意包含单位,如“40px”、“4rem”…
-
-```html
-<nut-icon 
-  type="action" 
-  size="40px"
->
-</nut-icon>
-```
-
-## 自定义颜色
-
-支持通过**color**设置图标颜色,支持十六进制/RGB/RGBA等写法。
-
-```html
-<nut-icon 
-  type="trolley" 
-  color="#f0250f"
->
-</nut-icon>
-```
-## 自定义svg图标
-
-支持通过**url**可以自定义添加额外的图片。
-
-```html
-<nut-icon type="self" :url="require('../../assets/svg/trolley.svg')"></nut-icon>
-```
-## type可选值
-
-nutui 自带图标库提供了下面的这些可选值。
-
-* top
-* down
-* right
-* action
-* more
-* trolley
-* search
-* tick
-* plus
-* minus
-* cross
-* circle-cross
-
-
-## Prop
-
-| 字段 | 说明 | 类型 | 默认值
-|----- | ----- | ----- | ----- 
-| type | 图标,可选值top/action/cross/down/right/more/plus/search/trolley/tick/minus/circle-cross | String | -
-| size | 尺寸,需要带单位 | String | -
-| color | 颜色 | String | -
-| url | 自定义图标路径,必须是svg格式,请用 require 方式引入 | String | - 

+ 0 - 9
src/packages/pullrefreshloadmore/index.js

@@ -1,9 +0,0 @@
-import Pullrefreshloadmore from './pullrefreshloadmore.vue';
-import './pullrefreshloadmore.scss';
-
-Pullrefreshloadmore.install = function (Vue) {
-  console.log('Pullrefreshloadmore.name', Pullrefreshloadmore.name);
-  Vue.component(Pullrefreshloadmore.name, Pullrefreshloadmore);
-};
-
-export default Pullrefreshloadmore;

+ 0 - 112
src/packages/pullrefreshloadmore/pullrefreshloadmore.scss

@@ -1,112 +0,0 @@
-.nut-container {
-  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-
-  width: 100%;
-  height: 100%;
-  position: absolute;
-  top: 0;
-  left: 0;
-  overflow: hidden;
-
-  -webkit-user-select: none;
-  -moz-user-select: none;
-  -ms-user-select: none;
-  -o-user-select: none;
-  user-select: none;
-}
-
-.nut-container > .nut-content {
-  width: 100%;
-  -webkit-transform-origin: left top;
-  -webkit-transform: translateZ(0);
-  -moz-transform-origin: left top;
-  -moz-transform: translateZ(0);
-  -ms-transform-origin: left top;
-  -ms-transform: translateZ(0);
-  -o-transform-origin: left top;
-  -o-transform: translateZ(0);
-  transform-origin: left top;
-  transform: translateZ(0);
-}
-
-.nut-container > .nut-content > .pull-to-refresh-layer {
-  width: 100%;
-  height: 60px;
-  margin-top: -60px;
-  text-align: center;
-  font-size: 16px;
-  color: #aaa;
-}
-
-.nut-container > .nut-content > .loading-layer {
-  width: 100%;
-  height: 60px;
-  text-align: center;
-  font-size: 16px;
-  line-height: 60px;
-  color: #aaa;
-  position: relative;
-}
-
-.nut-container > .nut-content > .loading-layer > .no-data-text {
-  position: absolute;
-  left: 0;
-  top: 0;
-  width: 100%;
-  height: 100%;
-  z-index: 1;
-}
-
-.nut-container > .nut-content > .loading-layer > .spinner-holder,
-.nut-container > .nut-content > .loading-layer > .no-data-text {
-  opacity: 0;
-  transition: opacity 0.15s linear;
-  -webkit-transition: opacity 0.15s linear;
-}
-
-.nut-container > .nut-content > .loading-layer > .spinner-holder.active,
-.nut-container > .nut-content > .loading-layer > .no-data-text.active {
-  opacity: 1;
-}
-
-.nut-container > .nut-content > .pull-to-refresh-layer .spinner-holder,
-.nut-container > .nut-content > .loading-layer .spinner-holder {
-  text-align: center;
-  -webkit-font-smoothing: antialiased;
-}
-
-.nut-container > .nut-content > .pull-to-refresh-layer .spinner-holder .arrow,
-.nut-container > .nut-content > .loading-layer .spinner-holder .arrow {
-  width: 20px;
-  height: 20px;
-  margin: 8px auto 0 auto;
-
-  -webkit-transform: translate3d(0, 0, 0) rotate(0deg);
-  transform: translate3d(0, 0, 0) rotate(0deg);
-
-  -webkit-transition: -webkit-transform 0.2s linear;
-  transition: transform 0.2s linear;
-}
-
-.nut-container > .nut-content > .pull-to-refresh-layer .spinner-holder .text,
-.nut-container > .nut-content > .loading-layer .spinner-holder .text {
-  display: block;
-  margin: 0 auto;
-  font-size: 14px;
-  line-height: 20px;
-  color: #aaa;
-}
-
-.nut-container > .nut-content > .pull-to-refresh-layer .spinner-holder .spinner,
-.nut-container > .nut-content > .loading-layer .spinner-holder .spinner {
-  margin-top: 14px;
-  width: 32px;
-  height: 32px;
-  fill: #444;
-  stroke: #69717d;
-}
-
-.nut-container > .nut-content > .pull-to-refresh-layer.active .spinner-holder .arrow {
-  -webkit-transform: translate3d(0, 0, 0) rotate(180deg);
-  transform: translate3d(0, 0, 0) rotate(180deg);
-}

+ 5 - 0
src/packages/scroll/__test__/scroll.spec.js

@@ -0,0 +1,5 @@
+import { shallowMount, mount } from '@vue/test-utils';
+import Sroll from '../scroll.vue';
+import Vue from 'vue';
+
+describe('Sroll.vue', () => {});

src/packages/pullrefreshloadmore/components/Arrow.vue → src/packages/scroll/components/Arrow.vue


src/packages/pullrefreshloadmore/components/Spinner.vue → src/packages/scroll/components/Spinner.vue


+ 115 - 0
src/packages/scroll/demo.vue

@@ -0,0 +1,115 @@
+<template>
+  <div class="page has-navbar">
+    <div class="demo-item">
+      <h4>上拉刷新&&无限加载</h4>
+      <div class="scroll-box">
+        <nut-pullrefresh-loadmore
+          class="page-content"
+          :on-refresh="onRefresh"
+          :on-infinite="onInfinite"
+          refreshText="下拉释放刷新-加载数据"
+          noDataText="没有数据啦~"
+          ref="scroller"
+        >
+          <div v-for="(item, index) in items" :key="index" @click="onItemClick(index)" class="item">
+            {{ item }}
+          </div>
+        </nut-pullrefresh-loadmore>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      items: [],
+      menuButtonText: '<span class="assertive">更多</span>',
+    };
+  },
+
+  mounted() {
+    for (let i = 1; i <= 20; i++) {
+      this.items.push('塑像本来就在石头里,我只是把不要的部分去掉 ' + (i < 10 ? '0' + i : i));
+    }
+    this.top = 1;
+    this.bottom = 20;
+    setTimeout(() => {
+      if (this.$refs.scroller) this.$refs.scroller.resize();
+    });
+  },
+
+  methods: {
+    onRefresh() {
+      setTimeout(() => {
+        let start = this.top - 1;
+        for (let i = start; i > start - 10; i--) {
+          this.items.splice(0, 0, '塑像本来就在石头里,我只是把不要的部分去掉 ' + (i > -10 ? '0' + -i : -i));
+        }
+        this.top = this.top - 10;
+        this.$refs.scroller && this.$refs.scroller.finishPullToRefresh();
+      }, 1500);
+    },
+
+    onInfinite(cb) {
+      if (this.bottom >= 50) {
+        cb(true);
+        return;
+      }
+      setTimeout(() => {
+        let start = this.bottom + 1;
+        for (let i = start; i < start + 10; i++) {
+          this.items.push('塑像本来就在石头里,我只是把不要的部分去掉 ' + (i < 10 ? '0' + i : i));
+        }
+        this.bottom = this.bottom + 10;
+        this.$refs.scroller && this.$refs.scroller.finishInfinite();
+      }, 1500);
+    },
+
+    onItemClick(index) {
+      this.$toast.text('当前点击项的index - ' + index);
+    },
+  },
+};
+</script>
+
+<style lang="scss">
+html,
+body {
+  overflow: hidden;
+  .has-navbar {
+    position: relative;
+    overflow: hidden;
+    height: calc(100vh - 40px);
+    padding: 0;
+    .demo-item {
+      position: relative;
+      height: 100vh;
+      margin-bottom: 10px;
+      overflow: hidden;
+      flex: 1;
+      display: flex;
+      flex-direction: column;
+      &:last-child {
+        margin-bottom: 0;
+      }
+      h4 {
+        margin: 10px;
+      }
+      .scroll-box {
+        position: relative;
+        flex: 1;
+        text-align: center;
+      }
+      .page-content {
+        background: #fff;
+      }
+      .item {
+        height: 30px;
+        line-height: 30px;
+      }
+    }
+  }
+}
+</style>

+ 75 - 0
src/packages/scroll/doc.md

@@ -0,0 +1,75 @@
+# 下拉刷新&&无限加载
+
+## 基本用法
+
+```html
+<nut-pullrefresh-loadmore 
+  :on-refresh="onRefresh"
+  :on-infinite="onInfinite"
+  <!-- 这里添加你需要的内容 -->
+>
+</nut-pullrefresh-loadmore>
+```
+## 下拉刷新&&无限加载方法使用
+
+支持下拉刷新、无限加载单独使用
+
+### 下拉刷新
+```html
+onRefresh() {
+  // 调用API获取数据 PS:这里通过setTimeout来mock
+  setTimeout(() => {
+    let start = this.top - 1;
+    for (let i = start; i > start - 10; i--) {
+      this.items.splice(0, 0, '塑像本来就在石头里,我只是把不要的部分去掉 ' + (i > -10  ? ('0' + -i) : -i));
+    }
+    this.top = this.top - 10;
+    // 停止下拉动画
+    this.$refs.scroller && this.$refs.scroller.finishPullToRefresh();
+  }, 1500);
+}
+```
+
+### 无限加载
+```html
+onInfinite(cb) {
+  // 通过回调函数cb进行控制是否数据加载
+  if(this.bottom >= 50) {
+    cb(true)
+    return
+  }
+  setTimeout(() => {
+    let start = this.bottom + 1;
+    for (let i = start; i < start + 10; i++) {
+      this.items.push('塑像本来就在石头里,我只是把不要的部分去掉 ' + (i < 10 ? ('0' + i) : i));
+    }
+    this.bottom = this.bottom + 10;
+      this.$refs.scroller && this.$refs.scroller.finishInfinite();
+  }, 1500);
+}
+```
+
+## 自定义文案、样式
+
+支持文案及样式覆写。
+
+```html
+refreshText="下拉释放刷新-加载数据"
+noDataText="没有数据啦~"
+...
+```
+
+## Prop
+
+| 字段 | 说明 | 类型 | 默认值
+|----- | ----- | ----- | ----- 
+| onRefresh | 下拉刷新回调函数 | Function | -
+| onInfinite | 尺寸,需要带单位 | Function | -
+| refreshText | 颜色 | String | 下拉刷新
+| noDataText | 没有数据展示的问题 | String | 没有更多数据 
+| width | 容器宽度,不需要带单位,采用px | Number | 100%
+| height | 容器高度,不需要带单位,采用px | Number | 100%
+| refreshLayerColor | 下拉刷新颜色 | String | #AAAAAA
+| loadingLayerColor | 无限加载颜色 | String | #AAAAAA
+| minContentHeight | 容器最小高度,不需要带单位,采用px | Number | -
+

+ 8 - 0
src/packages/scroll/index.js

@@ -0,0 +1,8 @@
+import Sroll from './scroll.vue';
+import './scroll.scss';
+
+Sroll.install = function (Vue) {
+  Vue.component(Sroll.name, Sroll);
+};
+
+export default Sroll;

src/packages/pullrefreshloadmore/lib/core.js → src/packages/scroll/lib/core.js


src/packages/pullrefreshloadmore/lib/render.js → src/packages/scroll/lib/render.js


+ 104 - 0
src/packages/scroll/scroll.scss

@@ -0,0 +1,104 @@
+.nut-container {
+  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  top: 0;
+  left: 0;
+  overflow: hidden;
+
+  user-select: none;
+  .nut-content {
+    width: 100%;
+    transform-origin: left top;
+    transform: translateZ(0);
+    .pull-to-refresh-layer {
+      width: 100%;
+      height: 60px;
+      margin-top: -60px;
+      text-align: center;
+      font-size: 16px;
+      color: #aaa;
+      .spinner-holder {
+        text-align: center;
+        -webkit-font-smoothing: antialiased;
+        .arrow {
+          width: 20px;
+          height: 20px;
+          margin: 8px auto 0 auto;
+          transform: translate3d(0, 0, 0) rotate(0deg);
+          transition: transform 0.2s linear;
+        }
+        .text {
+          display: block;
+          margin: 0 auto;
+          font-size: 14px;
+          line-height: 20px;
+          color: #aaa;
+        }
+        .spinner {
+          margin-top: 14px;
+          width: 32px;
+          height: 32px;
+          fill: #444;
+          stroke: #69717d;
+        }
+      }
+    }
+    .pull-to-refresh-layer.active .spinner-holder .arrow {
+      transform: translate3d(0, 0, 0) rotate(180deg);
+    }
+    .loading-layer {
+      width: 100%;
+      height: 60px;
+      text-align: center;
+      font-size: 16px;
+      line-height: 60px;
+      color: #aaa;
+      position: relative;
+      .no-data-text {
+        position: absolute;
+        left: 0;
+        top: 0;
+        width: 100%;
+        height: 100%;
+        z-index: 1;
+      }
+      .spinner-holder,
+      .no-data-text {
+        opacity: 0;
+        transition: opacity 0.15s linear;
+      }
+      .spinner-holder.active,
+      .no-data-text.active {
+        opacity: 1;
+      }
+      .spinner-holder {
+        text-align: center;
+        -webkit-font-smoothing: antialiased;
+        .arrow {
+          width: 20px;
+          height: 20px;
+          margin: 8px auto 0 auto;
+          transform: translate3d(0, 0, 0) rotate(0deg);
+          transition: transform 0.2s linear;
+        }
+        .text {
+          display: block;
+          margin: 0 auto;
+          font-size: 14px;
+          line-height: 20px;
+          color: #aaa;
+        }
+        .spinner {
+          margin-top: 14px;
+          width: 32px;
+          height: 32px;
+          fill: #444;
+          stroke: #69717d;
+        }
+      }
+    }
+  }
+}

src/packages/pullrefreshloadmore/pullrefreshloadmore.vue → src/packages/scroll/scroll.vue