概述
目录
前言
项目中使用的截图如下
封装better-scroll
组件的使用
后续
前言
本来想使用vux的scroller组件,但是看到官方说不在维护了,而且在提供的样例里面,虽然例子有可以自定义加载等待区域以及文字提示的内容,但是实际上却没有找到相关样例代码,改来改去也改不成想要的样子。。。最后放弃了。在网上查了很多,后来发现better-scroll这个插件就是为了这种应用场景而生的,简直不能再好。
官方地址:https://ustbhuangyi.github.io/better-scroll/doc/zh-hans/
项目中使用的截图如下
封装better-scroll
我对better-scroll又进行了封装,封装为scroll.vue,代码如下:
<template>
<div ref="wrapper" class="list-wrapper">
<div class="scroll-content">
<div ref="listWrapper">
<slot>
</slot>
<slot name="pullup"
:pullUpLoad="pullUpLoad"
:isPullUpLoad="isPullUpLoad"
>
<div class="pullup-wrapper" v-if="pullUpLoad">
<load-more :show-loading="isPullUpLoad"
:tip="pullUpTxt">
</load-more>
</div>
</slot>
</div>
</div>
<slot name="pulldown"
:pullDownRefresh="pullDownRefresh"
:pullDownStyle="pullDownStyle"
:beforePullDown="beforePullDown"
:isPullingDown="isPullingDown"
>
<div ref="pulldown" class="pulldown-wrapper" :style="pullDownStyle" v-if="pullDownRefresh">
<load-more :show-loading="isPullingDown" :tip="refreshTxt"></load-more>
</div>
</slot>
</div>
</template>
<script type="text/ecmascript-6">
import BScroll from 'better-scroll'
import {LoadMore} from 'vux'
const COMPONENT_NAME = 'scroll'
export default {
name: COMPONENT_NAME,
props: {
data: {
type:Array,
default:[]
}
},
data() {
return {
pullDownRefresh: {
threshold: 90,
stop: 70
},
pullUpLoad: {
threshold: 20
},
beforePullDown: true,
isRebounding: false,
isPullingDown: false,
isPullUpLoad: false,
pullUpDirty: true,
pullDownStyle: '',
isLoading:'正在加载',
pullRefresh:'下拉刷新↓',
moreTxt:'上推加载更多↑',
noMoreTxt:'没有更多',
refreshSuccess:'刷新成功'
}
},
computed: {
pullUpTxt() {
if (this.isPullUpLoad) {
return this.isLoading;
} else {
return this.pullUpDirty ? this.moreTxt : this.noMoreTxt;
}
},
refreshTxt(){
if(this.beforePullDown && !this.isPullingDown){
return this.pullRefresh;
}
if(this.isPullingDown){
return this.isLoading;
}else{
return this.refreshSuccess;
}
}
},
created() {
this.pullDownInitTop = -50
},
mounted() {
setTimeout(() => {
this.initScroll()
}, 20)
},
destroyed() {
this.$refs.scroll && this.$refs.scroll.destroy()
},
methods: {
initScroll() {
if (!this.$refs.wrapper) {
return
}
if (this.$refs.listWrapper && (this.pullDownRefresh || this.pullUpLoad)) {
this.$refs.listWrapper.style.minHeight = `${ctool.getRect(this.$refs.wrapper).height + 1}px`
}
let options = {
probeType: 1,
scrollbar: {
fade: true,
interactive: false
},
pullDownRefresh: this.pullDownRefresh,
pullUpLoad: this.pullUpLoad,
mouseWheel: true,
click:true,
tap:true
}
this.scroll = new BScroll(this.$refs.wrapper, options);
if (this.pullDownRefresh) {
this._initPullDownRefresh()
}
if (this.pullUpLoad) {
this._initPullUpLoad()
}
},
disable() {
this.scroll && this.scroll.disable()
},
enable() {
this.scroll && this.scroll.enable()
},
refresh() {
this.scroll && this.scroll.refresh()
},
scrollTo() {
this.scroll && this.scroll.scrollTo.apply(this.scroll, arguments)
},
scrollToElement() {
this.scroll && this.scroll.scrollToElement.apply(this.scroll, arguments)
},
destroy() {
this.scroll.destroy()
},
forceUpdate(dirty) {
if (this.pullDownRefresh && this.isPullingDown) {
this.isPullingDown = false
this._reboundPullDown().then(() => {
this._afterPullDown()
})
} else if (this.pullUpLoad && this.isPullUpLoad) {
this.isPullUpLoad = false
this.scroll.finishPullUp()
this.pullUpDirty = dirty
this.refresh()
} else {
this.refresh()
}
},
setdirtyfalse(){
this.pullUpDirty = false;
},
_initPullDownRefresh() {
this.scroll.on('pullingDown', () => {
this.beforePullDown = false
this.isPullingDown = true
this.$emit('pullingDown')
})
this.scroll.on('scroll', (pos) => {
if (!this.pullDownRefresh) {
return
}
if (this.beforePullDown) {
this.pullDownStyle = `top:${Math.min(pos.y + this.pullDownInitTop, 10)}px`
}
if (this.isRebounding) {
this.pullDownStyle = `top:${10 - (this.pullDownRefresh.stop - pos.y)}px`
}
})
},
_initPullUpLoad() {
this.scroll.on('pullingUp', () => {
this.isPullUpLoad = true
this.$emit('pullingUp')
})
},
_reboundPullDown() {
const {stopTime = 600} = this.pullDownRefresh
return new Promise((resolve) => {
setTimeout(() => {
this.isRebounding = true
this.scroll.finishPullDown()
resolve()
}, stopTime)
})
},
_afterPullDown() {
setTimeout(() => {
this.pullDownStyle = `top:${this.pullDownInitTop}px`
this.beforePullDown = true
this.isRebounding = false
this.refresh()
}, this.scroll.options.bounceTime)
}
},
watch: {
data() {
setTimeout(() => {
this.forceUpdate(true)
}, this.refreshDelay)
}
},
components: {
LoadMore
}
}
</script>
<style>
.list-wrapper {
position: relative;
height: 100%;
overflow: hidden;
background: #fff;
}
.scroll-content {
position: relative;
z-index: 1;
}
.pulldown-wrapper {
position: absolute;
width: 100%;
left: 0;
display: flex;
justify-content: center;
align-items: center;
transition: all;
}
.before-trigger {
margin-top: 5px;
}
.after-trigger {
text-align: center;
margin-top: 5px;
width: 100%;
}
.loading{
width: 100%;
}
.pullup-wrapper {
width: 100%;
display: flex;
left: 0;
justify-content: center;
align-items: center;
padding: 10px 0;
}
</style>
这个组件代码,可以直接直接复制出去用。其中initScroll方法中有一个getRect方法,该方法的主要作用是为了设置列表容器的高度一定比父div高,不然就不会出现滚动条,也无法响应下拉刷新的动作。
这里注意下面这两个css
.list-wrapper {
position: relative;
height: 100%;
overflow: hidden;
background: #fff;
}
.scroll-content {
position: relative;
z-index: 1;
}
这两个css的position都是relative,且list-wrapper的高度是100%。这就意味着,他们的高度是等于父div的高度的,而父div的高度就是我们引用这个组件时候,包裹组件的div高度。那么,【划重点】,这就要求我们使用的时候,包裹组件的div一定要指定具体的高度,这个高度怎么去,后面会代码说明。
getRect的方法代码如下:
getRect(el) {
if (el instanceof window.SVGElement) {
let rect = el.getBoundingClientRect()
return {
top: rect.top,
left: rect.left,
width: rect.width,
height: rect.height
}
} else {
return {
top: el.offsetTop,
left: el.offsetLeft,
width: el.offsetWidth,
height: el.offsetHeight
}
}
},
组件的使用
<template xmlns:v-on="http://www.w3.org/1999/xhtml" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<div>
<div class="base_div" ref="ldiv">
<scroll ref="scroll"
:data="items"
@pullingDown="onPullingDown"
@pullingUp="onPullingUp">
<div class="list-content">
<div v-for="(item, index) in items"
v-on:click="toDetail(item)">
<adapter :data="item"></adapter>
</div>
</div>
</scroll>
</div>
</div>
</template>
<script>
import Scroll from './scroll'
import adapter from './listAdapter'
export default {
props: {
url: String,//ajax请求的url
page:1,
params: {//筛选条件
type: Object,
default: function () {
return {};
}
}
},
data() {
return {
items: [],
},
mounted() {
this.$refs.ldiv.style.height = `${ctool.getHeight(this.ui_type)}px`;
},
methods: {
//---下拉刷新滚动相关
onPullingDown() {
//下拉刷新
this.page = 1;
this.ajaxPost();
},
onPullingUp() {
// 上推加载更多
this.page++;
this.ajaxPost();
},
ajaxPost(){
console.log('');
},
toDetail(obj){
console.log('click detail');
},
},
components: {
Scroll, adapter, Flexbox, FlexboxItem, Search, Popup, XButton, Group, Datetime
}
}
</script>
<style>
.search_div {
border-bottom: solid 1px #E4E4E4;
min-height: 36px;
}
.base_div {
height: 100%;
position: relative;
width: 100%;
padding-bottom: 2rem;
}
.list-content {
position: relative;
z-index: 10;
background: #fff;
}
</style>
在具体使用的时候,有几点要重点注意,主要是关于css样式的。
关于css的position属性说明,默认情况下,position:static,即正常的按照元素的块级、行排列即可。
常用的还有relative布局和absolute布局。需要说明的是,relative布局是相对于他自身static布局的布局,如果不指定位置,则就是static布局。但是好处在于,假如他的父div高度是300,它设置高度100%,则会直接也是300的高度,而不是像static布局那样,自动填充的。关于布局这里不做过多介绍,参考这里自行再了解。
前面提到包裹scroll.vue组件的div一定要设置固定高度,否则组件内部渲染的item高度会自动把父div撑大,也就不存在下拉刷新,上推加载更多的响应事件了。如何根据屏幕大小自动设置div的高度呢?重点就在mounted方法中。下面是getHeight方法的源码:
getHeight(type){
//获取当前应用所在容器的高度,可以理解为浏览器高度或者屏幕高度,52是我自己要减去的header的高度
var rh = document.documentElement.clientHeight - 52;
if (type == 1) {
return rh;
}else if(type==2){
return rh-70;//####3
}else if(type==3){
return rh-63-50;//tabBar/筛选(tab高度略)
}
}
根据自己的需要调整下里面相关柱子的大小即可。
至此,基于better-scroll的下拉刷新,上推加载更多组件应用就写完了。
后续
20191113记录。
在钉钉PC端使用的时候,出现点击无效的情况。解决方案参考这里。
最后
以上就是潇洒银耳汤为你收集整理的基于better-scroll的下拉刷新上推加载更多后续的全部内容,希望文章能够帮你解决基于better-scroll的下拉刷新上推加载更多后续所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复