Vue 触底加载组件简单实现
找到一个好用的下拉刷新,上拉加载的vue 插件 vue-scroller, git 地址
return
今天写了个触底加载的组件,因为经常用到,之前总会遇到一种需求,就是有一个列表,可以实现下拉刷新,上拉加载,
找了一个一个的插件,填了一个一个的坑后,决定自己写个触底加载,简单实现下这个功能,不要跟我说:“这样不好看,我们要看
有橡皮筋那样的弹性效果,还要有下拉刷新,巴拉巴拉。。。。”,写过几次这种需求的我,已经不在乎这种效果了,丫的全是坑,
一句“可以,但没必要”,就完了。
废话说多了,来看下实现触底加载的几个步骤
1. 触底加载的布局,一个高度固定的容器,然后容器里面放一个列表,一般列表的初始高度是大于容器的高度,小于的话它滚动不了,就监听不到
它有没有滚到底部了。注意: 容器高度取 clientHeight ,列表高度取 offsetHeight
2. 监听容器的滚动事件,在滚动时获取滚出容器的高度,当滚出的高度加上容器的高度等于列表的高度时就触底了。触底加载的组件就这些逻辑了
上触底加载组件代码
1 <template> 2 <div class="infinite" ref="container" :style="{height: height}"> 3 <div class="inner" ref="inner"> 4 <!-- 列表标题 --> 5 <slot name="title"></slot> 6 <!-- 这里放列表 --> 7 <slot></slot> 8 <!-- 加载中的动画 --> 9 <slot name="loading" v-if="loading"></slot> 10 <!-- 加载完成的动画 --> 11 <slot name="nomore" v-if="nomore"></slot> 12 </div> 13 </div> 14 </template> 15 <script> 16 export default { 17 name: 'infinite-scroll', 18 props: { 19 height: { 20 type: String, 21 default: '100%' 22 }, 23 loading: { 24 type: Boolean, 25 default: false 26 }, 27 nomore: { 28 type: Boolean, 29 default: false 30 }, 31 }, 32 data () { 33 return { 34 containerHeight: 0, 35 innerHeight: 0 36 } 37 }, 38 created () { 39 40 }, 41 mounted () { 42 this.containerHeight = this.$refs.container.clientHeight 43 this.innerHeight = this.$refs.inner.offsetHeight 44 this.$refs.container.addEventListener('scroll', this.initScroll) 45 }, 46 methods: { 47 initScroll (e) { 48 if (this.loading || this.nomore) return 49 this.innerHeight = this.$refs.inner.offsetHeight 50 let scrollTop = e.target.scrollTop 51 if (scrollTop + this.containerHeight >= this.innerHeight) { 52 console.log('-----------------触底了-------------'); 53 this.$emit('loadBottom') 54 } 55 } 56 } 57 } 58 </script> 59 <style lang="less" scoped> 60 .infinite { 61 width: 100%; 62 background-color: skyblue; 63 overflow: auto; 64 -webkit-overflow-scrolling: touch; // 解决iOS滚动问题 65 } 66 </style>
然后在页面中使用这个组件,我把组件注册成全局组件了,所以直接就用在页面了
1 <template> 2 <div class="home"> 3 <div class="scroll"> 4 <infinite-scroll class="infinite" :loading="loading" :nomore="nomore" @loadBottom="loadmore" > 5 <template slot="title"> 6 <p>这是一个标题</p> 7 </template> 8 <p v-for="item in list" :key="item.id">{{ item.name + '---' + item.value }}</p> 9 <template slot="loading" > 10 <i>加载中</i> 11 </template> 12 <template slot="nomore"> 13 <i>没有更多了</i> 14 </template> 15 </infinite-scroll> 16 </div> 17 </div> 18 </template> 19 <script> 20 export default { 21 data () { 22 return { 23 loading: false, 24 pageSize: 10, 25 pageNumber: 1, 26 total: 0, 27 loadTotal: false, 28 list: [] 29 } 30 }, 31 created () { 32 this.loadmore() 33 }, 34 methods: { 35 async loadmore () { 36 if (this.loading || this.nomore) return 37 this.loading = true 38 const response = await this.$post('******', { 39 pageSize: this.pageSize, 40 pageNumber: this.pageNumber 41 }) 42 if ('请求成功') { 43 this.total = response.totalRecord 44 this.list.push(...response.list) 45 if (this.list.length >= this.total) { 46 this.nomore = true 47 } else { 48 this.pageNumber ++ 49 } 50 } 51 this.$nextTick(() => { 52 setTimeout(() => { 53 this.loading = false 54 }, 300); 55 }) 56 }, 57 } 58 } 59 </script> 60 <style lang="less" scoped> 61 .home { 62 padding: 1px; 63 .scroll { 64 width: 80%; 65 height: 7rem; 66 margin: 1rem auto; 67 .infinite { 68 font-size: .32rem; 69 line-height: .8rem; 70 overflow: auto; 71 i { 72 font-size: .24rem; 73 text-align: center; 74 width: 100%; 75 display: block; 76 } 77 } 78 } 79 } 80 </style>
组件中有这么几个参数时必传的
1. loading 节流的,开始加载时是 true 加载更多的请求完成并显示在页面上了改为 false
2. nomore 所有数据是否都已加载完成
3. loadBottom 监听这个事件,事件触发后就是要加载更多了
4. 还有一些 slot ,用则写,不用就不管了