zx-infinite-scroll 1.0.1 → 1.0.2
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/README.md +290 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -84,34 +84,83 @@ app.mount('#app');
|
|
|
84
84
|
|
|
85
85
|
| 属性 | 类型 | 默认值 | 说明 |
|
|
86
86
|
|------|------|--------|------|
|
|
87
|
-
| fetchFn | `(params: FetchParams) => Promise<FetchResult<T>>` | - |
|
|
88
|
-
| params | `Record<string, any>` | `{}` |
|
|
87
|
+
| fetchFn | `(params: FetchParams) => Promise<FetchResult<T>>` | - | 数据请求函数(必填),需返回 `{ records: T[], total: number }` |
|
|
88
|
+
| params | `Record<string, any>` | `{}` | 查询参数(如筛选条件),变化时自动重新加载 |
|
|
89
89
|
| pageSize | `number` | `10` | 每页条数 |
|
|
90
90
|
| autoReload | `boolean` | `true` | params 变化时是否自动重新加载 |
|
|
91
91
|
| immediate | `boolean` | `true` | 是否在挂载时自动加载首页 |
|
|
92
92
|
| pullRefresh | `boolean` | `false` | 是否启用下拉刷新 |
|
|
93
93
|
| pullThreshold | `number` | `70` | 下拉刷新触发距离(px) |
|
|
94
|
-
| loadThreshold | `number` | `50` |
|
|
94
|
+
| loadThreshold | `number` | `50` | 上拉加载触发距离(距离底部 px) |
|
|
95
|
+
| emptyText | `string` | `'暂无数据'` | 空状态文案 |
|
|
96
|
+
| pullingText | `string` | `'下拉刷新'` | 下拉中的文案 |
|
|
97
|
+
| loosingText | `string` | `'释放即可刷新'` | 释放刷新的文案 |
|
|
98
|
+
| refreshingText | `string` | `'加载中...'` | 刷新中的文案 |
|
|
99
|
+
| loadingText | `string` | `'加载中...'` | 加载中的文案 |
|
|
100
|
+
| finishedText | `string` | `'没有更多了~'` | 加载完成的文案 |
|
|
101
|
+
| errorText | `string` | `'加载失败,点击重试'` | 加载失败的文案 |
|
|
102
|
+
|
|
103
|
+
#### FetchParams 类型
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
interface FetchParams {
|
|
107
|
+
page: number; // 当前页码,从 1 开始
|
|
108
|
+
pageSize: number; // 每页条数
|
|
109
|
+
[key: string]: any; // 其他自定义参数(从 params prop 传入)
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
#### FetchResult 类型
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
interface FetchResult<T> {
|
|
117
|
+
records: T[]; // 当前页数据列表
|
|
118
|
+
total: number; // 总条数
|
|
119
|
+
}
|
|
120
|
+
```
|
|
95
121
|
|
|
96
122
|
### InfiniteScrollV2 Events
|
|
97
123
|
|
|
98
124
|
| 事件 | 参数 | 说明 |
|
|
99
125
|
|------|------|------|
|
|
100
|
-
| success | `{ records: T[], total: number, reset: boolean }` |
|
|
101
|
-
| error | `err: unknown` |
|
|
126
|
+
| success | `{ records: T[], total: number, reset: boolean }` | 加载成功时触发,每次成功(含分页)都会触发 |
|
|
127
|
+
| error | `err: unknown` | 加载失败时触发 |
|
|
128
|
+
| update:list | `list: T[]` | 列表内容变化时触发(支持 v-model:list) |
|
|
102
129
|
|
|
103
130
|
### InfiniteScrollV2 Slots
|
|
104
131
|
|
|
105
132
|
| 插槽 | 参数 | 说明 |
|
|
106
133
|
|------|------|------|
|
|
107
|
-
| default | `{ list, loading, finished, isEmpty, error, total, reload }` |
|
|
134
|
+
| default | `{ list, loading, finished, isEmpty, error, total, reload }` | 列表内容插槽 |
|
|
135
|
+
|
|
136
|
+
#### Slot 参数说明
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
{
|
|
140
|
+
list: T[]; // 当前列表数据
|
|
141
|
+
loading: boolean; // 是否正在加载
|
|
142
|
+
finished: boolean; // 是否已加载完所有数据
|
|
143
|
+
isEmpty: boolean; // 是否为空数据
|
|
144
|
+
error: boolean; // 是否加载失败
|
|
145
|
+
total: number; // 总条数
|
|
146
|
+
reload: () => void; // 重新加载第一页的方法
|
|
147
|
+
}
|
|
148
|
+
```
|
|
108
149
|
|
|
109
150
|
### InfiniteScrollV2 Expose
|
|
110
151
|
|
|
111
|
-
| 方法 | 说明 |
|
|
112
|
-
|
|
113
|
-
| reload() | 重新加载第一页 |
|
|
114
|
-
| refresh() | 同 reload |
|
|
152
|
+
| 方法 | 类型 | 说明 |
|
|
153
|
+
|------|------|------|
|
|
154
|
+
| reload() | `() => Promise<void>` | 重新加载第一页 |
|
|
155
|
+
| refresh() | `() => Promise<void>` | 同 reload(别名) |
|
|
156
|
+
| list | `Ref<T[]>` | 当前列表数据(响应式) |
|
|
157
|
+
| loading | `Ref<boolean>` | 加载中状态(响应式) |
|
|
158
|
+
| finished | `Ref<boolean>` | 是否已加载完(响应式) |
|
|
159
|
+
| isEmpty | `Ref<boolean>` | 是否为空数据(响应式) |
|
|
160
|
+
| total | `Ref<number>` | 总条数(响应式) |
|
|
161
|
+
| finishLoad() | `() => void` | 完成上拉加载(透传 v1 方法) |
|
|
162
|
+
| finishRefresh() | `() => void` | 完成下拉刷新(透传 v1 方法) |
|
|
163
|
+
| checkContentHeight() | `() => void` | 检查内容高度(透传 v1 方法) |
|
|
115
164
|
|
|
116
165
|
## InfiniteScroll(基础组件)
|
|
117
166
|
|
|
@@ -151,6 +200,237 @@ const onRefresh = async () => {
|
|
|
151
200
|
</template>
|
|
152
201
|
```
|
|
153
202
|
|
|
203
|
+
### InfiniteScroll Props
|
|
204
|
+
|
|
205
|
+
| 属性 | 类型 | 默认值 | 说明 |
|
|
206
|
+
|------|------|--------|------|
|
|
207
|
+
| loading | `boolean` | `false` | 是否处于加载中状态 |
|
|
208
|
+
| finished | `boolean` | `false` | 是否已加载完所有数据 |
|
|
209
|
+
| isEmpty | `boolean` | `false` | 是否显示空状态 |
|
|
210
|
+
| emptyText | `string` | `'暂无数据'` | 空状态文案 |
|
|
211
|
+
| pullRefresh | `boolean` | `false` | 是否启用下拉刷新 |
|
|
212
|
+
| pullThreshold | `number` | `70` | 下拉刷新触发距离(px) |
|
|
213
|
+
| loadThreshold | `number` | `50` | 上拉加载触发距离(距离底部 px) |
|
|
214
|
+
| pullingText | `string` | `'下拉刷新'` | 下拉中的文案 |
|
|
215
|
+
| loosingText | `string` | `'释放即可刷新'` | 释放刷新的文案 |
|
|
216
|
+
| refreshingText | `string` | `'加载中...'` | 刷新中的文案 |
|
|
217
|
+
| loadingText | `string` | `'加载中...'` | 加载中的文案 |
|
|
218
|
+
| finishedText | `string` | `'没有更多了~'` | 加载完成的文案 |
|
|
219
|
+
| errorText | `string` | `'加载失败,点击重试'` | 加载失败的文案 |
|
|
220
|
+
| error | `boolean` | `false` | 是否显示错误状态 |
|
|
221
|
+
| contentLoading | `boolean` | `false` | 内容区域是否显示加载状态(用于下拉刷新时的遮罩) |
|
|
222
|
+
|
|
223
|
+
### InfiniteScroll Events
|
|
224
|
+
|
|
225
|
+
| 事件 | 参数 | 说明 |
|
|
226
|
+
|------|------|------|
|
|
227
|
+
| load | - | 触发上拉加载时触发 |
|
|
228
|
+
| refresh | - | 触发下拉刷新时触发 |
|
|
229
|
+
| retry | - | 点击错误重试时触发 |
|
|
230
|
+
|
|
231
|
+
### InfiniteScroll Expose
|
|
232
|
+
|
|
233
|
+
| 方法 | 类型 | 说明 |
|
|
234
|
+
|------|------|------|
|
|
235
|
+
| finishRefresh() | `() => void` | 完成下拉刷新,调用后收起刷新指示器 |
|
|
236
|
+
| finishPullDown() | `() => void` | 同 finishRefresh(别名) |
|
|
237
|
+
| finishLoad() | `() => void` | 完成上拉加载 |
|
|
238
|
+
| finishPullUp() | `() => void` | 同 finishLoad(别名) |
|
|
239
|
+
| checkContentHeight() | `() => void` | 检查内容高度,不足一屏时自动触发加载 |
|
|
240
|
+
|
|
241
|
+
### InfiniteScroll Slots
|
|
242
|
+
|
|
243
|
+
| 插槽 | 说明 |
|
|
244
|
+
|------|------|
|
|
245
|
+
| default | 列表内容 |
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## 完整使用示例
|
|
250
|
+
|
|
251
|
+
### 示例 1:基础列表
|
|
252
|
+
|
|
253
|
+
```vue
|
|
254
|
+
<script setup lang="ts">
|
|
255
|
+
import { InfiniteScrollV2 } from 'zx-infinite-scroll';
|
|
256
|
+
import 'zx-infinite-scroll/dist/style.css';
|
|
257
|
+
|
|
258
|
+
interface Item {
|
|
259
|
+
id: number;
|
|
260
|
+
name: string;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const fetchData = async ({ page, pageSize }) => {
|
|
264
|
+
const res = await fetch(`/api/list?page=${page}&pageSize=${pageSize}`);
|
|
265
|
+
const data = await res.json();
|
|
266
|
+
return {
|
|
267
|
+
records: data.list,
|
|
268
|
+
total: data.total
|
|
269
|
+
};
|
|
270
|
+
};
|
|
271
|
+
</script>
|
|
272
|
+
|
|
273
|
+
<template>
|
|
274
|
+
<InfiniteScrollV2 :fetch-fn="fetchData">
|
|
275
|
+
<template #default="{ list }">
|
|
276
|
+
<div v-for="item in list" :key="item.id" class="item">
|
|
277
|
+
{{ item.name }}
|
|
278
|
+
</div>
|
|
279
|
+
</template>
|
|
280
|
+
</InfiniteScrollV2>
|
|
281
|
+
</template>
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### 示例 2:带下拉刷新和筛选参数
|
|
285
|
+
|
|
286
|
+
```vue
|
|
287
|
+
<script setup lang="ts">
|
|
288
|
+
import { ref } from 'vue';
|
|
289
|
+
import { InfiniteScrollV2 } from 'zx-infinite-scroll';
|
|
290
|
+
import 'zx-infinite-scroll/dist/style.css';
|
|
291
|
+
|
|
292
|
+
const keyword = ref('');
|
|
293
|
+
const category = ref('');
|
|
294
|
+
|
|
295
|
+
const fetchData = async ({ page, pageSize, keyword, category }) => {
|
|
296
|
+
const res = await fetch(
|
|
297
|
+
`/api/list?page=${page}&pageSize=${pageSize}&keyword=${keyword}&category=${category}`
|
|
298
|
+
);
|
|
299
|
+
return await res.json();
|
|
300
|
+
};
|
|
301
|
+
</script>
|
|
302
|
+
|
|
303
|
+
<template>
|
|
304
|
+
<input v-model="keyword" placeholder="搜索关键词" />
|
|
305
|
+
<select v-model="category">
|
|
306
|
+
<option value="">全部分类</option>
|
|
307
|
+
<option value="1">分类1</option>
|
|
308
|
+
<option value="2">分类2</option>
|
|
309
|
+
</select>
|
|
310
|
+
|
|
311
|
+
<InfiniteScrollV2
|
|
312
|
+
:fetch-fn="fetchData"
|
|
313
|
+
:params="{ keyword, category }"
|
|
314
|
+
:pull-refresh="true"
|
|
315
|
+
:page-size="20"
|
|
316
|
+
>
|
|
317
|
+
<template #default="{ list, loading, reload }">
|
|
318
|
+
<div v-for="item in list" :key="item.id" class="item">
|
|
319
|
+
{{ item.name }}
|
|
320
|
+
</div>
|
|
321
|
+
<button v-if="!loading" @click="reload">手动刷新</button>
|
|
322
|
+
</template>
|
|
323
|
+
</InfiniteScrollV2>
|
|
324
|
+
</template>
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### 示例 3:监听事件
|
|
328
|
+
|
|
329
|
+
```vue
|
|
330
|
+
<script setup lang="ts">
|
|
331
|
+
import { InfiniteScrollV2 } from 'zx-infinite-scroll';
|
|
332
|
+
import 'zx-infinite-scroll/dist/style.css';
|
|
333
|
+
|
|
334
|
+
const handleSuccess = ({ records, total, reset }) => {
|
|
335
|
+
console.log('加载成功', { records, total, reset });
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
const handleError = (err) => {
|
|
339
|
+
console.error('加载失败', err);
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
const fetchData = async ({ page, pageSize }) => {
|
|
343
|
+
// 模拟可能失败的请求
|
|
344
|
+
const res = await fetch(`/api/list?page=${page}&pageSize=${pageSize}`);
|
|
345
|
+
if (!res.ok) throw new Error('请求失败');
|
|
346
|
+
return await res.json();
|
|
347
|
+
};
|
|
348
|
+
</script>
|
|
349
|
+
|
|
350
|
+
<template>
|
|
351
|
+
<InfiniteScrollV2
|
|
352
|
+
:fetch-fn="fetchData"
|
|
353
|
+
@success="handleSuccess"
|
|
354
|
+
@error="handleError"
|
|
355
|
+
>
|
|
356
|
+
<template #default="{ list }">
|
|
357
|
+
<div v-for="item in list" :key="item.id">
|
|
358
|
+
{{ item.name }}
|
|
359
|
+
</div>
|
|
360
|
+
</template>
|
|
361
|
+
</InfiniteScrollV2>
|
|
362
|
+
</template>
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### 示例 4:使用基础组件(手动控制)
|
|
366
|
+
|
|
367
|
+
```vue
|
|
368
|
+
<script setup lang="ts">
|
|
369
|
+
import { ref } from 'vue';
|
|
370
|
+
import { InfiniteScroll } from 'zx-infinite-scroll';
|
|
371
|
+
import 'zx-infinite-scroll/dist/style.css';
|
|
372
|
+
|
|
373
|
+
const scrollRef = ref();
|
|
374
|
+
const list = ref([]);
|
|
375
|
+
const loading = ref(false);
|
|
376
|
+
const finished = ref(false);
|
|
377
|
+
const error = ref(false);
|
|
378
|
+
const page = ref(1);
|
|
379
|
+
const total = ref(0);
|
|
380
|
+
|
|
381
|
+
const loadData = async () => {
|
|
382
|
+
loading.value = true;
|
|
383
|
+
error.value = false;
|
|
384
|
+
try {
|
|
385
|
+
const res = await fetch(`/api/list?page=${page.value}&pageSize=10`);
|
|
386
|
+
const data = await res.json();
|
|
387
|
+
list.value.push(...data.records);
|
|
388
|
+
total.value = data.total;
|
|
389
|
+
finished.value = list.value.length >= total.value;
|
|
390
|
+
page.value++;
|
|
391
|
+
} catch (err) {
|
|
392
|
+
error.value = true;
|
|
393
|
+
} finally {
|
|
394
|
+
loading.value = false;
|
|
395
|
+
scrollRef.value?.finishLoad();
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
const refreshData = async () => {
|
|
400
|
+
page.value = 1;
|
|
401
|
+
list.value = [];
|
|
402
|
+
finished.value = false;
|
|
403
|
+
await loadData();
|
|
404
|
+
scrollRef.value?.finishRefresh();
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
const retryLoad = () => {
|
|
408
|
+
if (list.value.length === 0) {
|
|
409
|
+
refreshData();
|
|
410
|
+
} else {
|
|
411
|
+
loadData();
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
</script>
|
|
415
|
+
|
|
416
|
+
<template>
|
|
417
|
+
<InfiniteScroll
|
|
418
|
+
ref="scrollRef"
|
|
419
|
+
:loading="loading"
|
|
420
|
+
:finished="finished"
|
|
421
|
+
:error="error"
|
|
422
|
+
:pull-refresh="true"
|
|
423
|
+
@load="loadData"
|
|
424
|
+
@refresh="refreshData"
|
|
425
|
+
@retry="retryLoad"
|
|
426
|
+
>
|
|
427
|
+
<div v-for="item in list" :key="item.id" class="item">
|
|
428
|
+
{{ item.name }}
|
|
429
|
+
</div>
|
|
430
|
+
</InfiniteScroll>
|
|
431
|
+
</template>
|
|
432
|
+
```
|
|
433
|
+
|
|
154
434
|
## License
|
|
155
435
|
|
|
156
436
|
MIT
|