今天研究了一下上拉加載數據組件

一直都想研究一下vue組件是如何寫的,有幸今天終於開始了研究,因此今天才寫了這一篇文章出來,咱們先來分析一下整個頁面吧 css

在這裏插入圖片描述
底部(footer.vue)是固定在頂部的,組件源碼以下:

頭部(header)也是固定在頂部的 html

header

咱們在滾動加載時,須要給出提示,加載更多這樣的字樣vue

(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)git

<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)web

<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.scsssegmentfault

$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>
複製代碼

在這裏插入圖片描述
期間遇到一個問題:Ignored attempt to cancel a touchmove event with cancelable=false, for example because scrolling is in progress and cannot be interrupted. 解決方法以下: segmentfault.com/q/101000000… segmentfault.com/a/119000000… forum.ionicframework.com/t/error-ign… 完美:附上個人碼雲地址: 李金文/vue組件 ​ 並且會持續更新學習,本身封裝的組件,簡直就是完美啊
相關文章
相關標籤/搜索