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

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

上级 e71e5c8f
......@@ -5,7 +5,8 @@
此示例中仅渲染滚动容器上下5屏的内容。适用于仅使用一个for循环创建所有列表项的场景。文档详见插件市场:https://ext.dcloud.net.cn/plugin?id=17385</view>
<uni-recycle-view style="flex: 1;" :list="list" @scrolltoupper="scrolltoupper" @scroll="scroll">
<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="name"><text style="font-size: 14px;">{{item.name}}</text></view>
<view class="info"><text style="font-size: 12px; color: #999999;">{{item.info}}</text></view>
......
<template>
<view class="item-container">
<slot></slot>
</view>
</template>
<script>
/**
* recycle-item 长列表子项组件
* @description 用于展示超长列表数据每一项
* @property {any[]} item 当前组件渲染的列表项
*/
export default {
name: "uni-recycle-item",
props: {
item: {
type: Object as PropType<any>,
required: true
}
},
inject: {
setCachedSize: {
type: Function as PropType<(item : any, size : number) => void>
},
},
mounted() {
uni.createSelectorQuery().in(this).select('.item-container').boundingClientRect().exec((ret) => {
this.setCachedSize(this.item, (ret[0] as NodeInfo).height!)
})
}
}
</script>
<style>
<template>
<view class="uni-recycle-view-item" :style="this.itemHeight != 0 ? {height: this.itemHeight + 'px'} : {}">
<slot></slot>
</view>
</template>
<script>
/**
* recycle-item 长列表子项组件
* @description 用于展示超长列表数据每一项
* @property {any[]} item 当前组件渲染的列表项
*/
export default {
name: "uni-recycle-item",
props: {
item: {
type: Object as PropType<any>,
required: true
}
},
inject: {
itemHeight: {
type: Number as PropType<number>
},
setCachedSize: {
type: Function as PropType<(item : any, size : number) => void>
},
getCachedSize: {
type: Function as PropType<(item : any) => number | null>
},
},
mounted() {
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!)
})
}
}
}
}
</script>
<style>
.uni-recycle-view-item {
box-sizing: border-box;
overflow: hidden;
}
</style>
<template>
<scroll-view class="uni-recycle-view-main" v-bind="$attrs" ref="scroll" @scroll="onScroll">
<view :style="{ height: placeholderHeight + 'px' }">
<view :style="{ top: containerTop + 'px' }">
<scroll-view class="uni-recycle-view-main"
ref="scroll"
: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>
</view>
</view>
......@@ -24,11 +60,104 @@
export default {
name: "uni-recycle-view",
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: {
type: Array as PropType<any[]>,
default: [] as any[]
},
itemHeight: {
type: Number,
default: 0
}
},
emits: [
'scroll',
'scrollend',
'scrolltolower',
'scrolltoupper',
'refresherabort',
'refresherpulling',
'refresherrefresh',
'refresherrestore',
],
watch: {
list: {
handler(list : any[]) {
......@@ -61,16 +190,26 @@
},
provide() {
return {
itemHeight: this.itemHeight,
setCachedSize: (item : any, size : number) => {
if(this.itemHeight != 0) {
return
}
if (!this.hasDefaultSize) {
this.defaultItemSize = size
this.hasDefaultSize = true
}
this.cachedSize.set(item, size)
},
getCachedSize: (item : any) => {
return this.cachedSize.get(item)
}
}
},
created() {
if(this.itemHeight != 0) {
this.defaultItemSize = this.itemHeight!
}
this.placeholderHeight = this.list.length * this.defaultItemSize
},
mounted() {
......@@ -83,7 +222,29 @@
})
},
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) {
this.$emit('scroll', e)
if (!this.initialized) {
return
}
......@@ -99,13 +260,12 @@
queue(scrollTop : number) {
/*
* rearrange内为大量同步逻辑,在上次rearrange未执行完毕的情况下将后续多个rearrange合并成一次执行,即仅执行最后一次
* 由于滚动机制差异,此优化仅在web端才有意义。
* 如何测试:push后console.log(this.rearrangeQueue.length) 输出结果大于1时触发优化
*/
this.rearrangeQueue.push(scrollTop)
setTimeout(() => {
this.flush()
}, 1)
}, 50)
},
flush() {
const queueLength = this.rearrangeQueue.length
......@@ -163,5 +323,12 @@
</script>
<style>
.uni-recycle-view-placeholder {
position: relative;
overflow: hidden;
}
.uni-recycle-view-container {
position: absolute;
width: 100%;
}
</style>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册