uview-plus 3.4.69 → 3.4.71
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.md +10 -0
- package/components/u-index-list/u-index-list.vue +1 -1
- package/components/u-pull-refresh/u-pull-refresh.vue +4 -0
- package/components/u-qrcode/u-qrcode.vue +1 -1
- package/components/u-refresh-virtual-list/u-refresh-virtual-list.vue +85 -0
- package/components/u-virtual-list/u-virtual-list.vue +186 -0
- package/package.json +1 -1
package/changelog.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
## 3.4.71(2025-08-05)
|
|
2
|
+
feat: 新增virtual-list虚拟列表组件
|
|
3
|
+
|
|
4
|
+
feat: 新增pull-refresh下拉刷新结合虚拟列表使用
|
|
5
|
+
|
|
6
|
+
## 3.4.70(2025-08-05)
|
|
7
|
+
fix: 修复qrcode组件长按事件传入错误cid导致的报错
|
|
8
|
+
|
|
9
|
+
fix: 修复index-list组件key为undefined导致的索引报错消失
|
|
10
|
+
|
|
1
11
|
## 3.4.69(2025-08-04)
|
|
2
12
|
feat: pull-refresh下拉刷新新增上拉加载特性
|
|
3
13
|
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
width: addUnit(indicatorHeight)
|
|
88
88
|
}"
|
|
89
89
|
>
|
|
90
|
-
<text class="u-index-list__indicator__text">{{ uIndexList[activeIndex]
|
|
90
|
+
<text class="u-index-list__indicator__text">{{ uIndexList[activeIndex]?.key || uIndexList[activeIndex] }}</text>
|
|
91
91
|
</view>
|
|
92
92
|
</u-transition>
|
|
93
93
|
</view>
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<u-pull-refresh
|
|
3
|
+
:refreshing="refreshing"
|
|
4
|
+
:threshold="50"
|
|
5
|
+
@refresh="handleRefresh"
|
|
6
|
+
>
|
|
7
|
+
<u-virtual-list
|
|
8
|
+
ref="virtualList"
|
|
9
|
+
:list-data="listData"
|
|
10
|
+
:item-height="itemHeight"
|
|
11
|
+
:height="height"
|
|
12
|
+
:buffer="buffer"
|
|
13
|
+
:key-field="keyField"
|
|
14
|
+
:scroll-top="scrollTop"
|
|
15
|
+
@scroll="handleScroll"
|
|
16
|
+
>
|
|
17
|
+
<template #default="{ item, index }">
|
|
18
|
+
<slot :item="item" :index="index"></slot>
|
|
19
|
+
</template>
|
|
20
|
+
</u-virtual-list>
|
|
21
|
+
</u-pull-refresh>
|
|
22
|
+
</template>
|
|
23
|
+
|
|
24
|
+
<script>
|
|
25
|
+
|
|
26
|
+
export default {
|
|
27
|
+
name: 'u-refresh-virtual-list',
|
|
28
|
+
props: {
|
|
29
|
+
// 数据源
|
|
30
|
+
listData: {
|
|
31
|
+
type: Array,
|
|
32
|
+
default: () => []
|
|
33
|
+
},
|
|
34
|
+
// 每项高度(固定高度模式)
|
|
35
|
+
itemHeight: {
|
|
36
|
+
type: Number,
|
|
37
|
+
default: 50
|
|
38
|
+
},
|
|
39
|
+
// 容器高度
|
|
40
|
+
height: {
|
|
41
|
+
type: [String, Number],
|
|
42
|
+
default: '100%'
|
|
43
|
+
},
|
|
44
|
+
// 缓冲区项数
|
|
45
|
+
buffer: {
|
|
46
|
+
type: Number,
|
|
47
|
+
default: 4
|
|
48
|
+
},
|
|
49
|
+
// 索引键名
|
|
50
|
+
keyField: {
|
|
51
|
+
type: String,
|
|
52
|
+
default: 'id'
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
data() {
|
|
56
|
+
return {
|
|
57
|
+
refreshing: false,
|
|
58
|
+
scrollTop: 0
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
methods: {
|
|
62
|
+
handleRefresh() {
|
|
63
|
+
this.refreshing = true
|
|
64
|
+
this.$emit('refresh')
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
handleScroll(scrollTop) {
|
|
68
|
+
this.scrollTop = scrollTop
|
|
69
|
+
this.$emit('scroll', scrollTop)
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
finishRefresh() {
|
|
73
|
+
this.refreshing = false
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
scrollTo(top) {
|
|
77
|
+
this.scrollTop = top
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
scrollToTop() {
|
|
81
|
+
this.scrollTo(0)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
</script>
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view class="u-virtual-list" :style="{ height: addUnit(height) }">
|
|
3
|
+
<scroll-view
|
|
4
|
+
class="virtual-scroll-container"
|
|
5
|
+
:scroll-y="true"
|
|
6
|
+
:scroll-top="scrollTop"
|
|
7
|
+
:style="{ height: '100%' }"
|
|
8
|
+
@scroll="handleScroll"
|
|
9
|
+
touchmove.stop.prevent="handleTouchMove"
|
|
10
|
+
>
|
|
11
|
+
<view class="scroll-content">
|
|
12
|
+
<!-- 顶部占位 -->
|
|
13
|
+
<view :style="{ height: topPlaceholderHeight + 'px' }"></view>
|
|
14
|
+
|
|
15
|
+
<!-- 可见项 -->
|
|
16
|
+
<view
|
|
17
|
+
v-for="item in visibleItems"
|
|
18
|
+
:key="getItemKey(item)"
|
|
19
|
+
class="list-item"
|
|
20
|
+
:style="{ height: itemHeight + 'px' }"
|
|
21
|
+
>
|
|
22
|
+
<slot :item="item" :index="item._virtualIndex"></slot>
|
|
23
|
+
</view>
|
|
24
|
+
|
|
25
|
+
<!-- 底部占位 -->
|
|
26
|
+
<view :style="{ height: bottomPlaceholderHeight + 'px' }"></view>
|
|
27
|
+
</view>
|
|
28
|
+
</scroll-view>
|
|
29
|
+
</view>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<script>
|
|
33
|
+
import { addUnit } from '../../libs/function/index.js'
|
|
34
|
+
|
|
35
|
+
export default {
|
|
36
|
+
name: 'u-virtual-list',
|
|
37
|
+
props: {
|
|
38
|
+
// 数据源
|
|
39
|
+
listData: {
|
|
40
|
+
type: Array,
|
|
41
|
+
default: () => []
|
|
42
|
+
},
|
|
43
|
+
// 每项高度(固定高度模式)
|
|
44
|
+
itemHeight: {
|
|
45
|
+
type: Number,
|
|
46
|
+
default: 50
|
|
47
|
+
},
|
|
48
|
+
// 容器高度
|
|
49
|
+
height: {
|
|
50
|
+
type: [String, Number],
|
|
51
|
+
default: '100%'
|
|
52
|
+
},
|
|
53
|
+
// 缓冲区项数
|
|
54
|
+
buffer: {
|
|
55
|
+
type: Number,
|
|
56
|
+
default: 4
|
|
57
|
+
},
|
|
58
|
+
// 索引键名
|
|
59
|
+
keyField: {
|
|
60
|
+
type: String,
|
|
61
|
+
default: 'id'
|
|
62
|
+
},
|
|
63
|
+
// 当前滚动位置
|
|
64
|
+
scrollTop: {
|
|
65
|
+
type: Number,
|
|
66
|
+
default: 0
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
data() {
|
|
70
|
+
return {
|
|
71
|
+
// 起始索引
|
|
72
|
+
startIndex: 0,
|
|
73
|
+
// 容器实际高度
|
|
74
|
+
containerHeight: 0
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
computed: {
|
|
78
|
+
// 可视区域显示的项数(根据容器实际高度自动计算)
|
|
79
|
+
remain() {
|
|
80
|
+
if (this.containerHeight <= 0) {
|
|
81
|
+
// 默认值,防止除以0
|
|
82
|
+
return Math.ceil(500 / this.itemHeight) || 10
|
|
83
|
+
}
|
|
84
|
+
return Math.ceil(this.containerHeight / this.itemHeight)
|
|
85
|
+
},
|
|
86
|
+
// 可视项数量
|
|
87
|
+
visibleCount() {
|
|
88
|
+
return this.remain + this.buffer
|
|
89
|
+
},
|
|
90
|
+
// 可视项
|
|
91
|
+
visibleItems() {
|
|
92
|
+
const start = Math.max(0, this.startIndex - Math.floor(this.buffer / 2))
|
|
93
|
+
const end = Math.min(this.listData.length, start + this.visibleCount)
|
|
94
|
+
|
|
95
|
+
return this.listData.slice(start, end).map((item, index) => {
|
|
96
|
+
return {
|
|
97
|
+
...item,
|
|
98
|
+
_virtualIndex: start + index
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
},
|
|
102
|
+
// 顶部占位高度
|
|
103
|
+
topPlaceholderHeight() {
|
|
104
|
+
const start = Math.max(0, this.startIndex - Math.floor(this.buffer / 2))
|
|
105
|
+
return start * this.itemHeight
|
|
106
|
+
},
|
|
107
|
+
// 底部占位高度
|
|
108
|
+
bottomPlaceholderHeight() {
|
|
109
|
+
const start = Math.max(0, this.startIndex - Math.floor(this.buffer / 2))
|
|
110
|
+
const end = Math.min(this.listData.length, start + this.visibleCount)
|
|
111
|
+
return (this.listData.length - end) * this.itemHeight
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
watch: {
|
|
115
|
+
listData: {
|
|
116
|
+
handler() {
|
|
117
|
+
this.updateVisibleItems()
|
|
118
|
+
},
|
|
119
|
+
immediate: true
|
|
120
|
+
},
|
|
121
|
+
scrollTop: {
|
|
122
|
+
handler(newVal) {
|
|
123
|
+
this.updateVisibleItems()
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
mounted() {
|
|
128
|
+
this.measureContainerHeight()
|
|
129
|
+
},
|
|
130
|
+
methods: {
|
|
131
|
+
addUnit,
|
|
132
|
+
|
|
133
|
+
// 测量容器高度
|
|
134
|
+
measureContainerHeight() {
|
|
135
|
+
const height = this.height
|
|
136
|
+
if (typeof height === 'number') {
|
|
137
|
+
this.containerHeight = height
|
|
138
|
+
return
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (typeof height === 'string') {
|
|
142
|
+
if (height.includes('px')) {
|
|
143
|
+
this.containerHeight = parseInt(height)
|
|
144
|
+
} else if (height.includes('%')) {
|
|
145
|
+
// 对于百分比高度,使用默认值或根据父容器计算
|
|
146
|
+
this.containerHeight = 500
|
|
147
|
+
} else {
|
|
148
|
+
const num = parseInt(height)
|
|
149
|
+
this.containerHeight = isNaN(num) ? 500 : num
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
this.containerHeight = 500
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
getItemKey(item) {
|
|
157
|
+
return item[this.keyField] !== undefined ? item[this.keyField] : item._virtualIndex
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
// 更新可视项
|
|
161
|
+
updateVisibleItems() {
|
|
162
|
+
const index = Math.floor(this.scrollTop / this.itemHeight)
|
|
163
|
+
this.startIndex = Math.max(0, index)
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
// 处理滚动
|
|
167
|
+
handleScroll(e) {
|
|
168
|
+
const scrollTop = e.detail.scrollTop
|
|
169
|
+
this.$emit('scroll', scrollTop)
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
// 处理触摸移动,阻止事件冒泡
|
|
173
|
+
handleTouchMove(e) {
|
|
174
|
+
// 阻止触摸移动事件冒泡到父级,防止触发页面滚动
|
|
175
|
+
e.stopPropagation()
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
// 获取可见项范围
|
|
179
|
+
getVisibleRange() {
|
|
180
|
+
const start = Math.max(0, this.startIndex - Math.floor(this.buffer / 2))
|
|
181
|
+
const end = Math.min(this.listData.length, start + this.visibleCount)
|
|
182
|
+
return { start, end }
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
</script>
|
package/package.json
CHANGED