100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > 实现一个移动端无限滚动+下拉刷新列表组件

实现一个移动端无限滚动+下拉刷新列表组件

时间:2024-03-07 07:38:21

相关推荐

实现一个移动端无限滚动+下拉刷新列表组件

部分功能描述

下拉松开可以刷新列表

滚动触底加载分页数据

底部加载失败点击重新加载

加载完毕显示加载完成

使用

项目中

<template><div class="page"><div class="list"><!-- 查询无结果 showFlag===1 --><!-- <notFound v-if="showFlag===1"></notFound> --><!-- 网络无法链接 showFlag===2 --><!-- <searchError v-else-if="showFlag===2"></searchError> --><!-- 搜索结果 showFlag===0 --><scrollBox ref="result" v-else-if="showFlag===0":noMore='noMoreData':onInfinite='onInfinite':onRefresh='onRefresh':hidefooter='hidefooter'><div><div class="card" v-for="(item, i) in dataList" :key="i"></div></div></scrollBox></div></div></template><script>import scrollBox from '../components/scrollBox'export default {components: {scrollBox },data () {return {showFlag: 0,noMoreData: false,dataList: [],fetchData: {pageNum: 0,pageSize: 10,searchName: ''}}},computed: {hidefooter () {return this.dataList.length > 0}},methods: {getList (data, type, fn) {if (type === 'init' || type === 'search') loading.start()this.httpRequest({method: 'POST',url: '',data: data}).then(res => {loading.end()fn && fn()if (res.data.code === '000') {switch (type) {let resultList = res.data.data.resultListlet totalNum = res.data.data.totalNumcase 'init':this.dataList = resultListthis.notFound = this.dataList.length === 0 ? 1 : 0if (this.dataList.length > 0) {this.showFlag = 0}breakcase 'refresh' :case 'search':this.dataList = resultListthis.notFound = 0this.showFlag = this.dataList.length === 0 ? 1 : 0if (this.dataList.length > 0) {this.showFlag = 0}breakcase 'infinite':this.dataList = this.dataList.concat(resultList)break}if (this.dataList.length && this.dataList.length < +totalNum) {this.noMoreData = false // 显示加载中} else {this.noMoreData = true // 显示加载完成}} else if (res.data.code) {this.fetchData.pageNum--fn && fn(true)this.showFlag = 1} else {this.fetchData.pageNum--fn && fn(true)this.showFlag = 2}}).catch(e => {console.warn(e)})},onInfinite (done) {// 滚动至底部触发加载this.fetchData.pageNum++this.getList(this.fetchData, 'infinite', done)},onRefresh (done) {// 松开刷新this.fetchData.pageNum = 0this.getList(this.fetchData, 'refresh', done)}},mounted () {this.getList(this.fetchData, 'init')}}</script><style lang="less" scoped>@w:20rem;.list{position: absolute;top: 0;left:0;bottom: 0;right: 0;}</style>

组件

<template lang="html"><div class="yo-scroll":class="{'down':(state===0),'up':(state==1),refresh:(state===2),touch:touching}"@touchstart="touchStart($event)"@touchmove="touchMove($event)"@touchend="touchEnd($event)"@scroll="(onInfinite || infiniteLoading) ? onScroll($event) : undefined"><div><slot name='theader'></slot></div><section class="inner" :style="{transform: 'translate3d(0, ' + top + 'px, 0)' }"><header class="pull-refresh" v-if='enableRefresh'><slot name="pull-refresh"><div class="up-tip">松开更新</div><div class="refresh-tip isLoading"><img src="../../../assets/loading.gif" /><span>正在更新</span></div></slot></header><slot></slot><footer class="load-more" v-if='enableInfinite' v-show='hidefooter'><slot name="load-more"><div v-if='infiniteError' class='isLoadded' @click='infiniteErrorClick'><span></span><div>加载失败,点击重试</div><span></span></div><div v-else><div v-if='innerNoMore' class='isLoadded'><span></span><div>加载完成</div><span></span></div><div v-else class="isLoading"><img src="../../../assets/loading.gif" /><span>正在加载</span></div></div></slot></footer></section></div></template><script>export default {props: {offset: {type: Number,default: 40},enableInfinite: {type: Boolean,default: true},enableRefresh: {type: Boolean,default: true},onRefresh: {type: Function,default () {return () => {}}},onInfinite: {type: Function,default () {return () => {}}},noMore: {type: Boolean,default: false},hidefooter: {type: Boolean,default: true}},data () {return {top: 0,state: 0,startY: 0,touching: false,infiniteLoading: false,infiniteError: false,timeStamp: new Date().getTime(),removeTop: 0}},computed: {innerNoMore: {get () {return this.noMore},set (val) {this.$emit('update:noMore', val)}}},watch: {removeTop: {handler () {this.$emit('scrollTop', this.$el.scrollTop)}}},methods: {touchStart (e) {this.startY = e.targetTouches[0].pageYthis.removeTop = this.$el.scrollTopthis.startScroll = this.$el.scrollTop || 0this.touching = truethis.timeStamp = new Date().getTime()},touchMove (e) {if (!this.enableRefresh || this.$el.scrollTop > 0 || !this.touching) {return}let diff = e.targetTouches[0].pageY - this.startY - this.startScrollif (diff > 0) e.preventDefault()this.top = Math.pow(diff, 0.8) + (this.state === 2 ? this.offset : 0)if (this.state === 2) {// in refreshingreturn}if (this.top >= this.offset) {this.state = 1} else {this.state = 0}},touchEnd (e) {if (!this.enableRefresh) returnthis.touching = falseif (new Date().getTime() - this.timeStamp <= 50) {return}if (this.state === 2) {// in refreshingthis.state = 2this.top = this.offsetreturn}if (this.top >= this.offset) {// do refreshthis.refresh()} else {// cancel refreshthis.state = 0this.top = 0}},refresh () {this.state = 2this.top = this.offsetthis.innerNoMore = falsethis.infiniteError = false// this.onRefresh(this.refreshDone)this.onRefresh(this.refreshDone)},refreshDone () {this.state = 0this.top = 0},infinite () {if (this.infiniteLoading === false) {this.infiniteLoading = truethis.onInfinite(this.infiniteDone)}},infiniteErrorClick () {this.infiniteLoading = truethis.infiniteError = falsethis.onInfinite(this.infiniteDone)},infiniteDone (flag = false) {this.infiniteLoading = falsethis.infiniteError = flag},onScroll (e) {if (this.innerNoMore) {return}if (this.infiniteError) {return}if (this.scrollFlag) {if (!this.enableInfinite || this.infiniteLoading) {return}}let outerHeight = this.$el.clientHeightlet innerHeight = this.$el.querySelector('.inner').clientHeightlet scrollTop = this.$el.scrollToplet ptrHeight = this.onRefresh && this.enableRefresh ? this.$el.querySelector('.pull-refresh').clientHeight : 0let infiniteHeight = this.$el.querySelector('.load-more').clientHeightlet bottom = innerHeight - outerHeight - scrollTop - ptrHeightif (bottom <= infiniteHeight) {this.infinite()}}}}</script><style lang='less' scoped>@w:20rem;.yo-scroll {position: absolute;top: 0;right: 0;bottom: 0;left: 0;overflow: auto;-webkit-overflow-scrolling: touch;display: flex;flex-direction: column;color: #c3c3c3;}.yo-scroll .inner {position: relative;width: 100%;transition-duration: 300ms;}.yo-scroll .pull-refresh {position: relative;left: 0;top: 0;width: 100%;line-height: 1;display: flex;align-items: center;justify-content: center;font-size: 17/@w;}.yo-scroll.touch .inner {transition-duration: 0ms;}.yo-scroll.down .down-tip {display: block;height: 0;}.yo-scroll.up .up-tip {display: block;}.yo-scroll.refresh .refresh-tip {display: block;}.yo-scroll .down-tip,.yo-scroll .refresh-tip,.yo-scroll .up-tip {display: none;}.isLoading {text-align: center;font-size: 17/@w;line-height: 34/@w;display: flex;align-items: center;justify-content: center;img {height: 15/@w;margin-right: 20/@w;vertical-align: middle}}.isLoadded {padding: 15/@w 0;text-align: center;font-size: 17/@w;color: #c3c3c3;display: flex;line-height: 30/@w;align-items: center;width: 65%;margin: 0 auto;span {flex-grow: 1;height: 1px;background-color: #e3e3e3;}div{white-space: nowrap;padding: 0 1em;flex-shrink: 0;}}</style>

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。