一直都想研究一下vue組件是如何寫的,有幸今天終於開始了研究,因此今天才寫了這一篇文章出來,咱們先來分析一下整個頁面吧 css
頭部(header)也是固定在頂部的 html
咱們在滾動加載時,須要給出提示,加載更多這樣的字樣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;
複製代碼
總體目錄結構以下 數組
<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>
複製代碼