Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”
TIP ๐ carefully planted flowers do not hair, leisurely inserted liuliu chengyin. Yuan ยท Guan Hanqing, “Lu Zhailang”
preface
In our daily project development, we will be involved in the function of the scroll list, so encapsulate the scroll list component.
Scroll list component
attribute
PullDownRefresh – pullDownRefresh
- Value types: Boolean | Object
- Default value:
{
threshold: flexible.rem2px(100 / 75), // The pull-down distance to trigger the refresh
stop: flexible.rem2px(90 / 75) // The distance of the bounce hover
}
Copy the code
PullUpLoad – Pull-up load
- Value types: Boolean | Object
- Default value: true
- Example values of the Object type:
{
threshold: 0 // Indicates the threshold for triggering the pull-up event
}
Copy the code
ScrollConfig – Scrollbar component configuration
- Value type: Object
- Default value:
{
wrapperBgColor: '#F5F5F5'.// Background color of scroll bar wrapper
bounce: true.// Displays a rebound animation
bounceTime: 800.// The animation length of the rebound animation (in milliseconds)
useTransition: false.// Use requestAnimationFrame to animate
observeDOM: true // Enable detection of DOM changes
}
Copy the code
For details, see the Scroll component
The event
1. Refresh – Refresh data (this event is triggered after the component is created successfully or after the top of the list is pulled down)
Parameters:
- Callback: callback method after successfully refreshing data
- Method parameters: status Data status, SUCCESS (success), no-data(no data), no-more(no more data), fail(fail)
ใ Attention ใ :
- If there is pagination, the listener for this event should query the data on the first page, and the queried data should replace the current data array rather than append to it
- After the component is successfully created, a Refresh event is automatically triggered
2. Load – Load data (this event is triggered when scrolling to the bottom of the list and pulling up)
Parameters:
- Callback: callback method after successfully refreshing data
- Method parameters: status Data status, SUCCESS (no more data), fail(failed)
ใ Attention ใ :
- If there is pagination, the listener should query the next page of data and append the data to the data array
The sample
<template>
<ScrollList @refresh="handleRefresh" @load="handleLoad">
<ul class="data-list" v-if="dataList.length > 0">
<li class="item" v-for="item in dataList" :key="item.id">
<div class="title">{{item.title}}</div>
<div class="date">{{item.articleDate}}</div>
</li>
</ul>
</ScrollList>
</template>
<script>
import ScrollList from '@/components/m/scrollList'
export default {
components: {
ScrollList
},
data () {
return {
pageSize: 10.// Size per page
pageNo: 0./ / page
count: 0.// Total number of data
dataList: [].// List data
isLoading: false // Whether the file is being loaded}},methods: {
// Get list data
getList (pageNo) {
if (this.isLoading) {
return
}
this.isLoading = true
pageNo = pageNo || this.pageNo + 1
return this.$api.post({
url: '/api/article/list'.data: { pageSize: this.pageSize, pageNo }
}, this).then(data= > {
this.pageNo = data.page.pageNo
this.count = data.page.count
if (this.pageNo > 1) {
this.dataList = [...this.dataList, ...data.page.list]
} else {
this.dataList = data.page.list
}
this.isLoading = false
let status = 'success' // The query succeeded
if (data.page.count === 0) {
status = 'no-data' // There is no data yet
} else if (data.page.count <= data.page.pageNo * this.pageSize) {
status = 'no-more' // No more data
}
return status
}, e= > {
this.isLoading = false
return 'fail' // Query failed})},// Refresh operation (a refresh event is automatically triggered when the page is initialized)
handleRefresh (callback) {
this.getList(1).then((status) = > {
callback(status)
})
},
// Load operation
handleLoad (callback) {
this.getList().then((status) = > {
callback(status)
})
}
}
}
</script>
Copy the code
Scroll.vue
<template>
<Scroll v-if="config" ref="scroll" v-bind="config" @created="init">
<div v-if="inited" class="pulldown-wrapper">
<div v-show="beforePullDown" class="pulldown-tips">
<span>Release to refresh</span>
</div>
<div v-show=! "" beforePullDown">
<div v-show="isPullingDown" class="loading">
<BaseSpinner spinner="bubbles" size="s"></BaseSpinner>
<span class="loading-txt">Loading in...</span>
</div>
<div v-show=! "" isPullingDown" class="refresh-result">
<span v-if="isFail">Refresh the failure</span>
<span v-else>Refresh the success</span>
</div>
</div>
</div>
<div v-else-if="isIniting" class="init-tips">
<div class="loading">
<BaseSpinner spinner="bubbles" size="s"></BaseSpinner>
<span class="loading-txt">Loading in...</span>
</div>
</div>
<div v-else-if="isFail" class="error-tips">
<div v-if=! "" isPullingDown" class="error-content" @click="emitRefresh">
<Icon name="cry" class="error-icon"></Icon>
<span>Query failed. Click Retry</span>
</div>
</div>
<slot ref="list"></slot>
<template v-if="inited">
<div v-if="status === 'no-data'" class="no-data-tips">
<div v-if=! "" isPullingDown" class="no-data-content">
<Icon name="no-data" class="no-data-icon"></Icon>
<span>Temporarily no data</span>
</div>
</div>
<div v-else class="pullup-tips">
<div v-if="status === 'no-more'" class="no-more-tips">
<span>There's no more data</span>
</div>
<div v-else-if=! "" isPullUpLoad">
<span v-if="isFail">Loading failed. Please pull up and try again</span>
<span v-else>Pull up to load more</span>
</div>
<div v-else class="loading">
<BaseSpinner spinner="bubbles" size="s"></BaseSpinner>
<span class="loading-txt">Loading in...</span>
</div>
</div>
</template>
</Scroll>
</template>
<script>
import Scroll from '@/components/base/scroll'
import BaseSpinner from '@/components/base/spinner'
const defaultConfig = {
wrapperBgColor: '#F5F5F5'.// Background color of scroll bar wrapper
bounce: true.// Displays a rebound animation
bounceTime: 800.// The animation length of the rebound animation (in milliseconds)
useTransition: false.// Use requestAnimationFrame to animate
observeDOM: true // Enable detection of DOM changes
}
export default {
name: 'ScrollList'.components: {
Scroll,
BaseSpinner
},
props: {
// Drop refresh
pullDownRefresh: {
type: [Boolean.Object].default: () = > {
let threshold = 100
let stop = 90
if (window.lib && window.lib.flexible) {
let flexible = window.lib.flexible
threshold = flexible.rem2px(threshold / 75)
stop = flexible.rem2px(stop / 75)}return {
threshold: threshold, // The pull-down distance to trigger the refresh
stop: stop // The distance of the bounce hover}}},// Pull up load
/* Example object {threshold: 0 // The threshold for triggering pull-up events} */
pullUpLoad: {
type: [Boolean.Object].default: true
},
// Scroll bar component configuration
scrollConfig: {
type: Object.default: () = > { return {} }
}
},
data () {
return {
config: null.inited: false.// Whether it has been initialized
isIniting: false.// Whether initialization is in progress
isFail: false.// Whether to fail
status: ' '.// Current status: SUCCESS, no-data, no-more
beforePullDown: true.// Whether to pull down before releasing the hand
isPullingDown: false.// Whether the refresh is being pulled down
isPullUpLoad: false // Whether the load is being pulled up}},watch: {
scrollConfig (val) {
this.config = this.getConfig()
},
pullDownRefresh (val) {
this.config = this.getConfig()
},
pullUpLoad (val) {
this.config = this.getConfig()
}
},
created () {
this.config = this.getConfig()
// Trigger the refresh
this.emitRefresh()
},
mounted () {
// Set the minimum height of the content area to 1 pixel larger than the wrapper to ensure scrolling
this.setContentMinHeight()
},
methods: {
/ / initialization
init (bs) {
bs.on('pullingDown'.this.pullingDownHandler)
bs.on('pullingUp'.this.pullingUpHandler)
// bs.on('scroll', e => { console.log('scroll') })
// bs.on('scrollEnd', e => { console.log('scrollEnd') })
},
getConfig () {
constconfig = { ... defaultConfig, ... this.scrollConfig }if (this.pullDownRefresh) {
config.pullDownRefresh = this.pullDownRefresh
}
if (this.pullUpLoad) {
config.pullUpLoad = this.pullUpLoad
}
return config
},
// Trigger the refresh
emitRefresh () {
if (this.isIniting) {
return
}
this.isIniting = true
this.$emit('refresh'.(status) = > {
this.status = status
this.isIniting = false
if(status ! = ='fail') {
this.inited = true
this.isFail = false
} else {
this.isFail = true}})},// Drop down operation
pullingDownHandler () {
if (!this.inited || this.isPullingDown || this.isPullUpLoad) {
if (!this.isPullingDown) {
const bs = this.$refs.scroll && this.$refs.scroll.bs / / BetterScroll instance
bs.finishPullDown()
}
return
}
this.beforePullDown = false
this.isPullingDown = true
this.$emit('refresh'.(status) = > {
if(status ! = ='fail') {
this.status = status
this.isFail = false
} else {
this.isFail = true
}
this.isPullingDown = false
const bs = this.$refs.scroll && this.$refs.scroll.bs / / BetterScroll instance
if (bs) {
bs.finishPullDown()
setTimeout(() = > {
this.beforePullDown = true
bs.refresh()
if (this.pullUpLoad) {
bs.openPullUp(this.pullUpLoad)
}
}, this.config.bounceTime + 100)}})},// Pull up operation
pullingUpHandler () {
if (!this.inited || this.isPullingDown || this.isPullUpLoad ||
this.status === 'no-data' || this.status === 'no-more') {
const bs = this.$refs.scroll && this.$refs.scroll.bs / / BetterScroll instance
if (bs) {
bs.finishPullUp()
}
return
}
this.isPullUpLoad = true
this.$emit('load'.(status) = > {
if(status ! = ='fail') {
this.status = status
this.isFail = false
} else {
this.isFail = true
}
this.isPullUpLoad = false
const bs = this.$refs.scroll && this.$refs.scroll.bs / / BetterScroll instance
if (bs) {
bs.finishPullUp()
bs.refresh()
}
})
},
// Set the minimum height of the content area to 1 pixel larger than the wrapper to ensure scrolling
setContentMinHeight () {
const scroll = this.$refs.scroll
const wrapperHeight = scroll.$refs.wrapper.getBoundingClientRect().height
scroll.$refs.content.style.minHeight = (wrapperHeight + 1) + 'px'}}}</script>
<style lang="scss" scoped>
.pulldown-wrapper{
position: absolute;
width: 100%;
padding: 20px;
box-sizing: border-box;
transform: translateY(-100%) translateZ(0);
text-align: center;
color: # 999;
}
.pulldown-tips {
line-height: 110px;
}
.init-tips {
padding-top: 20px;
}
.loading {
display: flex;
align-items: center;
justify-content: center;
color: # 999;
.loading-txt {
margin-left: 12px; }}.refresh-result {}
.no-data-tips {
padding-top: 50px;
text-align: center;
color: # 999;
.no-data-content {
display: flex;
flex-direction: column;
.no-data-icon {
font-size: 120px;
margin-bottom: 20px; }}}.error-tips {
padding-top: 40px;
text-align: center;
color: # 999;
.error-content {
display: flex;
flex-direction: column;
.error-icon {
font-size: 120px;
margin-bottom: 10px; }}}.pullup-tips {
padding: 20px;
text-align: center;
color: # 999;
.no-more-tips {
padding-bottom: 30px; }}</style>
Copy the code
index.js
/ * * * * @ scrolling list component's https://github.com/ustbhuangyi/better-scroll * @ see https://better-scroll.github.io/docs/zh-CN/ * / import ScrollList from './ScrollList.vue' export default ScrollListCopy the code
“Feel free to discuss in the comments section.”