提交 11c7816c 编写于 作者: 雪洛's avatar 雪洛

feat: uni-recycle-view适配微信小程序

上级 e71e5c8f
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
此示例中仅渲染滚动容器上下5屏的内容。适用于仅使用一个for循环创建所有列表项的场景。文档详见插件市场:https://ext.dcloud.net.cn/plugin?id=17385</view> 此示例中仅渲染滚动容器上下5屏的内容。适用于仅使用一个for循环创建所有列表项的场景。文档详见插件市场:https://ext.dcloud.net.cn/plugin?id=17385</view>
<uni-recycle-view style="flex: 1;" :list="list" @scrolltoupper="scrolltoupper" @scroll="scroll"> <uni-recycle-view style="flex: 1;" :list="list" @scrolltoupper="scrolltoupper" @scroll="scroll">
<template v-slot:default="{items}"> <template v-slot:default="{items}">
<uni-recycle-item class="item" v-for="item in (items as Item[])" :item="item" :key="item.id"> <!-- scroll-view内:key只绑定数据内的id时在微信小程序端有Bug,表现为滚动位置跳动,初步判断为微信scroll-view的Bug。 -->
<uni-recycle-item class="item" v-for="(item, index) in (items as Item[])" :item="item" :key="index + '_' + item.id">
<view class="item-wrapper"> <view class="item-wrapper">
<view class="name"><text style="font-size: 14px;">{{item.name}}</text></view> <view class="name"><text style="font-size: 14px;">{{item.name}}</text></view>
<view class="info"><text style="font-size: 12px; color: #999999;">{{item.info}}</text></view> <view class="info"><text style="font-size: 12px; color: #999999;">{{item.info}}</text></view>
......
<template> <template>
<view class="item-container"> <view class="uni-recycle-view-item" :style="this.itemHeight != 0 ? {height: this.itemHeight + 'px'} : {}">
<slot></slot> <slot></slot>
</view> </view>
</template> </template>
...@@ -19,18 +19,32 @@ ...@@ -19,18 +19,32 @@
} }
}, },
inject: { inject: {
itemHeight: {
type: Number as PropType<number>
},
setCachedSize: { setCachedSize: {
type: Function as PropType<(item : any, size : number) => void> type: Function as PropType<(item : any, size : number) => void>
}, },
getCachedSize: {
type: Function as PropType<(item : any) => number | null>
},
}, },
mounted() { mounted() {
uni.createSelectorQuery().in(this).select('.item-container').boundingClientRect().exec((ret) => { if (this.itemHeight == 0) {
const cachedSize = this.getCachedSize(this.item)
if(cachedSize == null) {
uni.createSelectorQuery().in(this).select('.uni-recycle-view-item').boundingClientRect().exec((ret) => {
this.setCachedSize(this.item, (ret[0] as NodeInfo).height!) this.setCachedSize(this.item, (ret[0] as NodeInfo).height!)
}) })
} }
} }
}
}
</script> </script>
<style> <style>
.uni-recycle-view-item {
box-sizing: border-box;
overflow: hidden;
}
</style> </style>
<template> <template>
<scroll-view class="uni-recycle-view-main" v-bind="$attrs" ref="scroll" @scroll="onScroll"> <scroll-view class="uni-recycle-view-main"
<view :style="{ height: placeholderHeight + 'px' }"> ref="scroll"
<view :style="{ top: containerTop + 'px' }"> :type="type"
:direction="direction"
:associative-container="associativeContainer"
:enable-back-to-top="enableBackToTop"
:bounces="bounces"
:upper-threshold="upperThreshold"
:lower-threshold="lowerThreshold"
:scroll-top="scrollTop"
:scroll-left="scrollLeft"
:scroll-into-view="scrollIntoView"
:scroll-with-animation="scrollWithAnimation"
:refresher-enabled="refresherEnabled"
:refresher-threshold="refresherThreshold"
:refresher-max-drag-distance="refresherMaxDragDistance"
:refresher-default-style="refresherDefaultStyle"
:refresher-background="refresherBackground"
:refresher-triggered="refresherTriggered"
:show-scrollbar="showScrollbar"
:custom-nested-scroll="customNestedScroll"
:nested-scroll-child="nestedScrollChild"
@scroll="onScroll"
@scrollend="onScrollEnd"
@scrolltolower="onScrollToLower"
@scrolltoupper="onScrollToUpper"
@refresherabort="onRefresherAbort"
@refresherpulling="onRefresherPulling"
@refresherrefresh="onRefresherRefresh"
@refresherrestore="onRefresherRestore"
>
<view
:style="{ height: placeholderHeight + 'px' }"
class="uni-recycle-view-placeholder"
>
<view
:style="{ top: containerTop + 'px' }"
class="uni-recycle-view-container"
>
<slot :items="items"></slot> <slot :items="items"></slot>
</view> </view>
</view> </view>
...@@ -24,11 +60,104 @@ ...@@ -24,11 +60,104 @@
export default { export default {
name: "uni-recycle-view", name: "uni-recycle-view",
props: { props: {
type: {
type: String,
default: ''
},
direction: {
type: String,
default: 'vertical'
},
associativeContainer: {
type: String,
default: ''
},
enableBackToTop: {
type: Boolean,
default: false
},
bounces: {
type: Boolean,
default: true
},
upperThreshold: {
type: Number,
default: 50
},
lowerThreshold: {
type: Number,
default: 50
},
scrollTop: {
type: Number,
default: 0
},
scrollLeft: {
type: Number,
default: 0
},
scrollIntoView: {
type: String,
default: ''
},
scrollWithAnimation: {
type: Boolean,
default: false
},
refresherEnabled: {
type: Boolean,
default: false
},
refresherThreshold: {
type: Number,
default: 45
},
refresherMaxDragDistance: {
type: Number
},
refresherDefaultStyle: {
type: String,
default: 'black'
},
refresherBackground: {
type: String,
default: 'transparent'
},
refresherTriggered: {
type: Boolean,
default: false
},
showScrollbar: {
type: Boolean,
default: true
},
customNestedScroll: {
type: Boolean,
default: false
},
nestedScrollChild: {
type: String,
default: ''
},
list: { list: {
type: Array as PropType<any[]>, type: Array as PropType<any[]>,
default: [] as any[] default: [] as any[]
},
itemHeight: {
type: Number,
default: 0
} }
}, },
emits: [
'scroll',
'scrollend',
'scrolltolower',
'scrolltoupper',
'refresherabort',
'refresherpulling',
'refresherrefresh',
'refresherrestore',
],
watch: { watch: {
list: { list: {
handler(list : any[]) { handler(list : any[]) {
...@@ -61,16 +190,26 @@ ...@@ -61,16 +190,26 @@
}, },
provide() { provide() {
return { return {
itemHeight: this.itemHeight,
setCachedSize: (item : any, size : number) => { setCachedSize: (item : any, size : number) => {
if(this.itemHeight != 0) {
return
}
if (!this.hasDefaultSize) { if (!this.hasDefaultSize) {
this.defaultItemSize = size this.defaultItemSize = size
this.hasDefaultSize = true this.hasDefaultSize = true
} }
this.cachedSize.set(item, size) this.cachedSize.set(item, size)
},
getCachedSize: (item : any) => {
return this.cachedSize.get(item)
} }
} }
}, },
created() { created() {
if(this.itemHeight != 0) {
this.defaultItemSize = this.itemHeight!
}
this.placeholderHeight = this.list.length * this.defaultItemSize this.placeholderHeight = this.list.length * this.defaultItemSize
}, },
mounted() { mounted() {
...@@ -83,7 +222,29 @@ ...@@ -83,7 +222,29 @@
}) })
}, },
methods: { methods: {
onScrollEnd(e: UniScrollEvent) {
this.$emit('scrollend', e)
},
onScrollToLower(e: UniScrollToLowerEvent) {
this.$emit('scrolltolower', e)
},
onScrollToUpper(e: UniScrollToUpperEvent) {
this.$emit('scrolltoupper', e)
},
onRefresherAbort(e: UniRefresherEvent) {
this.$emit('refresherabort', e)
},
onRefresherPulling(e: UniRefresherEvent) {
this.$emit('refresherpulling', e)
},
onRefresherRefresh(e: UniRefresherEvent) {
this.$emit('refresherrefresh', e)
},
onRefresherRestore(e: UniRefresherEvent) {
this.$emit('refresherrestore', e)
},
onScroll(e : UniScrollEvent) { onScroll(e : UniScrollEvent) {
this.$emit('scroll', e)
if (!this.initialized) { if (!this.initialized) {
return return
} }
...@@ -99,13 +260,12 @@ ...@@ -99,13 +260,12 @@
queue(scrollTop : number) { queue(scrollTop : number) {
/* /*
* rearrange内为大量同步逻辑,在上次rearrange未执行完毕的情况下将后续多个rearrange合并成一次执行,即仅执行最后一次 * rearrange内为大量同步逻辑,在上次rearrange未执行完毕的情况下将后续多个rearrange合并成一次执行,即仅执行最后一次
* 由于滚动机制差异,此优化仅在web端才有意义。
* 如何测试:push后console.log(this.rearrangeQueue.length) 输出结果大于1时触发优化 * 如何测试:push后console.log(this.rearrangeQueue.length) 输出结果大于1时触发优化
*/ */
this.rearrangeQueue.push(scrollTop) this.rearrangeQueue.push(scrollTop)
setTimeout(() => { setTimeout(() => {
this.flush() this.flush()
}, 1) }, 50)
}, },
flush() { flush() {
const queueLength = this.rearrangeQueue.length const queueLength = this.rearrangeQueue.length
...@@ -163,5 +323,12 @@ ...@@ -163,5 +323,12 @@
</script> </script>
<style> <style>
.uni-recycle-view-placeholder {
position: relative;
overflow: hidden;
}
.uni-recycle-view-container {
position: absolute;
width: 100%;
}
</style> </style>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册