Loadmore使用的時候分為下拉刷新和底部加載兩種方式。
下拉刷新的時候這樣調用:
<template>
<div class="page-loadmore">
<h1 class="page-title">Pull down</h1>
<p class="page-loadmore-desc">在列表頂端, 按住 - 下拉 - 釋放可以獲取更多數據</p>
<p class="page-loadmore-desc">此例請使用手機查看</p>
<p class="page-loadmore-desc">translate : {{ translate }}</p>
<div class="loading-background" :style="{ transform: 'scale3d(' + moveTranslate + ',' + moveTranslate + ',1)' }">
translateScale : {{ moveTranslate }}
</div>
<div class="page-loadmore-wrapper" ref="wrapper" :style="{ height: wrapperHeight + 'px' }">
<!-- page-loadmore-wrapper元素是loadmore模塊的父級盒子,它的高度是綁定了一個響應式的值wrapperHeight -->
<!-- 在生命周期mounted的時候為page-loadmore-wrapper計算高度 -->
<!-- page-loadmore-wrapper有一個ref屬性,這就是給這個DOM元素添加了一個引用,在當前組件里可以用this.$refs的形式來調用這個DOM元素 -->
<loadmore :top-method="loadTop" @translate-change="translateChange" @top-status-change="handleTopChange" ref="loadmore">
<!-- loadmore組件,傳進去了一個屬性,loadTop會從props接收到 -->
<!-- loadTop方法用於給列表添加數據項 -->
<!-- 還給loadmore組件綁定了自定義事件top-status-change,用於更改topStatus這個屬性值 -->
<!-- top-status-change的觸發是在loadmore組件內部判斷觸發的,子組件$emit觸發 -->
<ul class="page-loadmore-list">
<li v-for="(item, key, index) in list" :key="index" class="page-loadmore-listitem">{{ item }}</li>
</ul>
<!-- page-loadmore-list是數據列表 -->
<div slot="top" class="mint-loadmore-top">
<span v-show="topStatus !== 'loading'" :class="{ 'is-rotate': topStatus === 'drop' }">↓</span>
<span v-show="topStatus === 'loading'">
<a>加載中...</a>
</span>
</div>
<!-- top插槽插入的內容是下拉的時候,數據列表下移后上面出現的箭頭和loading文字或者動畫 -->
<!-- 箭頭和文字都隨着topStatus值來改變顯示狀態和樣式 -->
<!-- topStatus有三種狀態:pull,drop,loading -->
<!-- loading的時候顯示文字或者動畫,其它時候顯示箭頭 -->
</loadmore>
</div>
</div>
</template>
<style lang="scss" scoped>
.page-loadmore {
width: 100%;
overflow-x: hidden;
.page-loadmore-wrapper {
margin-top: -1px;
overflow: scroll;
.page-loadmore-listitem {
height: 50px;
line-height: 50px;
border-bottom: solid 1px #eee;
text-align: center;
&:first-child {
border-top: solid 1px #eee;
}
}
}
.loading-background {
width: 100%;
height: 50px;
line-height: 50px;
text-align: center;
transition: .2s linear;
}
.mint-loadmore-top {
span {
display: inline-block;
transition: .2s linear;
vertical-align: middle;
}
.is-rotate {
transform: rotate(180deg);
}
}
}
</style>
<script type="text/babel">
import loadmore from '@/components/loadmore'
export default {
data() {
return {
list: [],//數據列表
topStatus: '',//上方loading層狀態
wrapperHeight: 0,//包裹盒子高度
translate: 0,
moveTranslate: 0
};
},
methods: {
handleTopChange(status) {//改變topStatus狀態,下方的箭頭和加載文字會隨着topStatus改變樣式或者內容
this.moveTranslate = 1;
this.topStatus = status;
},
translateChange(translate) {//loadmore組件在滑動時會觸發此事件運行此方法
const translateNum = +translate;
this.translate = translateNum.toFixed(2);
this.moveTranslate = (1 + translateNum / 70).toFixed(2);
},
loadTop() {//加載更多數據列表
setTimeout(() => {
let firstValue = this.list[0];
for (let i = 1; i <= 10; i++) {
this.list.unshift(firstValue - i);
}
this.$refs.loadmore.onTopLoaded();//加載完數據之后調用loadmore組件的onTopLoaded方法
}, 1500);
}
},
components: {
loadmore
},
created() {//created的時候先給數據列表里填入20條數據
for (let i = 1; i <= 20; i++) {
this.list.push(i);
}
},
mounted() {
this.wrapperHeight = document.documentElement.clientHeight - this.$refs.wrapper.getBoundingClientRect().top;
//計算page-loadmore-wrapper的高度
//html元素的clientHeight - page-loadmore-wrapper盒子距離頁面頂部的高度
//Element.getBoundingClientRect()方法返回元素的大小及其相對於視口的位置
//也就是除了頁面上面的內容之外,下面整個就是page-loadmore-wrapper盒子,wrapper盒子給一個死高度之后,多給一個overflow:scroll;的樣式,這樣內容就可以通過滑動看到了
}
};
</script>
底部加載的時候這樣調用:
<template>
<div class="page-loadmore">
<h1 class="page-title">Pull up</h1>
<p class="page-loadmore-desc">在列表底部, 按住 - 上拉 - 釋放可以獲取更多數據</p>
<p class="page-loadmore-desc">此例請使用手機查看</p>
<div class="page-loadmore-wrapper" ref="wrapper" :style="{ height: wrapperHeight + 'px' }">
<!-- page-loadmore-wrapper元素是loadmore模塊的父級盒子,它的高度是綁定了一個響應式的值wrapperHeight -->
<!-- 在生命周期mounted的時候為page-loadmore-wrapper計算高度 -->
<!-- page-loadmore-wrapper有一個ref屬性,這就是給這個DOM元素添加了一個引用,在當前組件里可以用this.$refs的形式來調用這個DOM元素 -->
<loadmore :bottom-method="loadBottom" @bottom-status-change="handleBottomChange" :bottom-all-loaded="allLoaded" ref="loadmore">
<!-- loadmore組件,傳進去了兩個屬性,loadmore會從props接收到,loadBottom方法和allLoaded屬性 -->
<!-- loadBottom方法用於給列表添加數據項,allLoaded是個布爾值,判斷是否數據已經全部加載完了 -->
<!-- 還給loadmore組件綁定了一個自定義事件bottom-status-change,用於更改bottomStatus這個屬性值 -->
<!-- bottom-status-change的觸發是在loadmore組件內部判斷觸發的,子組件$emit觸發 -->
<ul class="page-loadmore-list">
<li v-for="(item, key, index) in list" :key="index" class="page-loadmore-listitem">{{ item }}</li>
</ul>
<!-- page-loadmore-list是數據列表 -->
<div slot="bottom" class="mint-loadmore-bottom">
<span v-show="bottomStatus !== 'loading'" :class="{ 'is-rotate': bottomStatus === 'drop' }">↑</span>
<span v-show="bottomStatus === 'loading'">
<a>加載中...</a>
</span>
</div>
<!-- bottom插槽插入的內容是上拉的時候,數據列表上移后下面出現的箭頭和loading文字或者動畫 -->
<!-- 箭頭和文字都隨着bottomStatus值來改變顯示狀態和樣式 -->
<!-- bottomStatus有三種狀態:pull,drop,loading -->
<!-- loading的時候顯示文字或者動畫,其它時候顯示箭頭 -->
</loadmore>
<!-- loadmore組件有三個插槽,top,bottom和默認插槽 -->
<!-- top是列表下移后上方出現的箭頭和loading文字,bottom是上移后下方出現的箭頭和文字,默認插槽就是數據列表 -->
</div>
</div>
</template>
<style lang="scss" scoped>
.page-loadmore-listitem {
height: 50px;
line-height: 50px;
border-bottom: solid 1px #eee;
text-align: center;
}
.page-loadmore-wrapper {
overflow: scroll;
}
.mint-loadmore-bottom {
span {
display: inline-block;
transition: .2s linear;
}
.is-rotate {
transform: rotate(180deg);
}
}
</style>
<script>
import loadmore from '@/components/loadmore'
export default {
data () {
return {
list: [],//數據列表
allLoaded: false,//是否全部加載
bottomStatus: '',//下方loading層狀態
wrapperHeight: 0//包裹盒子高度
}
},
methods: {
handleBottomChange(status) {//改變bottomStatus狀態,下方的箭頭和加載文字會隨着bottomStatus改變樣式或者內容
this.bottomStatus = status;
},
loadBottom() {//加載更多數據列表
setTimeout(() => {
let lastValue = this.list[this.list.length - 1];
if (lastValue < 40) {
for (let i = 1; i <= 10; i++) {
this.list.push(lastValue + i);
}
} else {
this.allLoaded = true;//數據全部加載完了,就改變allLoaded
}
this.$refs.loadmore.onBottomLoaded();//加載完數據之后調用loadmore組件的onBottomLoaded方法
}, 1500);
}
},
components: {
loadmore
},
created () {//created的時候先給數據列表里填入20條數據
for (let i = 0; i <= 20; i++) {
this.list.push(i)
}
},
mounted () {
this.wrapperHeight = document.documentElement.clientHeight - this.$refs.wrapper.getBoundingClientRect().top
//計算page-loadmore-wrapper的高度
//html元素的clientHeight - page-loadmore-wrapper盒子距離頁面頂部的高度
//Element.getBoundingClientRect()方法返回元素的大小及其相對於視口的位置
//也就是除了頁面上面的內容之外,下面整個就是page-loadmore-wrapper盒子,wrapper盒子給一個死高度之后,多給一個overflow:scroll;的樣式,這樣內容就可以通過滑動看到了
}
}
</script>
loadmore組件:
<template>
<div class="mint-loadmore">
<!-- mint-loadmore最外層盒子,有overflow:hidden;的樣式,這樣下方的箭頭文字動畫或者上方的就會隱藏看不到 -->
<div class="mint-loadmore-content" :class="{ 'is-dropped': topDropped || bottomDropped}" :style="{ 'transform': transform }">
<!-- content盒子擁有兩個響應式屬性,一個在drop的時候添加is-dropped類名,讓transform變化更流暢,一個是transform樣式,在touchmove的時候,會改變盒子在垂直方向的位置 -->
<!-- transfrom樣式的值是一個計算屬性,會隨着this.translate變化而變化 -->
<slot name="top">
<div class="mint-loadmore-top" v-if="topMethod">
<span v-if="topStatus === 'loading'" class="mint-loadmore-spinner"></span>
<span class="mint-loadmore-text">{{ topText }}</span>
</div>
<!-- top插槽,列表上拉后下方出現的箭頭和loading文字或者動畫 -->
<!-- 當有topMethod這個props傳入的時候才顯示,此處是備用內容,如果父組件定義了top插槽內容,則備用內容不顯示 -->
</slot>
<slot></slot>
<!-- 默認插槽,就是數據列表 -->
<slot name="bottom">
<div class="mint-loadmore-bottom" v-if="bottomMethod">
<span v-if="bottomStatus === 'loading'" class="mint-loadmore-spinner"></span>
<span class="mint-loadmore-text">{{ bottomText }}</span>
</div>
</slot>
<!-- bottom插槽,列表上拉后下方出現的箭頭和loading文字或者動畫 -->
<!-- 當有bottomMethod這個props傳入的時候才顯示,此處是備用內容,如果父組件定義了bottom插槽內容,則備用內容不顯示 -->
</div>
</div>
</template>
<style lang="scss" scoped>
.mint-loadmore {
overflow: hidden;
}
.mint-loadmore-content .is-dropped {
transition: .2s;
}
.mint-loadmore-bottom {
text-align: center;
height: 50px;
line-height: 50px;
margin-bottom: -50px;
}
.mint-loadmore-top {
text-align: center;
height: 50px;
line-height: 50px;
margin-top: -50px;
}
</style>
<script type="text/babel">
export default {
name: 'loadmore',
components: {
},
props: {//props后跟着的對象是驗證器,type是類型,default是默認值
maxDistance: {
type: Number,
default: 0
},
autoFill: {
type: Boolean,
default: true
},
distanceIndex: {
type: Number,
default: 2
},
topPullText: {
type: String,
default: '下拉刷新'
},
topDropText: {
type: String,
default: '釋放更新'
},
topLoadingText: {
type: String,
default: '加載中...'
},
topDistance: {
type: Number,
default: 70
},
topMethod: {
type: Function
},
bottomPullText: {
type: String,
default: '上拉刷新'
},
bottomDropText: {
type: String,
default: '釋放更新'
},
bottomLoadingText: {
type: String,
default: '加載中...'
},
bottomDistance: {
type: Number,
default: 70
},
bottomMethod: {//加載下方數據方法
type: Function
},
bottomAllLoaded: {//布爾值,下方數據已經全部加載
type: Boolean,
default: false
}
},
data() {
return {
translate: 0, //content在y軸移動距離
scrollEventTarget: null, //scroll元素
containerFilled: false, //當前滾動的內容是否填充完整
topText: '', //上方提示文字
topDropped: false, //下拉刷新是否已經釋放
bottomText: '', //下方提示文字
bottomDropped: false, //底部加載是否已經釋放
bottomReached: false, //是否已經到達底部
direction: '', //滑動方向
startY: 0, //開始滑動的時候觸點的的Y坐標
startScrollTop: 0, //開始滑動的時候,scroll盒子的滾動距離
currentY: 0, //move過程中觸點的y軸坐標
topStatus: '', //上方loading層狀態,更新后會傳給父組件
bottomStatus: '' //下方loading層狀態,更新后會傳給父組件
};
},
computed: {
transform() {//計算屬性transform,,根據translate值變化,用於通過transform樣式改變content盒子的y軸坐標
return this.translate === 0 ? null : 'translate3d(0, ' + this.translate + 'px, 0)';
}
},
watch: {
topStatus(val) {
//偵聽器,如果topStatus發生變化,這個函數就會運行,觸發父級組件的事件,並把topStatus新值作為參數傳過去
this.$emit('top-status-change', val);
switch (val) {
case 'pull':
this.topText = this.topPullText;
break;
case 'drop':
this.topText = this.topDropText;
break;
case 'loading':
this.topText = this.topLoadingText;
break;
}
//根據topStatus的新值改變上方的提示文字
},
bottomStatus(val) {
//偵聽器,如果bottomStatus發生變化,這個函數就會運行,觸發父級組件的事件,並把bottomStatus新值作為參數傳過去
this.$emit('bottom-status-change', val);
switch (val) {
case 'pull':
this.bottomText = this.bottomPullText;
break;
case 'drop':
this.bottomText = this.bottomDropText;
break;
case 'loading':
this.bottomText = this.bottomLoadingText;
break;
}
//根據bottomStatus的新值改變下方的提示文字
}
},
methods: {
onTopLoaded() {//父級組件里每次加載完新數據就會調用這個方法
this.translate = 0;//重置this.translate
setTimeout(() => {
this.topStatus = 'pull';//數據加載完之后topStatus變為pull狀態
}, 200);
},
onBottomLoaded() {//父級組件里每次加載完新數據就會調用這個方法
this.bottomStatus = 'pull'; //數據加載完之后bottomStatus變為pull狀態
this.bottomDropped = false; //數據加載完之后bottomDropped變為false
this.$nextTick(() => {//數據變化后會更新DOM,DOM更新后會調用$nextTick()里的方法
if (this.scrollEventTarget === window) {
document.body.scrollTop += 50;
} else {
this.scrollEventTarget.scrollTop += 50;
}//數據加載完之后讓對應的scroll盒子向下多滾動50px,也就是說多顯示一條數據讓用戶看到
this.translate = 0;//重置this.translate
});
if (!this.bottomAllLoaded && !this.containerFilled) {
this.fillContainer();
}
},
getScrollEventTarget(element) {//獲取overflow:scroll的父級盒子
let currentNode = element;
while (currentNode && currentNode.tagName !== 'HTML' &&
currentNode.tagName !== 'BODY' && currentNode.nodeType === 1) {
//當前傳入節點存在且不是html也不是body且是一個元素節點的時候
let overflowY = document.defaultView.getComputedStyle(currentNode).overflowY;
//document.defaultView返回document關聯的window對象
//getComputedStyle()獲取元素的計算樣式
//overflowY是當前傳入節點的計算樣式overflow-y
if (overflowY === 'scroll' || overflowY === 'auto') {
return currentNode; //如果當前節點的overflow-y值是scroll或者auto,那就返回此節點
}
currentNode = currentNode.parentNode;//如果不是,那就獲取當前節點的父節點,然后繼續判斷
}
return window;//如果都找不到就返回window對象
},
getScrollTop(element) {//獲取元素的內容滾動距離
if (element === window) {
return Math.max(window.pageYOffset || 0, document.documentElement.scrollTop);
//window.pageYOffset就是Window.scrollY,文檔在垂直方向滾動距離
} else {
return element.scrollTop;
}
},
bindTouchEvents() {//為mint-loadmore綁定touch事件操作
this.$el.addEventListener('touchstart', this.handleTouchStart);
this.$el.addEventListener('touchmove', this.handleTouchMove);
this.$el.addEventListener('touchend', this.handleTouchEnd);
},
init() {
this.topStatus = 'pull';//topStatus初始值為pull
this.bottomStatus = 'pull';//bottomStatus初始值為pull
this.topText = this.topPullText;
this.scrollEventTarget = this.getScrollEventTarget(this.$el);
//獲取overflow:scroll的父級盒子
//傳給getScrollEventTarget方法的參數是this.$el,它是當前Vue實例使用的根DOM元素,也就是mint-loadmore
//this.scrollEventTarget最后獲取到是父組件的page-loadmore-wrapper盒子,因為它overflow:scroll;
if (typeof this.bottomMethod === 'function') {//父級組件傳入的加載數據函數如果存在的話
this.fillContainer();//判斷是否數據填充完全,初始化this.containerFilled的值
this.bindTouchEvents();//為mint-loadmore綁定touch事件操作
}
if (typeof this.topMethod === 'function') {//父級組件傳入的加載數據函數如果存在的話
this.bindTouchEvents();//為mint-loadmore綁定touch事件操作
}
},
fillContainer() {//判斷是否數據填充完全
if (this.autoFill) {
this.$nextTick(() => {
if (this.scrollEventTarget === window) {
this.containerFilled = this.$el.getBoundingClientRect().bottom >=
document.documentElement.getBoundingClientRect().bottom;
} else {
this.containerFilled = this.$el.getBoundingClientRect().bottom >=
this.scrollEventTarget.getBoundingClientRect().bottom;
//如果mint-loadmore的bottom值大於等於滾動盒子的bottom值,說明數據填充完全了,this.containerFilled為true
}
if (!this.containerFilled) {
this.bottomStatus = 'loading';
this.bottomMethod();
//如果數據並沒有填充完全,則bottomStatus狀態為loading,執行父組件的加載數據方法
}
});
}
},
checkBottomReached() {//檢查是否已經滑到底部
if (this.scrollEventTarget === window) {
/**
* fix:scrollTop===0
*/
return document.documentElement.scrollTop || document.body.scrollTop + document.documentElement.clientHeight >= document.body.scrollHeight;
//如果scroll元素是window的話,就判斷文檔滑動距離加上文檔高度是否大於等於body的內容高度
} else {
return parseInt(this.$el.getBoundingClientRect().bottom) <= parseInt(this.scrollEventTarget.getBoundingClientRect().bottom) + 1;
}
},
handleTouchStart(event) {
this.startY = event.touches[0].clientY;
//TouchEvent.touches返回所有當前在與觸摸表面接觸的Touch對象
//Touch對象表示在觸控設備上的觸摸點
//Touch.clientY,觸點相對於可見視區上邊沿的的Y坐標
//this.startY是開始滑動的時候觸點的Y坐標
this.startScrollTop = this.getScrollTop(this.scrollEventTarget);
//開始滑動的時候,scroll盒子的滾動距離
this.bottomReached = false;
//是否已經滑動到底部
if (this.topStatus !== 'loading') {//如果上方提示塊並未處於加載階段就重置topStatus和topDropped
this.topStatus = 'pull';
this.topDropped = false;
}
if (this.bottomStatus !== 'loading') {//如果下方提示塊並未處於加載階段就重置bottomStatus和bottomDropped
this.bottomStatus = 'pull';
this.bottomDropped = false;
}
},
handleTouchMove(event) {
if (this.startY < this.$el.getBoundingClientRect().top && this.startY > this.$el.getBoundingClientRect().bottom) {
return;
}
//如果觸點在mint-loadmore之外就退出move事件
this.currentY = event.touches[0].clientY;
//this.currentY是move過程中觸點的y軸坐標
let distance = (this.currentY - this.startY) / this.distanceIndex;
//滑動的距離
this.direction = distance > 0 ? 'down' : 'up';
//判斷滑動方向
if (typeof this.topMethod === 'function' && this.direction === 'down' &&
this.getScrollTop(this.scrollEventTarget) === 0 && this.topStatus !== 'loading') {
//如果滑到了頂部
event.preventDefault();//阻止默認事件
event.stopPropagation();//阻止事件冒泡
if (this.maxDistance > 0) {
this.translate = distance <= this.maxDistance ? distance - this.startScrollTop : this.translate;
} else {
this.translate = distance - this.startScrollTop;
//隨着滑動來更新translate值,translate值變化,計算屬性transform就隨之變化,content盒子就在y軸上向下移動
}
if (this.translate < 0) {//剛滑到頂部滑不動,會頓一下
this.translate = 0;
}
this.topStatus = this.translate >= this.topDistance ? 'drop' : 'pull';
//topDistance默認70,拉動距離超過70下方箭頭就變個方向
}
if (this.direction === 'up') {//如果是向上滑動,那就是底部加載,就判斷是否已經滑到底部
this.bottomReached = this.bottomReached || this.checkBottomReached();
}
if (typeof this.bottomMethod === 'function' && this.direction === 'up' &&
this.bottomReached && this.bottomStatus !== 'loading' && !this.bottomAllLoaded) {
//如果拉到底部了且數據沒有加載完
event.preventDefault();//阻止默認事件
event.stopPropagation();//阻止事件冒泡
if (this.maxDistance > 0) {
this.translate = Math.abs(distance) <= this.maxDistance
? this.getScrollTop(this.scrollEventTarget) - this.startScrollTop + distance : this.translate;
} else {
this.translate = this.getScrollTop(this.scrollEventTarget) - this.startScrollTop + distance;
//隨着滑動來更新translate值,translate值變化,計算屬性transform就隨之變化,content盒子就在y軸上向上移動
}
if (this.translate > 0) {//剛滑到底部滑不動,會頓一下
this.translate = 0;
}
this.bottomStatus = -this.translate >= this.bottomDistance ? 'drop' : 'pull';
//bottomDistance默認70,拉動距離超過70下方箭頭就變個方向
}
this.$emit('translate-change', this.translate);//觸發父組件事件,這個是上拉刷新的時候用的
},
handleTouchEnd() {
if (this.direction === 'down' && this.getScrollTop(this.scrollEventTarget) === 0 && this.translate > 0) {
//下拉刷新
this.topDropped = true;//drop狀態變更,content添加is-dropped樣式,回到原點動畫
if (this.topStatus === 'drop') {
this.translate = '50';
this.topStatus = 'loading';
this.topMethod();
//如果topStatus還是drop狀態,說明剛放手,那就讓content回到距離頂部50px的地方,然后改變topStatus為loading,然后執行父組件加載新數據的方法
} else {
this.translate = '0';
this.topStatus = 'pull';
//如果沒有從超過70的地方釋放,那就回到初始狀態,不加載新數據
}
}
if (this.direction === 'up' && this.bottomReached && this.translate < 0) {
//底部加載
this.bottomDropped = true;//drop狀態變更,content添加is-dropped樣式,回到原點動畫
this.bottomReached = false;//改變是否到達底部狀態
if (this.bottomStatus === 'drop') {
this.translate = '-50';
this.bottomStatus = 'loading';
this.bottomMethod();
//如果bottomStatus還是drop狀態,說明剛放手,那就讓content回到距離底部50px的地方,然后改變bottomStatus為loading,然后執行父組件加載新數據的方法
} else {
this.translate = '0';
this.bottomStatus = 'pull';
//如果沒有從超過70的地方釋放,那就回到初始狀態,不加載新數據
}
}
this.$emit('translate-change', this.translate);//觸發父組件事件,這個是上拉刷新的時候用的
this.direction = '';//清空方向
}
},
mounted() {//mounted的時候調用init()初始化組件狀態
this.init();
}
};
</script>
實現原理就是,外面有個wrapper盒子有死高度且擁有樣式overflow:scroll;的樣式,這樣它的內容超出后就是可滾動的,它的滾動高度scrollTop就可以拿來計算用。wrapper盒子里的內容除了數據列表以外還有一個loading層,這個loading層就是已經到頂部再繼續下拉 或者 已經到底部再上拉的時候才會顯示出來,平時的時候利用maring負值改變y軸方向的位置隱藏起來,它里面就是loading動畫和一個小箭頭提示標志,滑動的時候改變里面content盒子的y軸坐標,然后將loading層顯示出來,釋放的時候讓content盒子回到距離原位一個loading層高度的地方,然后發請求加載數據,等數據加載好了再次把所有DOM的狀態回歸到默認狀態。
