基于Vue2实现的上拉加载之移动端

上拉加载需求相信很多做移动端的同学基本都有遇到,当然PC端也是家常便饭。目前项目基本接近尾声,前后端联调、真机测试都ok,话说项目需求文档其实并没有说要实现上拉加载功能,但是我们领导说这个可以有,可以成为一个小亮点。然后就这么愉快的决定了(冷冷的冰雨在我脸上胡乱的拍 233333333333.。。。)好了,废话不多扯,奔入今天的主题吧!

接下来就是一坨坨的代码了。。。

  1 <template>
  2   <div class="scroll-loadmore"
  3        @touchstart="touchStart($event)"
  4        @touchmove="touchMove($event)"
  5        @scroll="(onInfinite || infiniteLoading) ? onScroll($event) : undefined">
  6     <section class="inner">
  7       <slot></slot>
  8       <footer class="load-more">
  9         <slot name="load-more">
 10           <vue-loading v-if="loading" type="spin" color="rgba(0,0,0,0.4)" :size="{ width: '30px', height: '30px' }"></vue-loading>
 11           <span v-else>{{loadingText}}</span>
 12         </slot>
 13       </footer>
 14     </section>
 15   </div>
 16 </template>
 17 
 18 <script type="text/ecmascript-6">
 19   import vueLoading from 'vue-loading-template';
 20   export default {
 21     props: {
 22       offset: {
 23         type: Number,
 24         default: 30
 25       },
 26       onInfinite: {
 27         type: Function,
 28         default: undefined,
 29         require: false
 30       },
 31       loadingText: {
 32         type: String
 33       },
 34       loading: {
 35         type: Boolean,
 36         default: true
 37       }
 38     },
 39     data () {
 40       return {
 41         startY: 0,
 42         startScroll: 0,
 43         infiniteLoading: false
 44       };
 45     },
 46     methods: {
 47       touchStart (e) {
 48         this.startY = e.targetTouches[0].pageY;
 49         this.startScroll = this.$el.scrollTop || 0;
 50       },
 51       touchMove (e) {
 52         if (this.$el.scrollTop > 0) {
 53           return;
 54         }
 55         let diff = e.targetTouches[0].pageY - this.startY - this.startScroll;
 56         if (diff > 0) e.preventDefault();
 57       },
 58       infinite () {
 59         this.infiniteLoading = true;
 60         this.onInfinite(this.infiniteDone);
 61       },
 62 
 63       infiniteDone () {
 64         this.infiniteLoading = false;
 65       },
 66 
 67       onScroll () {
 68         if (this.infiniteLoading) {
 69           return;
 70         }
 71         let outerHeight = this.$el.clientHeight;
 72         let innerHeight = this.$el.querySelector('.inner').clientHeight;
 73         let scrollTop = this.$el.scrollTop;
 74         let infiniteHeight = this.$el.querySelector('.load-more').clientHeight;
 75         let bottom = innerHeight - outerHeight - scrollTop;
 76         if (bottom < infiniteHeight) this.infinite();
 77       }
 78     },
 79     components: {
 80       vueLoading
 81     }
 82   };
 83 </script>
 84 
 85 <style>
 86   .scroll-loadmore {
 87     position: absolute;
 88     top: 0;
 89     right: 0;
 90     bottom: 0;
 91     left: 0;
 92     overflow: auto;
 93     -webkit-overflow-scrolling: touch;
 94     background-color: #f4f4f4;
 95   }
 96 
 97   .scroll-loadmore .inner {
 98     position: absolute;
 99     top: 0;
100     width: 100%;
101     transition-duration: 300ms;
102   }
103 
104   .scroll-loadmore .load-more {
105     height: 1rem;
106     font-size: 0.4rem;
107     display: flex;
108     align-items: center;
109     justify-content: center;
110   }
111 </style>

把上面的代码直接保存到一个load-more组件里面。当然组件名字随便命名。接下来就是在你需要实现上拉加载的组件里引用它。代码如下↓

  1 <template>
  2   <div>
  3     <load-more :on-infinite="onInfinite"
  4                :loading-text="loadingText"
  5                :loading="loading"
  6                v-if="returnCode === '0000'">
  7       <div>
  8         <history-detail-list :message="item" v-for="item in downdata"></history-detail-list>
  9       </div>
 10     </load-more>
 11     <load-more class="appointmentListEmpty" :loading="loading" v-else>
 12       <div class="listnull"></div>
 13       <div class="marginTop10 color909090">
 14         {{desc}}
 15       </div>
 16     </load-more>
 17     <err-msg v-if="modal"></err-msg>
 18   </div>
 19 </template>
 20 
 21 <script type="text/ecmascript-6">
 22   import loadMore from 'common/loadmore/loadmore';
 23   import errMsg from 'common/err_msg/err_msg';
 24   import historyDetailList from 'components/history_detail_list/history_detail_list';
 25   import { mapGetters } from 'vuex';
 26   const ERR_OK = 200;
 27   export default {
 28     data () {
 29       return {
 30         num: '5',  // 一次显示多少条
 31         pageNo: 1, // 开始页数
 32         loadingText: '',
 33         loading: false,
 34         downdata: [], // 上拉更多的数据存放数组
 35         returnCode: '',
 36         desc: '',
 37         modal: false
 38       };
 39     },
 40     methods: {
 41       onInfinite (done) {
 42         this.loading = true;
 43         var formdata = {
 44           'UserID': this.clientInfomation.user_id,
 45           'PageNo': this.pageNo,
 46           'Num': this.num
 47         };
 48         this.$axios({
 49           method: 'post',
 50           url: '请求的后端接口地址',
 51           timeout: 超时时间,
 52           data: formdata
 53         }).then(response => {
 54           if (response.status === ERR_OK) {
 55             if (response.data.Head.ReturnCode === '0000') {
 56               this.returnCode = response.data.Head.ReturnCode;
 57               let arr = response.data.Body.RsList;
 58               this.downdata = this.downdata.concat(arr);
 59               this.pageNo += 1;
 60               if (this.num >= arr.length) {
 61                 this.loading = false;
 62                 this.loadingText = '没有更多了';
 66                 return;
 67               }
 68             } else if (response.data.Head.ReturnCode !== '2001' && response.data.Head.ReturnCode !== '0000') {
 69               this.desc = response.data.Head.Desc;
 70               this.loading = false;
 71             } else {
 72               this.modal = true;
 73             }
 74           }
 75           done();
 76         }).catch(() => {
 77           if (done) {
 78             this.$Message.config({
 79               top: 50,
 80               duration: 2
 81             });
 82             this.$Message.error('请求超时,请重试');
 83             this.$router.push({path: '/myAppointment'});
 84           }
 85         });
 86       }
 87     },
 88     components: {
 89       loadMore,
 90       errMsg,
 91       'history-detail-list': historyDetailList
 92     },
 93     computed: {
 94       ...mapGetters(['clientInfomation'])
 95     },
 96     created () {
 97       this.onInfinite(); 99     }
100   };
101 </script>
102 
103 <style rel="stylesheet/less" lang="less" scoped>
104   @import '../../common/less/reset.less';
105 
106   .appointmentListEmpty {
107     text-align: center;
108     vertical-align: middle;
109     .fs(32);
110     margin-top: 50%;
111     .line-height(50);
112     .listnull {
113       .w(267);
114       .h(283);
115       background: url('../../common/img/listnull.png') no-repeat center center;
116       .background-size(267, 283);
117       margin: 0 auto;
118       .mt(100);
119     }
120   }
121 </style>

赶快把代码复制到你的项目下跑起来吧,时间充裕可以看看抽离出来的load-more组件代码,欢迎一起交流学习,有问题和Bug欢迎留言提issure。最后顺便说一句,下拉刷新本项目没有开发,其实这个都是一套的,有时间再完善咯!

posted @ 2017-08-28 10:13  Erwinyong  阅读(11000)  评论(6编辑  收藏  举报