Advertisement

今天研究了一下上拉加载数据组件

阅读量:

一直以来都对Vue组件的编写过程充满兴趣。非常幸运地从今天开始着手这项研究工作,在经过一番深入思考后才有了这篇分享文章的诞生。让我们首先深入探讨整个页面的架构设置情况吧。

在这里插入图片描述

底部(footer.vue)是固定在顶部的,组件源码如下:

footer

头部(header)也是固定在顶部的

我们在滚动加载时,需要给出提示,加载更多这样的字样

复制代码
    (loadmore.vue)
    <template>
    <div class="more" v-show="loadmoreShow">
    	{{text}}		
    </div>	
    </template>
    
    <script>
    // eslint-disable-next-line
    /* eslint-disable */
    export default {
    	name: 'loadmore',
    	props: {
    		text: {
    			type: String,
    			default: '',
    		},
    		loadmoreShow: {
    			type: Boolean,
    			default: false,
    		}
    	}
    }
    </script>
    <style scoped lang="scss">
    @import "@/static/vars.scss";
    .more{
    	color: $loadmorecolor;
    	height: 30px;
    	line-height:30px;
    	font-size: $fontsize;
    	margin-bottom: 50px;
    }	
    </style>

当没有数据加载时,我们要给出提示暂无更多数据(nulldata.vue)

复制代码
    <template>
    <div class="null" v-show="nulld">
    	暂无更多数据		
    </div>	
    </template>
    
    <script>
    // eslint-disable-next-line
    /* eslint-disable */
    export default {
    	name: 'nulldata',
    	props: {
    		nulld: {
    			type: Boolean,
    			default: false
    		}
    
    	}
    }
    </script>
    
    <style scoped lang="scss">
    @import "@/static/vars.scss";
    .null{
    	color: $nulldatacolor;
    	height: 30px;
    	line-height:30px;
    	font-size: $fontsize;
    	margin-bottom: 50px;
    }
    </style>

接下来就来到滚动组件的编写了(scroll.vue)

复制代码
    <template lang="html">
    <div class="scroll" @touchstart=touchStart($event)
    	@touchmove=touchMove($event)
    	@touchend=touchEnd($event)>
    	<section class="inner">
    		<!-- 默认插槽 -->
    		<slot>
    			
    		</slot>
                // 
    		<v-loadmore ref='loadmore' :loadmoreShow="loadmoreShow" :text="text"></v-loadmore>	
    		<v-nulldata :nulld="dataList.nulld"></v-nulldata>
    	</section>
    </div>
    </template>
    
    <script>
    // eslint-disable-next-line
    /* eslint-disable */
    import nulldata from '@/components/nulldata.vue'
    import loadmore from '@/components/loadmore.vue'
    export default {
    	props: {
    		bottom: {
    			type: Number,
    			default: 50
    		},
    		enbaleLoadMore: {
    			type: Boolean,
    			default: true,
    		},
    		dataList: {
    			default: false,
                        required: false
    		},
    		onLoadMore: {
    			type: Function,
    			default: undefined,
    		}
    	},
    	components: {
    		"v-nulldata": nulldata,
    		"v-loadmore": loadmore
    	},
    	data() {
    		return {
    			text: '',
    			isLoading: false,
    			loadmoreEl:null,
    			loadmoreShow: false,
    			touches: {
    				startX: 0,
    				startY: 0,
    				scrollTop: 0,
    				touching: false,
    			}
    		}
    	},
    	mounted() {
    		this.loadmoreEl = this.$refs.loadmore.$el;
    	},
    	methods: {
    		touchStart(e){
    			// console.log('touchStart',e)
    			var touch = e.targetTouches[0];
    			this.touches.startX = touch.pageX
    			this.touches.startY = touch.pageY
    			this.touches.scrollTop = this.$el.scrollTop || this.touches.scrollTop
    			this.touches.touching = true
    			// this.dataList.nulld = false
    			this.enableLoadMore = true;
    		},
    		touchMove(e){
    			if(!this.enableLoadMore || !this.touches.touching || this.dataList.nulld){
    				// 如果没启动上拉加载更多,好、或者没有滑动,或者数据为空时
    				return
    			}
    			let diff = e.targetTouches[0].pageY - this.touches.startY - this.touches.scrollTop
            if(diff > 0) {
                e.preventDefault()
            }
            this.text = '上拉加载更多'
            this.loadmoreShow = true;
    		},
    		touchEnd(e) {
    
              if (this.isLoading) {
                    return;
                }
                console.log("滑动距离太短")
                this.touches.touching = false
    
                //用于判断滑动是否在原地 ----begin
                let endX = e.changedTouches[0].pageX,
                    endY = e.changedTouches[0].pageY,
                    dy = this.touches.startY - endY,
                    dx = endX - this.touches.startX;
    
                //如果滑动距离太短
                if(Math.abs(dx) < 2 && Math.abs(dy) < 2) {
                    // console.log("滑动距离太短")
                    this.loadmoreShow = false; //隐藏加载条
                    return;
                }
    
                if(!this.enableLoadMore || this.isLoading) {
                    this.loadmoreEl.style.display = 'none'; //隐藏加载条
                    return
                }
                console.log(1)
                let outerHeight = this.$el.clientHeight,
                    innerHeight = this.$el.querySelector('.inner').clientHeight,
                    scrollTop = this.$el.scrollTop,
                    bottom = innerHeight - outerHeight - scrollTop;
                // console.log("outerHeight",outerHeight)
                // console.log("innerHeight",innerHeight)
                // console.log("scrollTop",scrollTop)
                // console.log("bottom",bottom)
                // console.log('this.$el',this.$el)
                // console.log("this.bottom",this.bottom)
                if(bottom <= this.bottom) {
                    //内容太少
                    this.doLoadMore();
                } else {
                    this.loadmoreShow = false; //隐藏加载条
                }
            },
    
            doLoadMore() {
                this.isLoading = true
                this.text = '正在加载'
                this.onLoadMore(this.loadDone);
            },
    
            loadDone() {
                this.isLoading = false
                this.loadmoreShow = false; //隐藏加载条
    
            }
    	}
    }
    </script>
    
    <style scoped lang="scss">
    .scroll{
    	position: relative;
    	z-index: 100;
    	top: 34px;
    	overflow: auto;
    	-webkit-overflow-scrolling: touch;
    	.inner{
    		transition-duration: 300ms;
    	}
    }	
    </style>

基础scss样式如下:vars.scss

复制代码
    $backgroundcolor: rgb(0, 150, 136);
    $fontsize: 24px;
    $color: #fff;
    $nulldatacolor: #999999;
    $loadmorecolor: #666;

整体目录结构如下

在这里插入图片描述

好,接下来我们就来应用他(Index.vue)

复制代码
    <template>
    <div class="index">
    	<v-header></v-header>
    	<div class="box">
    		<v-scroll :onLoadMore="onLoadMore" :dataList="dataList">
    			<ul>
    				<li v-for="(item) in listdata" :key="item.name">{{item.name}}</li>
    				<li v-for="(item) in downdata" :key="item.name">{{item.name}}</li>
    			</ul>
    		</v-scroll>
    	</div>
    	<v-footer></v-footer>
    </div>
    </template>
    
    <script>
    // eslint-disable-next-line
    /* eslint-disable */
    import scroll from "@/components/scroll.vue"
    import vheader from '@/components/vheader.vue'
    import vfooter from '@/components/vfooter.vue'
    
    export default {
    	name: 'index',
    	components: {
    		"v-scroll": scroll,
    		'v-header': vheader,
    		'v-footer': vfooter,
    		
    	},
    	data() {
    		return {
    			counter: 1, //当前页
            num: 15, // 一页显示多少条
            pageStart: 0, // 开始页数
            pageEnd: 0, // 结束页数
            listdata: [], // 下拉更新数据存放数组
            downdata: [], // 上拉更多的数据存放数组
    			dataList: {
    				nulld: false,//暂无更多数据
    			}
    		}
    	},
    	mounted: function() {
        this.getList();
    },
    methods: {
        getList() {
            var response = []
            for(let i = 0; i < 100; i++) {
                response.push({
                    name: i
                })
            }
            this.listdata = response.slice(0, this.num);
        },
    
        onLoadMore(done) {
            this.counter++;
            let end = this.pageEnd = this.num * this.counter;
            let i = this.pageStart = this.pageEnd - this.num;
    
            setTimeout(() => {
                for(i; i < end; i++) {
                    if(i >= 50) {
    
                        //走完数据调用方法
                        this.dataList.nulld = true;
    
                        break;
                    } else {
                        this.downdata.push({
                            name: i + "==="
                        })
                        // more.style.display = 'none'; //隐藏加载条
                    }
                }
                done();
            }, 2000);
        }
    }
    }
    </script>
    
    <style scoped lang="scss">
    @import "@/static/vars.scss";
    .index{
    	.box{
    		ul li{
    			height: 40px;
    			line-height:40px;
    			border: 1px solid red;
    		}
    	}
    }	
    </style>
在这里插入图片描述

此外, 我会持续关注并学习相关的最佳实践, 以进一步提升项目的质量和稳定性

个人体验非常满意

全部评论 (0)

还没有任何评论哟~