zx-infinite-scroll 1.0.7 → 1.0.9
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/dist/index.es.js +124 -124
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
package/dist/index.es.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { defineComponent as Y, openBlock as f, createElementBlock as p, normalizeClass as X, createElementVNode as $, toDisplayString as V, computed as
|
|
2
|
-
const
|
|
1
|
+
import { defineComponent as Y, openBlock as f, createElementBlock as p, normalizeClass as X, createElementVNode as $, toDisplayString as V, computed as re, normalizeStyle as P, renderSlot as K, createTextVNode as ge, createCommentVNode as D, ref as d, watch as j, onMounted as fe, nextTick as I, onBeforeUnmount as xe, withDirectives as ye, vShow as Te, createVNode as we, createBlock as U, withCtx as Ee } from "vue";
|
|
2
|
+
const Re = { class: "loading-content" }, Ce = { class: "loading-text" }, ke = /* @__PURE__ */ Y({
|
|
3
3
|
name: "RequestLoading",
|
|
4
4
|
__name: "request-loading",
|
|
5
5
|
props: {
|
|
@@ -10,9 +10,9 @@ const Ee = { class: "loading-content" }, Re = { class: "loading-text" }, Ce = /*
|
|
|
10
10
|
return (m, g) => (f(), p("div", {
|
|
11
11
|
class: X(["loading-container", { fullscreen: t.fullscreen }])
|
|
12
12
|
}, [
|
|
13
|
-
$("div",
|
|
13
|
+
$("div", Re, [
|
|
14
14
|
g[0] || (g[0] = $("span", { class: "loading-spinner" }, null, -1)),
|
|
15
|
-
$("span",
|
|
15
|
+
$("span", Ce, V(t.text), 1)
|
|
16
16
|
])
|
|
17
17
|
], 2));
|
|
18
18
|
}
|
|
@@ -21,7 +21,7 @@ const Ee = { class: "loading-content" }, Re = { class: "loading-text" }, Ce = /*
|
|
|
21
21
|
for (const [l, x] of m)
|
|
22
22
|
g[l] = x;
|
|
23
23
|
return g;
|
|
24
|
-
}, Z = /* @__PURE__ */ G(
|
|
24
|
+
}, Z = /* @__PURE__ */ G(ke, [["__scopeId", "data-v-a890d226"]]), Le = ["src"], be = {
|
|
25
25
|
key: 0,
|
|
26
26
|
class: "empty-text"
|
|
27
27
|
}, He = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='80' viewBox='0 0 96 80' fill='none'%3E%3Cpath d='M8 16C8 12.6863 10.6863 10 14 10H38L44 16H82C85.3137 16 88 18.6863 88 22V66C88 69.3137 85.3137 72 82 72H14C10.6863 72 8 69.3137 8 66V16Z' fill='%23E8E8E8'/%3E%3Cpath d='M8 20C8 18.3431 9.34315 17 11 17H85C86.6569 17 88 18.3431 88 20V66C88 69.3137 85.3137 72 82 72H14C10.6863 72 8 69.3137 8 66V20Z' fill='%23F5F5F5'/%3E%3Cpath d='M38 42C38 40.8954 38.8954 40 40 40H56C57.1046 40 58 40.8954 58 42V44C58 45.1046 57.1046 46 56 46H40C38.8954 46 38 45.1046 38 44V42Z' fill='%23D9D9D9'/%3E%3C/svg%3E", Se = /* @__PURE__ */ Y({
|
|
@@ -34,10 +34,10 @@ const Ee = { class: "loading-content" }, Re = { class: "loading-text" }, Ce = /*
|
|
|
34
34
|
emptyImage: { default: "" }
|
|
35
35
|
},
|
|
36
36
|
setup(t) {
|
|
37
|
-
const m = t, g =
|
|
37
|
+
const m = t, g = re(() => ({
|
|
38
38
|
paddingTop: typeof m.paddingTop == "number" ? `${m.paddingTop}px` : m.paddingTop
|
|
39
|
-
})), l =
|
|
40
|
-
return (x,
|
|
39
|
+
})), l = re(() => m.emptyImage || He);
|
|
40
|
+
return (x, i) => (f(), p("div", {
|
|
41
41
|
class: "empty-wrap",
|
|
42
42
|
style: P(g.value)
|
|
43
43
|
}, [
|
|
@@ -45,8 +45,8 @@ const Ee = { class: "loading-content" }, Re = { class: "loading-text" }, Ce = /*
|
|
|
45
45
|
class: "empty-image",
|
|
46
46
|
src: l.value,
|
|
47
47
|
alt: ""
|
|
48
|
-
}, null, 8,
|
|
49
|
-
t.showText ? (f(), p("p",
|
|
48
|
+
}, null, 8, Le),
|
|
49
|
+
t.showText ? (f(), p("p", be, [
|
|
50
50
|
K(x.$slots, "default", {}, () => [
|
|
51
51
|
ge(V(t.text), 1)
|
|
52
52
|
], !0)
|
|
@@ -65,7 +65,7 @@ const Ee = { class: "loading-content" }, Re = { class: "loading-text" }, Ce = /*
|
|
|
65
65
|
}, Ve = {
|
|
66
66
|
key: 1,
|
|
67
67
|
class: "finished-text"
|
|
68
|
-
},
|
|
68
|
+
}, ce = 8, $e = /* @__PURE__ */ Y({
|
|
69
69
|
name: "InfiniteScroll",
|
|
70
70
|
__name: "infinite-scroll",
|
|
71
71
|
props: {
|
|
@@ -87,43 +87,43 @@ const Ee = { class: "loading-content" }, Re = { class: "loading-text" }, Ce = /*
|
|
|
87
87
|
},
|
|
88
88
|
emits: ["refresh", "load", "retry"],
|
|
89
89
|
setup(t, { expose: m, emit: g }) {
|
|
90
|
-
const l = t, x = g,
|
|
91
|
-
let
|
|
92
|
-
function B(e,
|
|
93
|
-
!l.pullRefresh || v || (
|
|
90
|
+
const l = t, x = g, i = d(null), o = d(null), C = d(null), a = d("idle"), h = d(0), y = d(!1);
|
|
91
|
+
let E = 0, k = 0, T = 0, w = "none", v = !1, H = !1, S = !1, L = null, r = null, n = null, c = null, u = -1;
|
|
92
|
+
function B(e, s) {
|
|
93
|
+
!l.pullRefresh || v || (E = e, k = s, T = 0, w = "none", a.value = "idle");
|
|
94
94
|
}
|
|
95
|
-
function J(e,
|
|
96
|
-
if (!l.pullRefresh || v ||
|
|
97
|
-
const M = e -
|
|
98
|
-
if (
|
|
99
|
-
const z = Math.abs(M), O = Math.abs(
|
|
100
|
-
if (z >
|
|
101
|
-
|
|
95
|
+
function J(e, s, R) {
|
|
96
|
+
if (!l.pullRefresh || v || k === 0) return !1;
|
|
97
|
+
const M = e - E, b = s - k;
|
|
98
|
+
if (w === "none") {
|
|
99
|
+
const z = Math.abs(M), O = Math.abs(b);
|
|
100
|
+
if (z > ce || O > ce)
|
|
101
|
+
w = O > z * 1.5 ? "vertical" : "horizontal";
|
|
102
102
|
else
|
|
103
103
|
return !1;
|
|
104
104
|
}
|
|
105
|
-
if (
|
|
105
|
+
if (w === "horizontal") return !1;
|
|
106
106
|
const q = pe() <= 1;
|
|
107
|
-
if (!q &&
|
|
108
|
-
const z =
|
|
109
|
-
return !!(z && z.scrollHeight - z.scrollTop - z.clientHeight <= 1 &&
|
|
107
|
+
if (!q && b < 0) {
|
|
108
|
+
const z = i.value;
|
|
109
|
+
return !!(z && z.scrollHeight - z.scrollTop - z.clientHeight <= 1 && R);
|
|
110
110
|
}
|
|
111
|
-
return q ? (T = Math.max(0, Math.min(
|
|
112
|
-
|
|
113
|
-
})),
|
|
111
|
+
return q ? (T = Math.max(0, Math.min(b, 150)), y.value = !0, r === null && (r = requestAnimationFrame(() => {
|
|
112
|
+
r = null, h.value = T * 0.5, T === 0 ? a.value = "idle" : a.value = T > l.pullThreshold ? "loosing" : "pulling";
|
|
113
|
+
})), b > 0) : !1;
|
|
114
114
|
}
|
|
115
115
|
function Q() {
|
|
116
|
-
!l.pullRefresh || v || (
|
|
116
|
+
!l.pullRefresh || v || (r !== null && (cancelAnimationFrame(r), r = null), y.value = !1, T > l.pullThreshold ? (v = !0, a.value = "refreshing", h.value = 50, x("refresh")) : (h.value = 0, a.value = "idle"), oe());
|
|
117
117
|
}
|
|
118
118
|
function ve() {
|
|
119
|
-
!l.pullRefresh || v || (
|
|
119
|
+
!l.pullRefresh || v || (r !== null && (cancelAnimationFrame(r), r = null), y.value = !1, h.value = 0, a.value = "idle", oe());
|
|
120
120
|
}
|
|
121
121
|
function W(e) {
|
|
122
122
|
B(e.touches[0].clientX, e.touches[0].clientY);
|
|
123
123
|
}
|
|
124
124
|
function _(e) {
|
|
125
|
-
const
|
|
126
|
-
J(
|
|
125
|
+
const s = e.touches[0];
|
|
126
|
+
J(s.clientX, s.clientY, e.cancelable) && e.cancelable && e.preventDefault();
|
|
127
127
|
}
|
|
128
128
|
function ee() {
|
|
129
129
|
Q();
|
|
@@ -137,57 +137,57 @@ const Ee = { class: "loading-content" }, Re = { class: "loading-text" }, Ce = /*
|
|
|
137
137
|
function le(e) {
|
|
138
138
|
S && J(e.clientX, e.clientY, !0) && e.preventDefault();
|
|
139
139
|
}
|
|
140
|
-
function
|
|
140
|
+
function ie() {
|
|
141
141
|
S && (S = !1, Q());
|
|
142
142
|
}
|
|
143
|
-
function
|
|
144
|
-
|
|
143
|
+
function oe() {
|
|
144
|
+
E = 0, k = 0, T = 0, w = "none";
|
|
145
145
|
}
|
|
146
146
|
function A() {
|
|
147
|
-
l.loading || l.finished || l.error || H ||
|
|
147
|
+
l.loading || l.finished || l.error || H || L || (L = window.setTimeout(() => {
|
|
148
148
|
var q;
|
|
149
|
-
|
|
150
|
-
const e =
|
|
149
|
+
L = null;
|
|
150
|
+
const e = i.value;
|
|
151
151
|
if (!e) return;
|
|
152
|
-
const { scrollTop:
|
|
153
|
-
if (
|
|
154
|
-
if (
|
|
155
|
-
|
|
152
|
+
const { scrollTop: s, clientHeight: R, scrollHeight: M } = e, b = ((q = o.value) == null ? void 0 : q.clientHeight) || 0;
|
|
153
|
+
if (b <= R) {
|
|
154
|
+
if (u === b) return;
|
|
155
|
+
u = b, ae(!0);
|
|
156
156
|
return;
|
|
157
157
|
}
|
|
158
|
-
M -
|
|
158
|
+
M - s - R <= l.loadThreshold && ae(!1);
|
|
159
159
|
}, 100));
|
|
160
160
|
}
|
|
161
|
-
function
|
|
161
|
+
function ae(e = !1) {
|
|
162
162
|
H = !0, x("load"), I(() => {
|
|
163
|
-
var
|
|
164
|
-
const
|
|
165
|
-
|
|
163
|
+
var R;
|
|
164
|
+
const s = i.value;
|
|
165
|
+
s && (e ? s.scrollTop = s.scrollHeight : (R = C.value) == null || R.scrollIntoView({ block: "end", behavior: "smooth" }));
|
|
166
166
|
});
|
|
167
167
|
}
|
|
168
168
|
function pe() {
|
|
169
169
|
var e;
|
|
170
|
-
return ((e =
|
|
170
|
+
return ((e = i.value) == null ? void 0 : e.scrollTop) ?? 0;
|
|
171
171
|
}
|
|
172
172
|
function N() {
|
|
173
173
|
v = !1, h.value = 0, n !== null && clearTimeout(n), n = window.setTimeout(() => {
|
|
174
|
-
|
|
175
|
-
}, 250),
|
|
174
|
+
a.value = "idle", n = null;
|
|
175
|
+
}, 250), u = -1, I(() => {
|
|
176
176
|
F();
|
|
177
177
|
});
|
|
178
178
|
}
|
|
179
|
-
function
|
|
179
|
+
function se() {
|
|
180
180
|
H = !1, I(() => {
|
|
181
|
-
var
|
|
182
|
-
const e = ((
|
|
183
|
-
|
|
181
|
+
var s;
|
|
182
|
+
const e = ((s = o.value) == null ? void 0 : s.clientHeight) || 0;
|
|
183
|
+
u !== -1 && e === u || (u = -1, F());
|
|
184
184
|
});
|
|
185
185
|
}
|
|
186
186
|
function F() {
|
|
187
187
|
l.finished || l.loading || l.error || I(() => {
|
|
188
|
-
var
|
|
189
|
-
const e = ((
|
|
190
|
-
e <=
|
|
188
|
+
var R, M;
|
|
189
|
+
const e = ((R = o.value) == null ? void 0 : R.clientHeight) || 0, s = ((M = i.value) == null ? void 0 : M.clientHeight) || 0;
|
|
190
|
+
e <= s && !H && A();
|
|
191
191
|
});
|
|
192
192
|
}
|
|
193
193
|
function me() {
|
|
@@ -201,28 +201,28 @@ const Ee = { class: "loading-content" }, Re = { class: "loading-text" }, Ce = /*
|
|
|
201
201
|
), j(
|
|
202
202
|
() => l.finished,
|
|
203
203
|
(e) => {
|
|
204
|
-
e && (
|
|
204
|
+
e && (u = -1);
|
|
205
205
|
}
|
|
206
206
|
), fe(() => {
|
|
207
|
-
const e =
|
|
208
|
-
e && (l.pullRefresh && (e.addEventListener("touchstart", W, { passive: !0 }), e.addEventListener("touchmove", _, { passive: !1 }), e.addEventListener("touchend", ee, { passive: !0 }), e.addEventListener("touchcancel", te, { passive: !0 }), e.addEventListener("mousedown", ne), window.addEventListener("mousemove", le), window.addEventListener("mouseup",
|
|
207
|
+
const e = i.value;
|
|
208
|
+
e && (l.pullRefresh && (e.addEventListener("touchstart", W, { passive: !0 }), e.addEventListener("touchmove", _, { passive: !1 }), e.addEventListener("touchend", ee, { passive: !0 }), e.addEventListener("touchcancel", te, { passive: !0 }), e.addEventListener("mousedown", ne), window.addEventListener("mousemove", le), window.addEventListener("mouseup", ie)), e.addEventListener("scroll", A, { passive: !0 }), typeof ResizeObserver < "u" && (c = new ResizeObserver(() => {
|
|
209
209
|
F();
|
|
210
|
-
}),
|
|
210
|
+
}), c.observe(e), o.value && c.observe(o.value)), I(() => {
|
|
211
211
|
F();
|
|
212
212
|
}));
|
|
213
213
|
}), xe(() => {
|
|
214
|
-
const e =
|
|
215
|
-
e && (e.removeEventListener("touchstart", W), e.removeEventListener("touchmove", _), e.removeEventListener("touchend", ee), e.removeEventListener("touchcancel", te), e.removeEventListener("mousedown", ne), e.removeEventListener("scroll", A)), window.removeEventListener("mousemove", le), window.removeEventListener("mouseup",
|
|
214
|
+
const e = i.value;
|
|
215
|
+
e && (e.removeEventListener("touchstart", W), e.removeEventListener("touchmove", _), e.removeEventListener("touchend", ee), e.removeEventListener("touchcancel", te), e.removeEventListener("mousedown", ne), e.removeEventListener("scroll", A)), window.removeEventListener("mousemove", le), window.removeEventListener("mouseup", ie), c && (c.disconnect(), c = null), r !== null && (cancelAnimationFrame(r), r = null), L !== null && (clearTimeout(L), L = null), n !== null && (clearTimeout(n), n = null);
|
|
216
216
|
}), m({
|
|
217
217
|
refresh: N,
|
|
218
218
|
finishRefresh: N,
|
|
219
219
|
finishPullDown: N,
|
|
220
|
-
finishLoad:
|
|
221
|
-
finishPullUp:
|
|
220
|
+
finishLoad: se,
|
|
221
|
+
finishPullUp: se,
|
|
222
222
|
checkContentHeight: F
|
|
223
|
-
}), (e,
|
|
223
|
+
}), (e, s) => (f(), p("div", {
|
|
224
224
|
ref_key: "containerRef",
|
|
225
|
-
ref:
|
|
225
|
+
ref: i,
|
|
226
226
|
class: "infinite-scroll"
|
|
227
227
|
}, [
|
|
228
228
|
t.pullRefresh ? (f(), p("div", {
|
|
@@ -231,19 +231,19 @@ const Ee = { class: "loading-content" }, Re = { class: "loading-text" }, Ce = /*
|
|
|
231
231
|
style: P({ transform: `translateY(${h.value}px)` })
|
|
232
232
|
}, [
|
|
233
233
|
ye($("div", ze, [
|
|
234
|
-
|
|
234
|
+
a.value === "refreshing" ? (f(), p("span", Be)) : a.value === "loosing" ? (f(), p("span", Me, V(t.loosingText), 1)) : (f(), p("span", De, V(t.pullingText), 1))
|
|
235
235
|
], 512), [
|
|
236
|
-
[Te,
|
|
236
|
+
[Te, a.value !== "idle"]
|
|
237
237
|
])
|
|
238
238
|
], 6)) : D("", !0),
|
|
239
239
|
$("div", {
|
|
240
240
|
ref_key: "contentRef",
|
|
241
|
-
ref:
|
|
241
|
+
ref: o,
|
|
242
242
|
class: X(["infinite-scroll-content", { "no-transition": y.value }]),
|
|
243
243
|
style: P(t.pullRefresh ? { transform: `translateY(${h.value}px)` } : {})
|
|
244
244
|
}, [
|
|
245
245
|
t.contentLoading ? (f(), p("div", Ie, [
|
|
246
|
-
|
|
246
|
+
we(Z, { text: t.refreshingText }, null, 8, ["text"])
|
|
247
247
|
])) : D("", !0),
|
|
248
248
|
t.isEmpty && !t.loading ? (f(), U(de, {
|
|
249
249
|
key: 1,
|
|
@@ -253,10 +253,10 @@ const Ee = { class: "loading-content" }, Re = { class: "loading-text" }, Ce = /*
|
|
|
253
253
|
t.isEmpty ? D("", !0) : (f(), p("div", {
|
|
254
254
|
key: 2,
|
|
255
255
|
ref_key: "indicatorRef",
|
|
256
|
-
ref:
|
|
256
|
+
ref: C,
|
|
257
257
|
class: "load-more-indicator"
|
|
258
258
|
}, [
|
|
259
|
-
t.loading &&
|
|
259
|
+
t.loading && a.value !== "refreshing" ? (f(), U(Z, {
|
|
260
260
|
key: 0,
|
|
261
261
|
text: t.loadingText
|
|
262
262
|
}, null, 8, ["text"])) : t.finished ? (f(), p("span", Ve, V(t.finishedText), 1)) : t.error ? (f(), p("span", {
|
|
@@ -268,7 +268,7 @@ const Ee = { class: "loading-content" }, Re = { class: "loading-text" }, Ce = /*
|
|
|
268
268
|
], 6)
|
|
269
269
|
], 512));
|
|
270
270
|
}
|
|
271
|
-
}), he = /* @__PURE__ */ G($e, [["__scopeId", "data-v-
|
|
271
|
+
}), he = /* @__PURE__ */ G($e, [["__scopeId", "data-v-fc5e471c"]]), Fe = /* @__PURE__ */ Y({
|
|
272
272
|
name: "InfiniteScrollV2",
|
|
273
273
|
__name: "infinite-scroll-v2",
|
|
274
274
|
props: {
|
|
@@ -290,95 +290,95 @@ const Ee = { class: "loading-content" }, Re = { class: "loading-text" }, Ce = /*
|
|
|
290
290
|
},
|
|
291
291
|
emits: ["success", "error", "update:list"],
|
|
292
292
|
setup(t, { expose: m, emit: g }) {
|
|
293
|
-
const l = t, x = g,
|
|
294
|
-
let
|
|
293
|
+
const l = t, x = g, i = d(null), o = d([]), C = d(!1), a = d(!1), h = d(!1), y = d(!1), E = d(0), k = d(1), T = d(!1);
|
|
294
|
+
let w = 0;
|
|
295
295
|
async function v(n = !1) {
|
|
296
|
-
n && (
|
|
297
|
-
const
|
|
296
|
+
n && (k.value = 1, a.value = !1, h.value = !1), C.value = !0, y.value = !1, w += 1;
|
|
297
|
+
const c = w;
|
|
298
298
|
try {
|
|
299
|
-
const
|
|
300
|
-
page:
|
|
299
|
+
const u = await l.fetchFn({
|
|
300
|
+
page: k.value,
|
|
301
301
|
pageSize: l.pageSize,
|
|
302
302
|
...l.params
|
|
303
303
|
});
|
|
304
|
-
if (
|
|
305
|
-
const B = (
|
|
306
|
-
n ? (
|
|
307
|
-
} catch (
|
|
308
|
-
if (
|
|
309
|
-
y.value = !0, x("error",
|
|
304
|
+
if (c !== w) return;
|
|
305
|
+
const B = (u == null ? void 0 : u.records) || [];
|
|
306
|
+
n ? (o.value = B, E.value = 0) : o.value = [...o.value, ...B], E.value = Number((u == null ? void 0 : u.total) || 0), a.value = o.value.length >= E.value, h.value = o.value.length === 0, x("success", { records: B, total: E.value, reset: n }), x("update:list", o.value);
|
|
307
|
+
} catch (u) {
|
|
308
|
+
if (c !== w) return;
|
|
309
|
+
y.value = !0, x("error", u);
|
|
310
310
|
} finally {
|
|
311
|
-
|
|
311
|
+
c === w && (C.value = !1);
|
|
312
312
|
}
|
|
313
313
|
}
|
|
314
314
|
async function H() {
|
|
315
315
|
var n;
|
|
316
|
-
T.value = !0, (n =
|
|
317
|
-
setTimeout(() =>
|
|
316
|
+
T.value = !0, (n = i.value) == null || n.finishRefresh(), await new Promise((c) => {
|
|
317
|
+
setTimeout(() => c(), 250);
|
|
318
318
|
}), await v(!0), T.value = !1;
|
|
319
319
|
}
|
|
320
320
|
async function S() {
|
|
321
|
-
var n,
|
|
322
|
-
if (
|
|
323
|
-
(n =
|
|
321
|
+
var n, c;
|
|
322
|
+
if (a.value) {
|
|
323
|
+
(n = i.value) == null || n.finishLoad();
|
|
324
324
|
return;
|
|
325
325
|
}
|
|
326
|
-
|
|
326
|
+
o.value.length > 0 && (k.value += 1), await v(!1), (c = i.value) == null || c.finishLoad();
|
|
327
327
|
}
|
|
328
|
-
function
|
|
329
|
-
y.value = !1,
|
|
328
|
+
function L() {
|
|
329
|
+
y.value = !1, o.value.length === 0 ? v(!0) : S();
|
|
330
330
|
}
|
|
331
|
-
async function
|
|
331
|
+
async function r() {
|
|
332
332
|
await v(!0);
|
|
333
333
|
}
|
|
334
334
|
return j(
|
|
335
335
|
() => l.params,
|
|
336
336
|
() => {
|
|
337
|
-
l.autoReload &&
|
|
337
|
+
l.autoReload && r();
|
|
338
338
|
},
|
|
339
339
|
{ deep: !0 }
|
|
340
340
|
), j(
|
|
341
|
-
|
|
341
|
+
o,
|
|
342
342
|
async () => {
|
|
343
343
|
var n;
|
|
344
|
-
await I(), (n =
|
|
344
|
+
await I(), (n = i.value) == null || n.checkContentHeight();
|
|
345
345
|
},
|
|
346
346
|
{ deep: !0 }
|
|
347
347
|
), fe(() => {
|
|
348
348
|
l.immediate && v(!0);
|
|
349
349
|
}), m({
|
|
350
350
|
/** 重新加载第一页 */
|
|
351
|
-
reload:
|
|
351
|
+
reload: r,
|
|
352
352
|
/** 兼容别名 */
|
|
353
|
-
refresh:
|
|
353
|
+
refresh: r,
|
|
354
354
|
/** 当前列表数据 */
|
|
355
|
-
list:
|
|
355
|
+
list: o,
|
|
356
356
|
/** 加载中状态 */
|
|
357
|
-
loading:
|
|
357
|
+
loading: C,
|
|
358
358
|
/** 是否已加载完 */
|
|
359
|
-
finished:
|
|
359
|
+
finished: a,
|
|
360
360
|
/** 是否空数据 */
|
|
361
361
|
isEmpty: h,
|
|
362
362
|
/** 总条数 */
|
|
363
|
-
total:
|
|
363
|
+
total: E,
|
|
364
364
|
/** 透传 v1 方法 */
|
|
365
365
|
finishLoad: () => {
|
|
366
366
|
var n;
|
|
367
|
-
return (n =
|
|
367
|
+
return (n = i.value) == null ? void 0 : n.finishLoad();
|
|
368
368
|
},
|
|
369
369
|
finishRefresh: () => {
|
|
370
370
|
var n;
|
|
371
|
-
return (n =
|
|
371
|
+
return (n = i.value) == null ? void 0 : n.finishRefresh();
|
|
372
372
|
},
|
|
373
373
|
checkContentHeight: () => {
|
|
374
374
|
var n;
|
|
375
|
-
return (n =
|
|
375
|
+
return (n = i.value) == null ? void 0 : n.checkContentHeight();
|
|
376
376
|
}
|
|
377
|
-
}), (n,
|
|
377
|
+
}), (n, c) => (f(), U(he, {
|
|
378
378
|
ref_key: "scrollRef",
|
|
379
|
-
ref:
|
|
380
|
-
loading:
|
|
381
|
-
finished:
|
|
379
|
+
ref: i,
|
|
380
|
+
loading: C.value,
|
|
381
|
+
finished: a.value,
|
|
382
382
|
"is-empty": h.value,
|
|
383
383
|
error: y.value,
|
|
384
384
|
"pull-refresh": t.pullRefresh,
|
|
@@ -394,29 +394,29 @@ const Ee = { class: "loading-content" }, Re = { class: "loading-text" }, Ce = /*
|
|
|
394
394
|
"content-loading": T.value,
|
|
395
395
|
onLoad: S,
|
|
396
396
|
onRefresh: H,
|
|
397
|
-
onRetry:
|
|
397
|
+
onRetry: L
|
|
398
398
|
}, {
|
|
399
|
-
default:
|
|
399
|
+
default: Ee(() => [
|
|
400
400
|
K(n.$slots, "default", {
|
|
401
|
-
list:
|
|
402
|
-
loading:
|
|
403
|
-
finished:
|
|
401
|
+
list: o.value,
|
|
402
|
+
loading: C.value,
|
|
403
|
+
finished: a.value,
|
|
404
404
|
isEmpty: h.value,
|
|
405
405
|
error: y.value,
|
|
406
|
-
total:
|
|
407
|
-
reload:
|
|
406
|
+
total: E.value,
|
|
407
|
+
reload: r
|
|
408
408
|
})
|
|
409
409
|
]),
|
|
410
410
|
_: 3
|
|
411
411
|
}, 8, ["loading", "finished", "is-empty", "error", "pull-refresh", "pull-threshold", "load-threshold", "empty-text", "pulling-text", "loosing-text", "refreshing-text", "loading-text", "finished-text", "error-text", "content-loading"]));
|
|
412
412
|
}
|
|
413
413
|
});
|
|
414
|
-
let
|
|
415
|
-
const qe = ".loading-content[data-v-
|
|
414
|
+
let ue = !1;
|
|
415
|
+
const qe = ".loading-content[data-v-a890d226]{display:flex;align-items:center;justify-content:center;gap:8px;padding:6px 12px;border-radius:16px;color:#1989fa;font-size:14px}.loading-spinner[data-v-a890d226]{width:18px;height:18px;border-radius:50%;border:2.5px solid #1989fa;border-top-color:transparent;animation:spin-a890d226 .8s linear infinite}@keyframes spin-a890d226{to{transform:rotate(360deg)}}.loading-container.fullscreen[data-v-a890d226]{position:fixed;top:0;left:0;width:100%;height:100%;display:flex;align-items:center;justify-content:center;background-color:#ffffff80}.empty-wrap[data-v-3c452901]{display:flex;flex-direction:column;align-items:center}.empty-image[data-v-3c452901]{width:96px;height:80px}.empty-text[data-v-3c452901]{margin:12px 0 0;color:#8c8f97;font-size:12px;line-height:22px}.infinite-scroll[data-v-fc5e471c]{height:100%;position:relative;min-height:100%;overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;touch-action:pan-y;-webkit-overflow-scrolling:touch}.pull-refresh-indicator[data-v-fc5e471c]{position:absolute;top:-50px;left:0;right:0;height:50px;transition:transform .25s}.pull-refresh-indicator.no-transition[data-v-fc5e471c]{transition:none}.pull-refresh-content[data-v-fc5e471c]{display:flex;align-items:center;justify-content:center;height:100%;font-size:14px;color:#969799}.pull-text[data-v-fc5e471c]{color:#1989fa;font-size:14px}.infinite-scroll-content[data-v-fc5e471c]{position:relative;transition:transform .25s;min-height:100%}.infinite-scroll-content.no-transition[data-v-fc5e471c]{transition:none}.content-loading-mask[data-v-fc5e471c]{position:absolute;top:0;left:0;right:0;bottom:0;background-color:#fffc;display:flex;align-items:center;justify-content:center;z-index:10;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.load-more-indicator[data-v-fc5e471c]{display:flex;align-items:center;justify-content:center;min-height:50px;padding:16px 0;font-size:14px;color:#8c8f97}.finished-text[data-v-fc5e471c]{color:#8c8f97;font-size:14px}.error-text[data-v-fc5e471c]{color:#ee0a24;font-size:14px;cursor:pointer}.error-text[data-v-fc5e471c]:active{opacity:.7}";
|
|
416
416
|
function je() {
|
|
417
|
-
if (
|
|
417
|
+
if (ue || typeof document > "u") return;
|
|
418
418
|
const t = document.createElement("style");
|
|
419
|
-
t.setAttribute("data-source", "zx-infinite-scroll"), t.textContent = qe, document.head.appendChild(t),
|
|
419
|
+
t.setAttribute("data-source", "zx-infinite-scroll"), t.textContent = qe, document.head.appendChild(t), ue = !0;
|
|
420
420
|
}
|
|
421
421
|
je();
|
|
422
422
|
function Ye(t) {
|
package/dist/index.es.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.es.js","sources":["../src/components/request-loading.vue","../src/components/empty-component.vue","../src/components/infinite-scroll.vue","../src/components/infinite-scroll-v2.vue","../src/inject-style.ts","../src/index.ts"],"sourcesContent":["<script setup lang=\"ts\">\ndefineOptions({ name: 'RequestLoading' });\n\nwithDefaults(defineProps<{ text?: string; fullscreen?: boolean }>(), {\n text: '加载中...',\n fullscreen: false\n});\n</script>\n\n<template>\n <div class=\"loading-container\" :class=\"{ fullscreen: fullscreen }\">\n <div class=\"loading-content\">\n <span class=\"loading-spinner\"></span>\n <span class=\"loading-text\">{{ text }}</span>\n </div>\n </div>\n</template>\n\n<style scoped lang=\"scss\">\n.loading-content {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 6px 12px;\n border-radius: 16px;\n color: var(--zx-primary-color, #1e5efd);\n font-size: 14px;\n}\n\n.loading-spinner {\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: 2.5px solid var(--zx-primary-color, #1e5efd);\n border-top-color: transparent;\n animation: spin 0.8s linear infinite;\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n.loading-container.fullscreen {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: rgba(255, 255, 255, 0.5);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue';\n\ndefineOptions({ name: 'EmptyComponent' });\n\ninterface Props {\n text?: string;\n showText?: boolean;\n /** 顶部间距,可传数字(px)或带单位字符串,默认 168px */\n paddingTop?: number | string;\n /** 自定义图片 URL */\n emptyImage?: string;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n text: '暂无数据',\n showText: true,\n paddingTop: 168,\n emptyImage: ''\n});\n\nconst wrapStyle = computed(() => ({\n paddingTop: typeof props.paddingTop === 'number' ? `${props.paddingTop}px` : props.paddingTop\n}));\n\n// 默认空状态 SVG(简洁的空文件夹图标)\nconst defaultEmptySvg = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='80' viewBox='0 0 96 80' fill='none'%3E%3Cpath d='M8 16C8 12.6863 10.6863 10 14 10H38L44 16H82C85.3137 16 88 18.6863 88 22V66C88 69.3137 85.3137 72 82 72H14C10.6863 72 8 69.3137 8 66V16Z' fill='%23E8E8E8'/%3E%3Cpath d='M8 20C8 18.3431 9.34315 17 11 17H85C86.6569 17 88 18.3431 88 20V66C88 69.3137 85.3137 72 82 72H14C10.6863 72 8 69.3137 8 66V20Z' fill='%23F5F5F5'/%3E%3Cpath d='M38 42C38 40.8954 38.8954 40 40 40H56C57.1046 40 58 40.8954 58 42V44C58 45.1046 57.1046 46 56 46H40C38.8954 46 38 45.1046 38 44V42Z' fill='%23D9D9D9'/%3E%3C/svg%3E`;\n\nconst imageSrc = computed(() => props.emptyImage || defaultEmptySvg);\n</script>\n\n<template>\n <div class=\"empty-wrap\" :style=\"wrapStyle\">\n <img class=\"empty-image\" :src=\"imageSrc\" alt=\"\" />\n <p v-if=\"showText\" class=\"empty-text\">\n <slot>{{ text }}</slot>\n </p>\n </div>\n</template>\n\n<style scoped lang=\"scss\">\n.empty-wrap {\n display: flex;\n flex-direction: column;\n align-items: center;\n}\n\n.empty-image {\n width: 96px;\n height: 80px;\n}\n\n.empty-text {\n margin: 12px 0 0;\n color: #8c8f97;\n font-size: 12px;\n line-height: 22px;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';\nimport RequestLoading from './request-loading.vue';\nimport EmptyComponent from './empty-component.vue';\n\ndefineOptions({\n name: 'InfiniteScroll'\n});\n\ninterface Props {\n /** 是否处于加载中状态 */\n loading?: boolean;\n /** 是否已加载完所有数据 */\n finished?: boolean;\n /** 是否显示空状态 */\n isEmpty?: boolean;\n /** 空状态文案 */\n emptyText?: string;\n /** 是否启用下拉刷新 */\n pullRefresh?: boolean;\n /** 下拉刷新触发距离(px) */\n pullThreshold?: number;\n /** 上拉加载触发距离(距离底部 px) */\n loadThreshold?: number;\n /** 下拉中的文案 */\n pullingText?: string;\n /** 释放刷新的文案 */\n loosingText?: string;\n /** 刷新中的文案 */\n refreshingText?: string;\n /** 加载中的文案 */\n loadingText?: string;\n /** 加载完成的文案 */\n finishedText?: string;\n /** 加载失败的文案 */\n errorText?: string;\n /** 是否显示错误状态 */\n error?: boolean;\n /** 内容区域是否显示加载状态 */\n contentLoading?: boolean;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n loading: false,\n finished: false,\n isEmpty: false,\n emptyText: '暂无数据',\n pullRefresh: false,\n pullThreshold: 70,\n loadThreshold: 50,\n pullingText: '下拉刷新',\n loosingText: '释放即可刷新',\n refreshingText: '加载中...',\n loadingText: '加载中...',\n finishedText: '没有更多了~',\n errorText: '加载失败,点击重试',\n error: false,\n contentLoading: false\n});\n\nconst emit = defineEmits<{\n /** 触发下拉刷新 */\n refresh: [];\n /** 触发上拉加载 */\n load: [];\n /** 点击错误重试 */\n retry: [];\n}>();\n\nconst containerRef = ref<HTMLElement | null>(null);\nconst contentRef = ref<HTMLElement | null>(null);\nconst indicatorRef = ref<HTMLElement | null>(null);\n\n// 下拉刷新状态\nconst pullStatus = ref<'idle' | 'pulling' | 'loosing' | 'refreshing'>('idle');\nconst pullDistance = ref(0);\n// 拖动期间禁用 transition,避免 transform 变化时被 0.25s 补间拖慢\nconst isDragging = ref(false);\n\n// 触摸相关\nlet startX = 0;\nlet startY = 0;\nlet lastDistance = 0;\n// 手势方向锁:避免横向滑动被误判为下拉\nlet gestureLock: 'none' | 'vertical' | 'horizontal' = 'none';\nconst SLOPE_LOCK_DISTANCE = 8;\n\nlet isRefreshing = false;\nlet isLoading = false;\n// 鼠标拖拽下拉(PC 端)\nlet isMouseDown = false;\n\n// 节流相关\nlet scrollTimer: number | null = null;\nlet touchMoveRaf: number | null = null;\nlet idleTimer: number | null = null;\n// 监听容器尺寸变化\nlet resizeObserver: ResizeObserver | null = null;\n// 防止空页死循环:snapshot 触发 load 时的 contentHeight,下次完成后没增长就不再 auto-load\nlet lastTriggerContentHeight = -1;\n\n// 下拉刷新核心:按下(与指针类型无关,touch/mouse 共用)\nfunction pullStart(clientX: number, clientY: number) {\n if (!props.pullRefresh || isRefreshing) return;\n startX = clientX;\n startY = clientY;\n lastDistance = 0;\n gestureLock = 'none';\n pullStatus.value = 'idle';\n}\n\n// 下拉刷新核心:移动(rAF 节流,始终使用最新位置)\n// 返回 true 表示消费了本次移动(下拉进行中),调用方据此决定是否 preventDefault\nfunction pullMove(clientX: number, clientY: number, cancelable: boolean): boolean {\n if (!props.pullRefresh || isRefreshing || startY === 0) return false;\n\n const dx = clientX - startX;\n const dy = clientY - startY;\n\n // 方向判定:先到达 8px 锁定的方向才认为有意图,垂直要明显大于水平(1.5x)\n if (gestureLock === 'none') {\n const ax = Math.abs(dx);\n const ay = Math.abs(dy);\n if (ax > SLOPE_LOCK_DISTANCE || ay > SLOPE_LOCK_DISTANCE) {\n gestureLock = ay > ax * 1.5 ? 'vertical' : 'horizontal';\n } else {\n return false;\n }\n }\n if (gestureLock === 'horizontal') return false;\n\n // 子像素容差:≤1 视为已到顶,避免 X5 内核 scrollTop 偶发非整数判断失败\n const atTop = getScrollTop() <= 1;\n\n // iOS 15- 兜底:在 atBottom 且向上拖时阻止整页 rubber-band\n // (iOS 16+ overscroll-behavior 已处理,此处兜底兼容)\n if (!atTop && dy < 0) {\n const c = containerRef.value;\n if (c) {\n const atBottom = c.scrollHeight - c.scrollTop - c.clientHeight <= 1;\n if (atBottom && cancelable) {\n return true;\n }\n }\n return false;\n }\n if (!atTop) return false;\n\n // 反向拖动也要更新(让指示器跟着手指回退),夹紧到 [0, 150]\n const clamped = Math.max(0, Math.min(dy, 150));\n\n lastDistance = clamped;\n isDragging.value = true;\n\n if (touchMoveRaf === null) {\n touchMoveRaf = requestAnimationFrame(() => {\n touchMoveRaf = null;\n pullDistance.value = lastDistance * 0.5;\n if (lastDistance === 0) {\n pullStatus.value = 'idle';\n } else {\n pullStatus.value = lastDistance > props.pullThreshold ? 'loosing' : 'pulling';\n }\n });\n }\n\n // 仅在向下拖时消费事件(避免误吞用户向上滚动的意图)\n return dy > 0;\n}\n\n// 下拉刷新核心:松开\nfunction pullEnd() {\n if (!props.pullRefresh || isRefreshing) return;\n\n // 取消待执行的 rAF,避免松手后还有一帧异步更新把 UI 拉回 loosing 卡住\n if (touchMoveRaf !== null) {\n cancelAnimationFrame(touchMoveRaf);\n touchMoveRaf = null;\n }\n\n isDragging.value = false;\n\n // 用最新的 lastDistance 同步判定,不依赖可能尚未生效的 pullStatus\n if (lastDistance > props.pullThreshold) {\n isRefreshing = true;\n pullStatus.value = 'refreshing';\n pullDistance.value = 50;\n emit('refresh');\n } else {\n pullDistance.value = 0;\n pullStatus.value = 'idle';\n }\n\n resetTouch();\n}\n\n// 下拉刷新核心:取消(回到 idle)\nfunction pullCancel() {\n if (!props.pullRefresh || isRefreshing) return;\n\n if (touchMoveRaf !== null) {\n cancelAnimationFrame(touchMoveRaf);\n touchMoveRaf = null;\n }\n\n isDragging.value = false;\n pullDistance.value = 0;\n pullStatus.value = 'idle';\n resetTouch();\n}\n\n// 下拉刷新 - touchstart\nfunction handleTouchStart(e: TouchEvent) {\n pullStart(e.touches[0].clientX, e.touches[0].clientY);\n}\n\n// 下拉刷新 - touchmove\nfunction handleTouchMove(e: TouchEvent) {\n const touch = e.touches[0];\n if (pullMove(touch.clientX, touch.clientY, e.cancelable) && e.cancelable) {\n e.preventDefault();\n }\n}\n\n// 下拉刷新 - touchend\nfunction handleTouchEnd() {\n pullEnd();\n}\n\n// 下拉刷新 - touchcancel(微信 X5 内核会在系统手势介入时派发 cancel 而非 end)\nfunction handleTouchCancel() {\n pullCancel();\n}\n\n// 下拉刷新 - mousedown(PC 端鼠标拖拽)\nfunction handleMouseDown(e: MouseEvent) {\n // 仅左键触发\n if (!props.pullRefresh || isRefreshing || e.button !== 0) return;\n isMouseDown = true;\n pullStart(e.clientX, e.clientY);\n}\n\n// 下拉刷新 - mousemove(挂在 window 上,允许拖出容器)\nfunction handleMouseMove(e: MouseEvent) {\n if (!isMouseDown) return;\n if (pullMove(e.clientX, e.clientY, true)) {\n // 阻止拖拽时选中文本\n e.preventDefault();\n }\n}\n\n// 下拉刷新 - mouseup\nfunction handleMouseUp() {\n if (!isMouseDown) return;\n isMouseDown = false;\n pullEnd();\n}\n\nfunction resetTouch() {\n startX = 0;\n startY = 0;\n lastDistance = 0;\n gestureLock = 'none';\n}\n\n// 上拉加载 - scroll(节流处理)\nfunction handleScroll() {\n if (props.loading || props.finished || props.error || isLoading) return;\n if (scrollTimer) return;\n\n scrollTimer = window.setTimeout(() => {\n scrollTimer = null;\n const container = containerRef.value;\n if (!container) return;\n\n const { scrollTop, clientHeight, scrollHeight } = container;\n const contentHeight = contentRef.value?.clientHeight || 0;\n\n // 情况1:内容不足一屏,自动触发加载\n if (contentHeight <= clientHeight) {\n // 死循环防护:上一次 auto-load 后内容没增长,不再继续触发\n if (lastTriggerContentHeight === contentHeight) return;\n lastTriggerContentHeight = contentHeight;\n // 不足一屏时主动滚到底,让 loading 指示器进入视口\n triggerLoad(true);\n return;\n }\n\n // 情况2:滚动到距离底部阈值范围内\n if (scrollHeight - scrollTop - clientHeight <= props.loadThreshold) {\n // 用户已经手动滚到底,不再强制 scrollTop(避免打断惯性滚动)\n triggerLoad(false);\n }\n }, 100);\n}\n\nfunction triggerLoad(scrollToBottom = false) {\n isLoading = true;\n emit('load');\n nextTick(() => {\n const c = containerRef.value;\n if (!c) return;\n if (scrollToBottom) {\n // 内容不足一屏:直接滚到底(没有\"惯性\"可以打断)\n c.scrollTop = c.scrollHeight;\n } else {\n // 阈值触发:用 scrollIntoView 平滑进入视口,避免突兀打断;\n // 旧 WebKit 不识别 options 会降级为即时滚动,效果等价\n indicatorRef.value?.scrollIntoView({ block: 'end', behavior: 'smooth' });\n }\n });\n}\n\n// 获取滚动距离\nfunction getScrollTop(): number {\n return containerRef.value?.scrollTop ?? 0;\n}\n\n// 完成下拉刷新\nfunction finishRefresh() {\n isRefreshing = false;\n pullDistance.value = 0;\n // 让 transform snap-back 完成后再切 idle,避免 spinner 在动画中途突然消失\n if (idleTimer !== null) clearTimeout(idleTimer);\n idleTimer = window.setTimeout(() => {\n pullStatus.value = 'idle';\n idleTimer = null;\n }, 250);\n // 重置死循环计数\n lastTriggerContentHeight = -1;\n nextTick(() => {\n checkContentHeight();\n });\n}\n\n// 完成上拉加载\nfunction finishLoad() {\n isLoading = false;\n nextTick(() => {\n const contentHeight = contentRef.value?.clientHeight || 0;\n // 内容没增长就不再触发 auto-load,避免空页死循环\n if (lastTriggerContentHeight !== -1 && contentHeight === lastTriggerContentHeight) return;\n lastTriggerContentHeight = -1;\n checkContentHeight();\n });\n}\n\n// 检查内容高度,不足一屏时自动触发加载\nfunction checkContentHeight() {\n if (props.finished || props.loading || props.error) return;\n\n nextTick(() => {\n const contentHeight = contentRef.value?.clientHeight || 0;\n const clientHeight = containerRef.value?.clientHeight || 0;\n\n if (contentHeight <= clientHeight && !isLoading) {\n handleScroll();\n }\n });\n}\n\n// 点击错误重试 — 由父组件决定具体行为,避免 retry + load 双触发\nfunction handleRetry() {\n emit('retry');\n}\n\n// loading 完成时同步重置 isLoading\nwatch(\n () => props.loading,\n newVal => {\n if (!newVal) {\n isLoading = false;\n }\n }\n);\n\n// finished 翻为 true 时重置死循环计数\nwatch(\n () => props.finished,\n newVal => {\n if (newVal) {\n lastTriggerContentHeight = -1;\n }\n }\n);\n\nonMounted(() => {\n const container = containerRef.value;\n if (!container) return;\n\n if (props.pullRefresh) {\n container.addEventListener('touchstart', handleTouchStart, { passive: true });\n container.addEventListener('touchmove', handleTouchMove, { passive: false });\n container.addEventListener('touchend', handleTouchEnd, { passive: true });\n container.addEventListener('touchcancel', handleTouchCancel, { passive: true });\n // 鼠标拖拽(PC):move/up 挂在 window 上,允许拖出容器边界\n container.addEventListener('mousedown', handleMouseDown);\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUp);\n }\n\n container.addEventListener('scroll', handleScroll, { passive: true });\n\n // 监听容器/内容尺寸变化(旋转、WebView resize、软键盘弹出收起等)\n if (typeof ResizeObserver !== 'undefined') {\n resizeObserver = new ResizeObserver(() => {\n checkContentHeight();\n });\n resizeObserver.observe(container);\n if (contentRef.value) resizeObserver.observe(contentRef.value);\n }\n\n // 初始检查内容高度\n nextTick(() => {\n checkContentHeight();\n });\n});\n\nonBeforeUnmount(() => {\n const container = containerRef.value;\n if (container) {\n container.removeEventListener('touchstart', handleTouchStart);\n container.removeEventListener('touchmove', handleTouchMove);\n container.removeEventListener('touchend', handleTouchEnd);\n container.removeEventListener('touchcancel', handleTouchCancel);\n container.removeEventListener('mousedown', handleMouseDown);\n container.removeEventListener('scroll', handleScroll);\n }\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n if (resizeObserver) {\n resizeObserver.disconnect();\n resizeObserver = null;\n }\n if (touchMoveRaf !== null) {\n cancelAnimationFrame(touchMoveRaf);\n touchMoveRaf = null;\n }\n if (scrollTimer !== null) {\n clearTimeout(scrollTimer);\n scrollTimer = null;\n }\n if (idleTimer !== null) {\n clearTimeout(idleTimer);\n idleTimer = null;\n }\n});\n\ndefineExpose({\n refresh: finishRefresh,\n finishRefresh,\n finishPullDown: finishRefresh,\n finishLoad,\n finishPullUp: finishLoad,\n checkContentHeight\n});\n</script>\n\n<template>\n <div ref=\"containerRef\" class=\"infinite-scroll\">\n <!-- 下拉刷新指示器 -->\n <div\n v-if=\"pullRefresh\"\n class=\"pull-refresh-indicator\"\n :class=\"{ 'no-transition': isDragging }\"\n :style=\"{ transform: `translateY(${pullDistance}px)` }\"\n >\n <div v-show=\"pullStatus !== 'idle'\" class=\"pull-refresh-content\">\n <!-- <RequestLoading v-if=\"pullStatus === 'refreshing'\" text=\"\" /> -->\n <span v-if=\"pullStatus === 'refreshing'\"></span>\n <span v-else-if=\"pullStatus === 'loosing'\" class=\"pull-text\">{{ loosingText }}</span>\n <span v-else class=\"pull-text\">{{ pullingText }}</span>\n </div>\n </div>\n\n <!-- 内容区域 -->\n <div\n ref=\"contentRef\"\n class=\"infinite-scroll-content\"\n :class=\"{ 'no-transition': isDragging }\"\n :style=\"pullRefresh ? { transform: `translateY(${pullDistance}px)` } : {}\"\n >\n <!-- 内容区域加载遮罩 -->\n <div v-if=\"contentLoading\" class=\"content-loading-mask\">\n <RequestLoading :text=\"refreshingText\" />\n </div>\n\n <!-- 空状态 -->\n <EmptyComponent v-if=\"isEmpty && !loading\" :text=\"emptyText\" />\n\n <!-- 默认插槽 -->\n <slot></slot>\n\n <!-- 上拉加载指示器 -->\n <div v-if=\"!isEmpty\" ref=\"indicatorRef\" class=\"load-more-indicator\">\n <RequestLoading v-if=\"loading && pullStatus !== 'refreshing'\" :text=\"loadingText\" />\n <span v-else-if=\"finished\" class=\"finished-text\">{{ finishedText }}</span>\n <span v-else-if=\"error\" class=\"error-text\" @click=\"handleRetry\">{{ errorText }}</span>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped lang=\"scss\">\n.infinite-scroll {\n height: 100%;\n position: relative;\n min-height: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n // 阻止滚动到边界时把滚动链传递给祖先(修复 iOS 16+ / 微信 X5 下拉变成整页拖拽)\n overscroll-behavior: contain;\n // 显式声明只接受纵向手势,避免被外层 touch-action 影响\n touch-action: pan-y;\n // iOS 下让原生回弹有惯性\n -webkit-overflow-scrolling: touch;\n}\n\n.pull-refresh-indicator {\n position: absolute;\n top: -50px;\n left: 0;\n right: 0;\n height: 50px;\n transition: transform 0.25s;\n\n // 拖动期间禁用过渡,让 transform 1:1 跟随手指\n &.no-transition {\n transition: none;\n }\n}\n\n.pull-refresh-content {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n font-size: 14px;\n color: #969799;\n}\n\n.pull-text {\n color: var(--zx-primary-color, #1989fa);\n font-size: 14px;\n}\n\n.infinite-scroll-content {\n position: relative;\n transition: transform 0.25s;\n min-height: 100%;\n\n &.no-transition {\n transition: none;\n }\n}\n\n.content-loading-mask {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(255, 255, 255, 0.8);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10;\n backdrop-filter: blur(2px);\n}\n\n.load-more-indicator {\n display: flex;\n align-items: center;\n justify-content: center;\n // 预留高度避免 loading 渲染后被推到视口外造成遮挡\n min-height: 50px;\n padding: 16px 0;\n font-size: 14px;\n color: #8c8f97;\n}\n\n.finished-text {\n color: #8c8f97;\n font-size: 14px;\n}\n\n.error-text {\n color: #ee0a24;\n font-size: 14px;\n cursor: pointer;\n\n &:active {\n opacity: 0.7;\n }\n}\n</style>\n","<script setup lang=\"ts\" generic=\"T\">\nimport { type Ref, nextTick, onMounted, ref, watch } from 'vue';\nimport InfiniteScroll from './infinite-scroll.vue';\n\ndefineOptions({\n name: 'InfiniteScrollV2'\n});\n\nconst props = withDefaults(\n defineProps<{\n /** 数据请求函数,需返回 { records, total },失败时抛错 */\n fetchFn: (params: {\n page: number;\n pageSize: number;\n [key: string]: any;\n }) => Promise<{\n records: T[];\n total: number;\n }>;\n /** 业务查询参数(如筛选条件),变化时自动 reset 重新加载 */\n params?: Record<string, any>;\n /** 每页条数 */\n pageSize?: number;\n /** params 变化时是否自动重新加载 */\n autoReload?: boolean;\n /** 是否在挂载时自动加载首页 */\n immediate?: boolean;\n /** 是否启用下拉刷新 */\n pullRefresh?: boolean;\n /** 下拉刷新触发距离(px) */\n pullThreshold?: number;\n /** 上拉加载触发距离(距离底部 px) */\n loadThreshold?: number;\n /** 空状态文案 */\n emptyText?: string;\n /** 下拉中的文案 */\n pullingText?: string;\n /** 释放刷新的文案 */\n loosingText?: string;\n /** 刷新中的文案 */\n refreshingText?: string;\n /** 加载中的文案 */\n loadingText?: string;\n /** 加载完成的文案 */\n finishedText?: string;\n /** 加载失败的文案 */\n errorText?: string;\n }>(),\n {\n params: () => ({}),\n pageSize: 10,\n autoReload: true,\n immediate: true,\n pullRefresh: false,\n pullThreshold: 70,\n loadThreshold: 50,\n emptyText: '暂无数据',\n pullingText: '下拉刷新',\n loosingText: '释放即可刷新',\n refreshingText: '加载中...',\n loadingText: '加载中...',\n finishedText: '没有更多了~',\n errorText: '加载失败,点击重试'\n});\n\nconst emit = defineEmits<{\n /** 加载成功,每次成功(含分页)都会触发 */\n success: [payload: { records: T[]; total: number; reset: boolean }];\n /** 加载失败 */\n error: [err: unknown];\n /** 列表内容变化(v-model:list 支持) */\n 'update:list': [list: T[]];\n}>();\n\nconst scrollRef = ref<InstanceType<typeof InfiniteScroll> | null>(null);\n\nconst list = ref<T[]>([]) as Ref<T[]>;\nconst loading = ref(false);\nconst finished = ref(false);\nconst isEmpty = ref(false);\nconst loadError = ref(false);\nconst total = ref(0);\nconst page = ref(1);\nconst isRefreshing = ref(false);\n\nlet requestSeq = 0;\n\nasync function load(reset = false) {\n if (reset) {\n page.value = 1;\n finished.value = false;\n isEmpty.value = false;\n // 不立即清空 list,保留旧数据直到新数据到达\n }\n loading.value = true;\n loadError.value = false;\n\n requestSeq += 1;\n const seq = requestSeq;\n\n try {\n const result = await props.fetchFn({\n page: page.value,\n pageSize: props.pageSize,\n ...props.params\n });\n\n if (seq !== requestSeq) return;\n\n const records = result?.records || [];\n if (reset) {\n // reset 时替换整个列表\n list.value = records;\n total.value = 0;\n } else {\n list.value = [...list.value, ...records];\n }\n total.value = Number(result?.total || 0);\n finished.value = list.value.length >= total.value;\n isEmpty.value = list.value.length === 0;\n\n emit('success', { records, total: total.value, reset });\n emit('update:list', list.value);\n } catch (err) {\n if (seq !== requestSeq) return;\n loadError.value = true;\n emit('error', err);\n } finally {\n if (seq === requestSeq) {\n loading.value = false;\n }\n }\n}\n\nasync function handleRefresh() {\n isRefreshing.value = true;\n // 先让下拉刷新指示器收回\n scrollRef.value?.finishRefresh();\n // 等待 250ms 让指示器完全收回(对应 infinite-scroll.vue 的 transition 时长)\n await new Promise<void>(resolve => {\n setTimeout(() => resolve(), 250);\n });\n // 指示器收回后再开始请求新数据\n await load(true);\n isRefreshing.value = false;\n}\n\nasync function handleLoad() {\n if (finished.value) {\n scrollRef.value?.finishLoad();\n return;\n }\n // 列表为空时是首次加载(page 已经是 1),其它情况 page++\n if (list.value.length > 0) {\n page.value += 1;\n }\n await load(false);\n scrollRef.value?.finishLoad();\n}\n\nfunction handleRetry() {\n loadError.value = false;\n if (list.value.length === 0) {\n load(true);\n } else {\n handleLoad();\n }\n}\n\nasync function reload() {\n await load(true);\n}\n\nwatch(\n () => props.params,\n () => {\n if (props.autoReload) {\n reload();\n }\n },\n { deep: true }\n);\n\nwatch(\n list,\n async () => {\n await nextTick();\n scrollRef.value?.checkContentHeight();\n },\n { deep: true }\n);\n\nonMounted(() => {\n if (props.immediate) {\n load(true);\n }\n});\n\ndefineExpose({\n /** 重新加载第一页 */\n reload,\n /** 兼容别名 */\n refresh: reload,\n /** 当前列表数据 */\n list,\n /** 加载中状态 */\n loading,\n /** 是否已加载完 */\n finished,\n /** 是否空数据 */\n isEmpty,\n /** 总条数 */\n total,\n /** 透传 v1 方法 */\n finishLoad: () => scrollRef.value?.finishLoad(),\n finishRefresh: () => scrollRef.value?.finishRefresh(),\n checkContentHeight: () => scrollRef.value?.checkContentHeight()\n});\n</script>\n\n<template>\n <InfiniteScroll\n ref=\"scrollRef\"\n :loading=\"loading\"\n :finished=\"finished\"\n :is-empty=\"isEmpty\"\n :error=\"loadError\"\n :pull-refresh=\"pullRefresh\"\n :pull-threshold=\"pullThreshold\"\n :load-threshold=\"loadThreshold\"\n :empty-text=\"emptyText\"\n :pulling-text=\"pullingText\"\n :loosing-text=\"loosingText\"\n :refreshing-text=\"refreshingText\"\n :loading-text=\"loadingText\"\n :finished-text=\"finishedText\"\n :error-text=\"errorText\"\n :content-loading=\"isRefreshing\"\n @load=\"handleLoad\"\n @refresh=\"handleRefresh\"\n @retry=\"handleRetry\"\n >\n <slot\n :list=\"list\"\n :loading=\"loading\"\n :finished=\"finished\"\n :is-empty=\"isEmpty\"\n :error=\"loadError\"\n :total=\"total\"\n :reload=\"reload\"\n />\n </InfiniteScroll>\n</template>\n","// 样式自动注入\nlet styleInjected = false;\n\nconst cssContent = `.loading-content[data-v-d89150ba]{display:flex;align-items:center;justify-content:center;gap:8px;padding:6px 12px;border-radius:16px;color:var(--zx-primary-color, #1e5efd);font-size:14px}.loading-spinner[data-v-d89150ba]{width:18px;height:18px;border-radius:50%;border:2.5px solid var(--zx-primary-color, #1e5efd);border-top-color:transparent;animation:spin-d89150ba .8s linear infinite}@keyframes spin-d89150ba{to{transform:rotate(360deg)}}.loading-container.fullscreen[data-v-d89150ba]{position:fixed;top:0;left:0;width:100%;height:100%;display:flex;align-items:center;justify-content:center;background-color:#ffffff80}.empty-wrap[data-v-3c452901]{display:flex;flex-direction:column;align-items:center}.empty-image[data-v-3c452901]{width:96px;height:80px}.empty-text[data-v-3c452901]{margin:12px 0 0;color:#8c8f97;font-size:12px;line-height:22px}.infinite-scroll[data-v-bf5ca1d9]{height:100%;position:relative;min-height:100%;overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;touch-action:pan-y;-webkit-overflow-scrolling:touch}.pull-refresh-indicator[data-v-bf5ca1d9]{position:absolute;top:-50px;left:0;right:0;height:50px;transition:transform .25s}.pull-refresh-indicator.no-transition[data-v-bf5ca1d9]{transition:none}.pull-refresh-content[data-v-bf5ca1d9]{display:flex;align-items:center;justify-content:center;height:100%;font-size:14px;color:#969799}.pull-text[data-v-bf5ca1d9]{color:var(--zx-primary-color, #1989fa);font-size:14px}.infinite-scroll-content[data-v-bf5ca1d9]{position:relative;transition:transform .25s;min-height:100%}.infinite-scroll-content.no-transition[data-v-bf5ca1d9]{transition:none}.content-loading-mask[data-v-bf5ca1d9]{position:absolute;top:0;left:0;right:0;bottom:0;background-color:#fffc;display:flex;align-items:center;justify-content:center;z-index:10;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.load-more-indicator[data-v-bf5ca1d9]{display:flex;align-items:center;justify-content:center;min-height:50px;padding:16px 0;font-size:14px;color:#8c8f97}.finished-text[data-v-bf5ca1d9]{color:#8c8f97;font-size:14px}.error-text[data-v-bf5ca1d9]{color:#ee0a24;font-size:14px;cursor:pointer}.error-text[data-v-bf5ca1d9]:active{opacity:.7}`;\n\nexport function injectStyle() {\n if (styleInjected || typeof document === 'undefined') return;\n\n const style = document.createElement('style');\n style.setAttribute('data-source', 'zx-infinite-scroll');\n style.textContent = cssContent;\n document.head.appendChild(style);\n\n styleInjected = true;\n}\n","import { App } from 'vue';\nimport InfiniteScroll from './components/infinite-scroll.vue';\nimport InfiniteScrollV2 from './components/infinite-scroll-v2.vue';\nimport RequestLoading from './components/request-loading.vue';\nimport EmptyComponent from './components/empty-component.vue';\nimport { injectStyle } from './inject-style';\n\n// 自动注入样式(只要导入了这个包就会执行)\ninjectStyle();\n\n// 单独导出组件\nexport { InfiniteScroll, InfiniteScrollV2, RequestLoading, EmptyComponent };\n\n// Vue plugin install 函数\nexport function install(app: App) {\n app.component('InfiniteScroll', InfiniteScroll);\n app.component('InfiniteScrollV2', InfiniteScrollV2);\n app.component('RequestLoading', RequestLoading);\n app.component('EmptyComponent', EmptyComponent);\n}\n\n// 默认导出(支持 app.use() 安装)\nexport default {\n install\n};\n"],"names":["_createElementBlock","_normalizeClass","__props","_createElementVNode","_hoisted_1","_hoisted_2","_toDisplayString","defaultEmptySvg","props","wrapStyle","computed","imageSrc","_openBlock","_renderSlot","_ctx","SLOPE_LOCK_DISTANCE","emit","__emit","containerRef","ref","contentRef","indicatorRef","pullStatus","pullDistance","isDragging","startX","startY","lastDistance","gestureLock","isRefreshing","isLoading","isMouseDown","scrollTimer","touchMoveRaf","idleTimer","resizeObserver","lastTriggerContentHeight","pullStart","clientX","clientY","pullMove","cancelable","dx","dy","ax","ay","atTop","getScrollTop","c","pullEnd","resetTouch","pullCancel","handleTouchStart","handleTouchMove","touch","handleTouchEnd","handleTouchCancel","handleMouseDown","handleMouseMove","handleMouseUp","handleScroll","container","scrollTop","clientHeight","scrollHeight","contentHeight","_a","triggerLoad","scrollToBottom","nextTick","finishRefresh","checkContentHeight","finishLoad","_b","handleRetry","watch","newVal","onMounted","onBeforeUnmount","__expose","_withDirectives","_hoisted_3","_hoisted_4","_normalizeStyle","_hoisted_5","_createVNode","RequestLoading","_createBlock","EmptyComponent","_hoisted_6","scrollRef","list","loading","finished","isEmpty","loadError","total","page","requestSeq","load","reset","seq","result","records","err","handleRefresh","resolve","handleLoad","reload","InfiniteScroll","styleInjected","cssContent","injectStyle","style","install","app","InfiniteScrollV2","index"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.es.js","sources":["../src/components/request-loading.vue","../src/components/empty-component.vue","../src/components/infinite-scroll.vue","../src/components/infinite-scroll-v2.vue","../src/inject-style.ts","../src/index.ts"],"sourcesContent":["<script setup lang=\"ts\">\ndefineOptions({ name: 'RequestLoading' });\n\nwithDefaults(defineProps<{ text?: string; fullscreen?: boolean }>(), {\n text: '加载中...',\n fullscreen: false\n});\n</script>\n\n<template>\n <div class=\"loading-container\" :class=\"{ fullscreen: fullscreen }\">\n <div class=\"loading-content\">\n <span class=\"loading-spinner\"></span>\n <span class=\"loading-text\">{{ text }}</span>\n </div>\n </div>\n</template>\n\n<style scoped lang=\"scss\">\n.loading-content {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 6px 12px;\n border-radius: 16px;\n color: #1989fa;\n font-size: 14px;\n}\n\n.loading-spinner {\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: 2.5px solid #1989fa;\n border-top-color: transparent;\n animation: spin 0.8s linear infinite;\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n.loading-container.fullscreen {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: rgba(255, 255, 255, 0.5);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue';\n\ndefineOptions({ name: 'EmptyComponent' });\n\ninterface Props {\n text?: string;\n showText?: boolean;\n /** 顶部间距,可传数字(px)或带单位字符串,默认 168px */\n paddingTop?: number | string;\n /** 自定义图片 URL */\n emptyImage?: string;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n text: '暂无数据',\n showText: true,\n paddingTop: 168,\n emptyImage: ''\n});\n\nconst wrapStyle = computed(() => ({\n paddingTop: typeof props.paddingTop === 'number' ? `${props.paddingTop}px` : props.paddingTop\n}));\n\n// 默认空状态 SVG(简洁的空文件夹图标)\nconst defaultEmptySvg = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='80' viewBox='0 0 96 80' fill='none'%3E%3Cpath d='M8 16C8 12.6863 10.6863 10 14 10H38L44 16H82C85.3137 16 88 18.6863 88 22V66C88 69.3137 85.3137 72 82 72H14C10.6863 72 8 69.3137 8 66V16Z' fill='%23E8E8E8'/%3E%3Cpath d='M8 20C8 18.3431 9.34315 17 11 17H85C86.6569 17 88 18.3431 88 20V66C88 69.3137 85.3137 72 82 72H14C10.6863 72 8 69.3137 8 66V20Z' fill='%23F5F5F5'/%3E%3Cpath d='M38 42C38 40.8954 38.8954 40 40 40H56C57.1046 40 58 40.8954 58 42V44C58 45.1046 57.1046 46 56 46H40C38.8954 46 38 45.1046 38 44V42Z' fill='%23D9D9D9'/%3E%3C/svg%3E`;\n\nconst imageSrc = computed(() => props.emptyImage || defaultEmptySvg);\n</script>\n\n<template>\n <div class=\"empty-wrap\" :style=\"wrapStyle\">\n <img class=\"empty-image\" :src=\"imageSrc\" alt=\"\" />\n <p v-if=\"showText\" class=\"empty-text\">\n <slot>{{ text }}</slot>\n </p>\n </div>\n</template>\n\n<style scoped lang=\"scss\">\n.empty-wrap {\n display: flex;\n flex-direction: column;\n align-items: center;\n}\n\n.empty-image {\n width: 96px;\n height: 80px;\n}\n\n.empty-text {\n margin: 12px 0 0;\n color: #8c8f97;\n font-size: 12px;\n line-height: 22px;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';\nimport RequestLoading from './request-loading.vue';\nimport EmptyComponent from './empty-component.vue';\n\ndefineOptions({\n name: 'InfiniteScroll'\n});\n\ninterface Props {\n /** 是否处于加载中状态 */\n loading?: boolean;\n /** 是否已加载完所有数据 */\n finished?: boolean;\n /** 是否显示空状态 */\n isEmpty?: boolean;\n /** 空状态文案 */\n emptyText?: string;\n /** 是否启用下拉刷新 */\n pullRefresh?: boolean;\n /** 下拉刷新触发距离(px) */\n pullThreshold?: number;\n /** 上拉加载触发距离(距离底部 px) */\n loadThreshold?: number;\n /** 下拉中的文案 */\n pullingText?: string;\n /** 释放刷新的文案 */\n loosingText?: string;\n /** 刷新中的文案 */\n refreshingText?: string;\n /** 加载中的文案 */\n loadingText?: string;\n /** 加载完成的文案 */\n finishedText?: string;\n /** 加载失败的文案 */\n errorText?: string;\n /** 是否显示错误状态 */\n error?: boolean;\n /** 内容区域是否显示加载状态 */\n contentLoading?: boolean;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n loading: false,\n finished: false,\n isEmpty: false,\n emptyText: '暂无数据',\n pullRefresh: false,\n pullThreshold: 70,\n loadThreshold: 50,\n pullingText: '下拉刷新',\n loosingText: '释放即可刷新',\n refreshingText: '加载中...',\n loadingText: '加载中...',\n finishedText: '没有更多了~',\n errorText: '加载失败,点击重试',\n error: false,\n contentLoading: false\n});\n\nconst emit = defineEmits<{\n /** 触发下拉刷新 */\n refresh: [];\n /** 触发上拉加载 */\n load: [];\n /** 点击错误重试 */\n retry: [];\n}>();\n\nconst containerRef = ref<HTMLElement | null>(null);\nconst contentRef = ref<HTMLElement | null>(null);\nconst indicatorRef = ref<HTMLElement | null>(null);\n\n// 下拉刷新状态\nconst pullStatus = ref<'idle' | 'pulling' | 'loosing' | 'refreshing'>('idle');\nconst pullDistance = ref(0);\n// 拖动期间禁用 transition,避免 transform 变化时被 0.25s 补间拖慢\nconst isDragging = ref(false);\n\n// 触摸相关\nlet startX = 0;\nlet startY = 0;\nlet lastDistance = 0;\n// 手势方向锁:避免横向滑动被误判为下拉\nlet gestureLock: 'none' | 'vertical' | 'horizontal' = 'none';\nconst SLOPE_LOCK_DISTANCE = 8;\n\nlet isRefreshing = false;\nlet isLoading = false;\n// 鼠标拖拽下拉(PC 端)\nlet isMouseDown = false;\n\n// 节流相关\nlet scrollTimer: number | null = null;\nlet touchMoveRaf: number | null = null;\nlet idleTimer: number | null = null;\n// 监听容器尺寸变化\nlet resizeObserver: ResizeObserver | null = null;\n// 防止空页死循环:snapshot 触发 load 时的 contentHeight,下次完成后没增长就不再 auto-load\nlet lastTriggerContentHeight = -1;\n\n// 下拉刷新核心:按下(与指针类型无关,touch/mouse 共用)\nfunction pullStart(clientX: number, clientY: number) {\n if (!props.pullRefresh || isRefreshing) return;\n startX = clientX;\n startY = clientY;\n lastDistance = 0;\n gestureLock = 'none';\n pullStatus.value = 'idle';\n}\n\n// 下拉刷新核心:移动(rAF 节流,始终使用最新位置)\n// 返回 true 表示消费了本次移动(下拉进行中),调用方据此决定是否 preventDefault\nfunction pullMove(clientX: number, clientY: number, cancelable: boolean): boolean {\n if (!props.pullRefresh || isRefreshing || startY === 0) return false;\n\n const dx = clientX - startX;\n const dy = clientY - startY;\n\n // 方向判定:先到达 8px 锁定的方向才认为有意图,垂直要明显大于水平(1.5x)\n if (gestureLock === 'none') {\n const ax = Math.abs(dx);\n const ay = Math.abs(dy);\n if (ax > SLOPE_LOCK_DISTANCE || ay > SLOPE_LOCK_DISTANCE) {\n gestureLock = ay > ax * 1.5 ? 'vertical' : 'horizontal';\n } else {\n return false;\n }\n }\n if (gestureLock === 'horizontal') return false;\n\n // 子像素容差:≤1 视为已到顶,避免 X5 内核 scrollTop 偶发非整数判断失败\n const atTop = getScrollTop() <= 1;\n\n // iOS 15- 兜底:在 atBottom 且向上拖时阻止整页 rubber-band\n // (iOS 16+ overscroll-behavior 已处理,此处兜底兼容)\n if (!atTop && dy < 0) {\n const c = containerRef.value;\n if (c) {\n const atBottom = c.scrollHeight - c.scrollTop - c.clientHeight <= 1;\n if (atBottom && cancelable) {\n return true;\n }\n }\n return false;\n }\n if (!atTop) return false;\n\n // 反向拖动也要更新(让指示器跟着手指回退),夹紧到 [0, 150]\n const clamped = Math.max(0, Math.min(dy, 150));\n\n lastDistance = clamped;\n isDragging.value = true;\n\n if (touchMoveRaf === null) {\n touchMoveRaf = requestAnimationFrame(() => {\n touchMoveRaf = null;\n pullDistance.value = lastDistance * 0.5;\n if (lastDistance === 0) {\n pullStatus.value = 'idle';\n } else {\n pullStatus.value = lastDistance > props.pullThreshold ? 'loosing' : 'pulling';\n }\n });\n }\n\n // 仅在向下拖时消费事件(避免误吞用户向上滚动的意图)\n return dy > 0;\n}\n\n// 下拉刷新核心:松开\nfunction pullEnd() {\n if (!props.pullRefresh || isRefreshing) return;\n\n // 取消待执行的 rAF,避免松手后还有一帧异步更新把 UI 拉回 loosing 卡住\n if (touchMoveRaf !== null) {\n cancelAnimationFrame(touchMoveRaf);\n touchMoveRaf = null;\n }\n\n isDragging.value = false;\n\n // 用最新的 lastDistance 同步判定,不依赖可能尚未生效的 pullStatus\n if (lastDistance > props.pullThreshold) {\n isRefreshing = true;\n pullStatus.value = 'refreshing';\n pullDistance.value = 50;\n emit('refresh');\n } else {\n pullDistance.value = 0;\n pullStatus.value = 'idle';\n }\n\n resetTouch();\n}\n\n// 下拉刷新核心:取消(回到 idle)\nfunction pullCancel() {\n if (!props.pullRefresh || isRefreshing) return;\n\n if (touchMoveRaf !== null) {\n cancelAnimationFrame(touchMoveRaf);\n touchMoveRaf = null;\n }\n\n isDragging.value = false;\n pullDistance.value = 0;\n pullStatus.value = 'idle';\n resetTouch();\n}\n\n// 下拉刷新 - touchstart\nfunction handleTouchStart(e: TouchEvent) {\n pullStart(e.touches[0].clientX, e.touches[0].clientY);\n}\n\n// 下拉刷新 - touchmove\nfunction handleTouchMove(e: TouchEvent) {\n const touch = e.touches[0];\n if (pullMove(touch.clientX, touch.clientY, e.cancelable) && e.cancelable) {\n e.preventDefault();\n }\n}\n\n// 下拉刷新 - touchend\nfunction handleTouchEnd() {\n pullEnd();\n}\n\n// 下拉刷新 - touchcancel(微信 X5 内核会在系统手势介入时派发 cancel 而非 end)\nfunction handleTouchCancel() {\n pullCancel();\n}\n\n// 下拉刷新 - mousedown(PC 端鼠标拖拽)\nfunction handleMouseDown(e: MouseEvent) {\n // 仅左键触发\n if (!props.pullRefresh || isRefreshing || e.button !== 0) return;\n isMouseDown = true;\n pullStart(e.clientX, e.clientY);\n}\n\n// 下拉刷新 - mousemove(挂在 window 上,允许拖出容器)\nfunction handleMouseMove(e: MouseEvent) {\n if (!isMouseDown) return;\n if (pullMove(e.clientX, e.clientY, true)) {\n // 阻止拖拽时选中文本\n e.preventDefault();\n }\n}\n\n// 下拉刷新 - mouseup\nfunction handleMouseUp() {\n if (!isMouseDown) return;\n isMouseDown = false;\n pullEnd();\n}\n\nfunction resetTouch() {\n startX = 0;\n startY = 0;\n lastDistance = 0;\n gestureLock = 'none';\n}\n\n// 上拉加载 - scroll(节流处理)\nfunction handleScroll() {\n if (props.loading || props.finished || props.error || isLoading) return;\n if (scrollTimer) return;\n\n scrollTimer = window.setTimeout(() => {\n scrollTimer = null;\n const container = containerRef.value;\n if (!container) return;\n\n const { scrollTop, clientHeight, scrollHeight } = container;\n const contentHeight = contentRef.value?.clientHeight || 0;\n\n // 情况1:内容不足一屏,自动触发加载\n if (contentHeight <= clientHeight) {\n // 死循环防护:上一次 auto-load 后内容没增长,不再继续触发\n if (lastTriggerContentHeight === contentHeight) return;\n lastTriggerContentHeight = contentHeight;\n // 不足一屏时主动滚到底,让 loading 指示器进入视口\n triggerLoad(true);\n return;\n }\n\n // 情况2:滚动到距离底部阈值范围内\n if (scrollHeight - scrollTop - clientHeight <= props.loadThreshold) {\n // 用户已经手动滚到底,不再强制 scrollTop(避免打断惯性滚动)\n triggerLoad(false);\n }\n }, 100);\n}\n\nfunction triggerLoad(scrollToBottom = false) {\n isLoading = true;\n emit('load');\n nextTick(() => {\n const c = containerRef.value;\n if (!c) return;\n if (scrollToBottom) {\n // 内容不足一屏:直接滚到底(没有\"惯性\"可以打断)\n c.scrollTop = c.scrollHeight;\n } else {\n // 阈值触发:用 scrollIntoView 平滑进入视口,避免突兀打断;\n // 旧 WebKit 不识别 options 会降级为即时滚动,效果等价\n indicatorRef.value?.scrollIntoView({ block: 'end', behavior: 'smooth' });\n }\n });\n}\n\n// 获取滚动距离\nfunction getScrollTop(): number {\n return containerRef.value?.scrollTop ?? 0;\n}\n\n// 完成下拉刷新\nfunction finishRefresh() {\n isRefreshing = false;\n pullDistance.value = 0;\n // 让 transform snap-back 完成后再切 idle,避免 spinner 在动画中途突然消失\n if (idleTimer !== null) clearTimeout(idleTimer);\n idleTimer = window.setTimeout(() => {\n pullStatus.value = 'idle';\n idleTimer = null;\n }, 250);\n // 重置死循环计数\n lastTriggerContentHeight = -1;\n nextTick(() => {\n checkContentHeight();\n });\n}\n\n// 完成上拉加载\nfunction finishLoad() {\n isLoading = false;\n nextTick(() => {\n const contentHeight = contentRef.value?.clientHeight || 0;\n // 内容没增长就不再触发 auto-load,避免空页死循环\n if (lastTriggerContentHeight !== -1 && contentHeight === lastTriggerContentHeight) return;\n lastTriggerContentHeight = -1;\n checkContentHeight();\n });\n}\n\n// 检查内容高度,不足一屏时自动触发加载\nfunction checkContentHeight() {\n if (props.finished || props.loading || props.error) return;\n\n nextTick(() => {\n const contentHeight = contentRef.value?.clientHeight || 0;\n const clientHeight = containerRef.value?.clientHeight || 0;\n\n if (contentHeight <= clientHeight && !isLoading) {\n handleScroll();\n }\n });\n}\n\n// 点击错误重试 — 由父组件决定具体行为,避免 retry + load 双触发\nfunction handleRetry() {\n emit('retry');\n}\n\n// loading 完成时同步重置 isLoading\nwatch(\n () => props.loading,\n newVal => {\n if (!newVal) {\n isLoading = false;\n }\n }\n);\n\n// finished 翻为 true 时重置死循环计数\nwatch(\n () => props.finished,\n newVal => {\n if (newVal) {\n lastTriggerContentHeight = -1;\n }\n }\n);\n\nonMounted(() => {\n const container = containerRef.value;\n if (!container) return;\n\n if (props.pullRefresh) {\n container.addEventListener('touchstart', handleTouchStart, { passive: true });\n container.addEventListener('touchmove', handleTouchMove, { passive: false });\n container.addEventListener('touchend', handleTouchEnd, { passive: true });\n container.addEventListener('touchcancel', handleTouchCancel, { passive: true });\n // 鼠标拖拽(PC):move/up 挂在 window 上,允许拖出容器边界\n container.addEventListener('mousedown', handleMouseDown);\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUp);\n }\n\n container.addEventListener('scroll', handleScroll, { passive: true });\n\n // 监听容器/内容尺寸变化(旋转、WebView resize、软键盘弹出收起等)\n if (typeof ResizeObserver !== 'undefined') {\n resizeObserver = new ResizeObserver(() => {\n checkContentHeight();\n });\n resizeObserver.observe(container);\n if (contentRef.value) resizeObserver.observe(contentRef.value);\n }\n\n // 初始检查内容高度\n nextTick(() => {\n checkContentHeight();\n });\n});\n\nonBeforeUnmount(() => {\n const container = containerRef.value;\n if (container) {\n container.removeEventListener('touchstart', handleTouchStart);\n container.removeEventListener('touchmove', handleTouchMove);\n container.removeEventListener('touchend', handleTouchEnd);\n container.removeEventListener('touchcancel', handleTouchCancel);\n container.removeEventListener('mousedown', handleMouseDown);\n container.removeEventListener('scroll', handleScroll);\n }\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n if (resizeObserver) {\n resizeObserver.disconnect();\n resizeObserver = null;\n }\n if (touchMoveRaf !== null) {\n cancelAnimationFrame(touchMoveRaf);\n touchMoveRaf = null;\n }\n if (scrollTimer !== null) {\n clearTimeout(scrollTimer);\n scrollTimer = null;\n }\n if (idleTimer !== null) {\n clearTimeout(idleTimer);\n idleTimer = null;\n }\n});\n\ndefineExpose({\n refresh: finishRefresh,\n finishRefresh,\n finishPullDown: finishRefresh,\n finishLoad,\n finishPullUp: finishLoad,\n checkContentHeight\n});\n</script>\n\n<template>\n <div ref=\"containerRef\" class=\"infinite-scroll\">\n <!-- 下拉刷新指示器 -->\n <div\n v-if=\"pullRefresh\"\n class=\"pull-refresh-indicator\"\n :class=\"{ 'no-transition': isDragging }\"\n :style=\"{ transform: `translateY(${pullDistance}px)` }\"\n >\n <div v-show=\"pullStatus !== 'idle'\" class=\"pull-refresh-content\">\n <!-- <RequestLoading v-if=\"pullStatus === 'refreshing'\" text=\"\" /> -->\n <span v-if=\"pullStatus === 'refreshing'\"></span>\n <span v-else-if=\"pullStatus === 'loosing'\" class=\"pull-text\">{{ loosingText }}</span>\n <span v-else class=\"pull-text\">{{ pullingText }}</span>\n </div>\n </div>\n\n <!-- 内容区域 -->\n <div\n ref=\"contentRef\"\n class=\"infinite-scroll-content\"\n :class=\"{ 'no-transition': isDragging }\"\n :style=\"pullRefresh ? { transform: `translateY(${pullDistance}px)` } : {}\"\n >\n <!-- 内容区域加载遮罩 -->\n <div v-if=\"contentLoading\" class=\"content-loading-mask\">\n <RequestLoading :text=\"refreshingText\" />\n </div>\n\n <!-- 空状态 -->\n <EmptyComponent v-if=\"isEmpty && !loading\" :text=\"emptyText\" />\n\n <!-- 默认插槽 -->\n <slot></slot>\n\n <!-- 上拉加载指示器 -->\n <div v-if=\"!isEmpty\" ref=\"indicatorRef\" class=\"load-more-indicator\">\n <RequestLoading v-if=\"loading && pullStatus !== 'refreshing'\" :text=\"loadingText\" />\n <span v-else-if=\"finished\" class=\"finished-text\">{{ finishedText }}</span>\n <span v-else-if=\"error\" class=\"error-text\" @click=\"handleRetry\">{{ errorText }}</span>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped lang=\"scss\">\n.infinite-scroll {\n height: 100%;\n position: relative;\n min-height: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n // 阻止滚动到边界时把滚动链传递给祖先(修复 iOS 16+ / 微信 X5 下拉变成整页拖拽)\n overscroll-behavior: contain;\n // 显式声明只接受纵向手势,避免被外层 touch-action 影响\n touch-action: pan-y;\n // iOS 下让原生回弹有惯性\n -webkit-overflow-scrolling: touch;\n}\n\n.pull-refresh-indicator {\n position: absolute;\n top: -50px;\n left: 0;\n right: 0;\n height: 50px;\n transition: transform 0.25s;\n\n // 拖动期间禁用过渡,让 transform 1:1 跟随手指\n &.no-transition {\n transition: none;\n }\n}\n\n.pull-refresh-content {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n font-size: 14px;\n color: #969799;\n}\n\n.pull-text {\n color: #1989fa;\n font-size: 14px;\n}\n\n.infinite-scroll-content {\n position: relative;\n transition: transform 0.25s;\n min-height: 100%;\n\n &.no-transition {\n transition: none;\n }\n}\n\n.content-loading-mask {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(255, 255, 255, 0.8);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10;\n backdrop-filter: blur(2px);\n}\n\n.load-more-indicator {\n display: flex;\n align-items: center;\n justify-content: center;\n // 预留高度避免 loading 渲染后被推到视口外造成遮挡\n min-height: 50px;\n padding: 16px 0;\n font-size: 14px;\n color: #8c8f97;\n}\n\n.finished-text {\n color: #8c8f97;\n font-size: 14px;\n}\n\n.error-text {\n color: #ee0a24;\n font-size: 14px;\n cursor: pointer;\n\n &:active {\n opacity: 0.7;\n }\n}\n</style>\n","<script setup lang=\"ts\" generic=\"T\">\nimport { type Ref, nextTick, onMounted, ref, watch } from 'vue';\nimport InfiniteScroll from './infinite-scroll.vue';\n\ndefineOptions({\n name: 'InfiniteScrollV2'\n});\n\nconst props = withDefaults(\n defineProps<{\n /** 数据请求函数,需返回 { records, total },失败时抛错 */\n fetchFn: (params: {\n page: number;\n pageSize: number;\n [key: string]: any;\n }) => Promise<{\n records: T[];\n total: number;\n }>;\n /** 业务查询参数(如筛选条件),变化时自动 reset 重新加载 */\n params?: Record<string, any>;\n /** 每页条数 */\n pageSize?: number;\n /** params 变化时是否自动重新加载 */\n autoReload?: boolean;\n /** 是否在挂载时自动加载首页 */\n immediate?: boolean;\n /** 是否启用下拉刷新 */\n pullRefresh?: boolean;\n /** 下拉刷新触发距离(px) */\n pullThreshold?: number;\n /** 上拉加载触发距离(距离底部 px) */\n loadThreshold?: number;\n /** 空状态文案 */\n emptyText?: string;\n /** 下拉中的文案 */\n pullingText?: string;\n /** 释放刷新的文案 */\n loosingText?: string;\n /** 刷新中的文案 */\n refreshingText?: string;\n /** 加载中的文案 */\n loadingText?: string;\n /** 加载完成的文案 */\n finishedText?: string;\n /** 加载失败的文案 */\n errorText?: string;\n }>(),\n {\n params: () => ({}),\n pageSize: 10,\n autoReload: true,\n immediate: true,\n pullRefresh: false,\n pullThreshold: 70,\n loadThreshold: 50,\n emptyText: '暂无数据',\n pullingText: '下拉刷新',\n loosingText: '释放即可刷新',\n refreshingText: '加载中...',\n loadingText: '加载中...',\n finishedText: '没有更多了~',\n errorText: '加载失败,点击重试'\n});\n\nconst emit = defineEmits<{\n /** 加载成功,每次成功(含分页)都会触发 */\n success: [payload: { records: T[]; total: number; reset: boolean }];\n /** 加载失败 */\n error: [err: unknown];\n /** 列表内容变化(v-model:list 支持) */\n 'update:list': [list: T[]];\n}>();\n\nconst scrollRef = ref<InstanceType<typeof InfiniteScroll> | null>(null);\n\nconst list = ref<T[]>([]) as Ref<T[]>;\nconst loading = ref(false);\nconst finished = ref(false);\nconst isEmpty = ref(false);\nconst loadError = ref(false);\nconst total = ref(0);\nconst page = ref(1);\nconst isRefreshing = ref(false);\n\nlet requestSeq = 0;\n\nasync function load(reset = false) {\n if (reset) {\n page.value = 1;\n finished.value = false;\n isEmpty.value = false;\n // 不立即清空 list,保留旧数据直到新数据到达\n }\n loading.value = true;\n loadError.value = false;\n\n requestSeq += 1;\n const seq = requestSeq;\n\n try {\n const result = await props.fetchFn({\n page: page.value,\n pageSize: props.pageSize,\n ...props.params\n });\n\n if (seq !== requestSeq) return;\n\n const records = result?.records || [];\n if (reset) {\n // reset 时替换整个列表\n list.value = records;\n total.value = 0;\n } else {\n list.value = [...list.value, ...records];\n }\n total.value = Number(result?.total || 0);\n finished.value = list.value.length >= total.value;\n isEmpty.value = list.value.length === 0;\n\n emit('success', { records, total: total.value, reset });\n emit('update:list', list.value);\n } catch (err) {\n if (seq !== requestSeq) return;\n loadError.value = true;\n emit('error', err);\n } finally {\n if (seq === requestSeq) {\n loading.value = false;\n }\n }\n}\n\nasync function handleRefresh() {\n isRefreshing.value = true;\n // 先让下拉刷新指示器收回\n scrollRef.value?.finishRefresh();\n // 等待 250ms 让指示器完全收回(对应 infinite-scroll.vue 的 transition 时长)\n await new Promise<void>(resolve => {\n setTimeout(() => resolve(), 250);\n });\n // 指示器收回后再开始请求新数据\n await load(true);\n isRefreshing.value = false;\n}\n\nasync function handleLoad() {\n if (finished.value) {\n scrollRef.value?.finishLoad();\n return;\n }\n // 列表为空时是首次加载(page 已经是 1),其它情况 page++\n if (list.value.length > 0) {\n page.value += 1;\n }\n await load(false);\n scrollRef.value?.finishLoad();\n}\n\nfunction handleRetry() {\n loadError.value = false;\n if (list.value.length === 0) {\n load(true);\n } else {\n handleLoad();\n }\n}\n\nasync function reload() {\n await load(true);\n}\n\nwatch(\n () => props.params,\n () => {\n if (props.autoReload) {\n reload();\n }\n },\n { deep: true }\n);\n\nwatch(\n list,\n async () => {\n await nextTick();\n scrollRef.value?.checkContentHeight();\n },\n { deep: true }\n);\n\nonMounted(() => {\n if (props.immediate) {\n load(true);\n }\n});\n\ndefineExpose({\n /** 重新加载第一页 */\n reload,\n /** 兼容别名 */\n refresh: reload,\n /** 当前列表数据 */\n list,\n /** 加载中状态 */\n loading,\n /** 是否已加载完 */\n finished,\n /** 是否空数据 */\n isEmpty,\n /** 总条数 */\n total,\n /** 透传 v1 方法 */\n finishLoad: () => scrollRef.value?.finishLoad(),\n finishRefresh: () => scrollRef.value?.finishRefresh(),\n checkContentHeight: () => scrollRef.value?.checkContentHeight()\n});\n</script>\n\n<template>\n <InfiniteScroll\n ref=\"scrollRef\"\n :loading=\"loading\"\n :finished=\"finished\"\n :is-empty=\"isEmpty\"\n :error=\"loadError\"\n :pull-refresh=\"pullRefresh\"\n :pull-threshold=\"pullThreshold\"\n :load-threshold=\"loadThreshold\"\n :empty-text=\"emptyText\"\n :pulling-text=\"pullingText\"\n :loosing-text=\"loosingText\"\n :refreshing-text=\"refreshingText\"\n :loading-text=\"loadingText\"\n :finished-text=\"finishedText\"\n :error-text=\"errorText\"\n :content-loading=\"isRefreshing\"\n @load=\"handleLoad\"\n @refresh=\"handleRefresh\"\n @retry=\"handleRetry\"\n >\n <slot\n :list=\"list\"\n :loading=\"loading\"\n :finished=\"finished\"\n :is-empty=\"isEmpty\"\n :error=\"loadError\"\n :total=\"total\"\n :reload=\"reload\"\n />\n </InfiniteScroll>\n</template>\n","// 样式自动注入\nlet styleInjected = false;\n\nconst cssContent = `.loading-content[data-v-a890d226]{display:flex;align-items:center;justify-content:center;gap:8px;padding:6px 12px;border-radius:16px;color:#1989fa;font-size:14px}.loading-spinner[data-v-a890d226]{width:18px;height:18px;border-radius:50%;border:2.5px solid #1989fa;border-top-color:transparent;animation:spin-a890d226 .8s linear infinite}@keyframes spin-a890d226{to{transform:rotate(360deg)}}.loading-container.fullscreen[data-v-a890d226]{position:fixed;top:0;left:0;width:100%;height:100%;display:flex;align-items:center;justify-content:center;background-color:#ffffff80}.empty-wrap[data-v-3c452901]{display:flex;flex-direction:column;align-items:center}.empty-image[data-v-3c452901]{width:96px;height:80px}.empty-text[data-v-3c452901]{margin:12px 0 0;color:#8c8f97;font-size:12px;line-height:22px}.infinite-scroll[data-v-fc5e471c]{height:100%;position:relative;min-height:100%;overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;touch-action:pan-y;-webkit-overflow-scrolling:touch}.pull-refresh-indicator[data-v-fc5e471c]{position:absolute;top:-50px;left:0;right:0;height:50px;transition:transform .25s}.pull-refresh-indicator.no-transition[data-v-fc5e471c]{transition:none}.pull-refresh-content[data-v-fc5e471c]{display:flex;align-items:center;justify-content:center;height:100%;font-size:14px;color:#969799}.pull-text[data-v-fc5e471c]{color:#1989fa;font-size:14px}.infinite-scroll-content[data-v-fc5e471c]{position:relative;transition:transform .25s;min-height:100%}.infinite-scroll-content.no-transition[data-v-fc5e471c]{transition:none}.content-loading-mask[data-v-fc5e471c]{position:absolute;top:0;left:0;right:0;bottom:0;background-color:#fffc;display:flex;align-items:center;justify-content:center;z-index:10;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.load-more-indicator[data-v-fc5e471c]{display:flex;align-items:center;justify-content:center;min-height:50px;padding:16px 0;font-size:14px;color:#8c8f97}.finished-text[data-v-fc5e471c]{color:#8c8f97;font-size:14px}.error-text[data-v-fc5e471c]{color:#ee0a24;font-size:14px;cursor:pointer}.error-text[data-v-fc5e471c]:active{opacity:.7}`;\n\nexport function injectStyle() {\n if (styleInjected || typeof document === 'undefined') return;\n\n const style = document.createElement('style');\n style.setAttribute('data-source', 'zx-infinite-scroll');\n style.textContent = cssContent;\n document.head.appendChild(style);\n\n styleInjected = true;\n}\n","import { App } from 'vue';\nimport InfiniteScroll from './components/infinite-scroll.vue';\nimport InfiniteScrollV2 from './components/infinite-scroll-v2.vue';\nimport RequestLoading from './components/request-loading.vue';\nimport EmptyComponent from './components/empty-component.vue';\nimport { injectStyle } from './inject-style';\n\n// 自动注入样式(只要导入了这个包就会执行)\ninjectStyle();\n\n// 单独导出组件\nexport { InfiniteScroll, InfiniteScrollV2, RequestLoading, EmptyComponent };\n\n// Vue plugin install 函数\nexport function install(app: App) {\n app.component('InfiniteScroll', InfiniteScroll);\n app.component('InfiniteScrollV2', InfiniteScrollV2);\n app.component('RequestLoading', RequestLoading);\n app.component('EmptyComponent', EmptyComponent);\n}\n\n// 默认导出(支持 app.use() 安装)\nexport default {\n install\n};\n"],"names":["_createElementBlock","_normalizeClass","__props","_createElementVNode","_hoisted_1","_hoisted_2","_toDisplayString","defaultEmptySvg","props","wrapStyle","computed","imageSrc","_openBlock","_renderSlot","_ctx","SLOPE_LOCK_DISTANCE","emit","__emit","containerRef","ref","contentRef","indicatorRef","pullStatus","pullDistance","isDragging","startX","startY","lastDistance","gestureLock","isRefreshing","isLoading","isMouseDown","scrollTimer","touchMoveRaf","idleTimer","resizeObserver","lastTriggerContentHeight","pullStart","clientX","clientY","pullMove","cancelable","dx","dy","ax","ay","atTop","getScrollTop","c","pullEnd","resetTouch","pullCancel","handleTouchStart","handleTouchMove","touch","handleTouchEnd","handleTouchCancel","handleMouseDown","handleMouseMove","handleMouseUp","handleScroll","container","scrollTop","clientHeight","scrollHeight","contentHeight","_a","triggerLoad","scrollToBottom","nextTick","finishRefresh","checkContentHeight","finishLoad","_b","handleRetry","watch","newVal","onMounted","onBeforeUnmount","__expose","_withDirectives","_hoisted_3","_hoisted_4","_normalizeStyle","_hoisted_5","_createVNode","RequestLoading","_createBlock","EmptyComponent","_hoisted_6","scrollRef","list","loading","finished","isEmpty","loadError","total","page","requestSeq","load","reset","seq","result","records","err","handleRefresh","resolve","handleLoad","reload","InfiniteScroll","styleInjected","cssContent","injectStyle","style","install","app","InfiniteScrollV2","index"],"mappings":"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"}
|
package/dist/index.umd.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(function(p,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(p=typeof globalThis<"u"?globalThis:p||self,e(p.ZxInfiniteScroll={},p.Vue))})(this,function(p,e){"use strict";const le={class:"loading-content"},oe={class:"loading-text"},ae=e.defineComponent({name:"RequestLoading",__name:"request-loading",props:{text:{default:"加载中..."},fullscreen:{type:Boolean,default:!1}},setup(n){return(m,g)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["loading-container",{fullscreen:n.fullscreen}])},[e.createElementVNode("div",le,[g[0]||(g[0]=e.createElementVNode("span",{class:"loading-spinner"},null,-1)),e.createElementVNode("span",oe,e.toDisplayString(n.text),1)])],2))}}),I=(n,m)=>{const g=n.__vccOpts||n;for(const[o,x]of m)g[o]=x;return g},M=I(ae,[["__scopeId","data-v-d89150ba"]]),ie=["src"],re={key:0,class:"empty-text"},se="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='80' viewBox='0 0 96 80' fill='none'%3E%3Cpath d='M8 16C8 12.6863 10.6863 10 14 10H38L44 16H82C85.3137 16 88 18.6863 88 22V66C88 69.3137 85.3137 72 82 72H14C10.6863 72 8 69.3137 8 66V16Z' fill='%23E8E8E8'/%3E%3Cpath d='M8 20C8 18.3431 9.34315 17 11 17H85C86.6569 17 88 18.3431 88 20V66C88 69.3137 85.3137 72 82 72H14C10.6863 72 8 69.3137 8 66V20Z' fill='%23F5F5F5'/%3E%3Cpath d='M38 42C38 40.8954 38.8954 40 40 40H56C57.1046 40 58 40.8954 58 42V44C58 45.1046 57.1046 46 56 46H40C38.8954 46 38 45.1046 38 44V42Z' fill='%23D9D9D9'/%3E%3C/svg%3E",N=I(e.defineComponent({name:"EmptyComponent",__name:"empty-component",props:{text:{default:"暂无数据"},showText:{type:Boolean,default:!0},paddingTop:{default:168},emptyImage:{default:""}},setup(n){const m=n,g=e.computed(()=>({paddingTop:typeof m.paddingTop=="number"?`${m.paddingTop}px`:m.paddingTop})),o=e.computed(()=>m.emptyImage||se);return(x,a)=>(e.openBlock(),e.createElementBlock("div",{class:"empty-wrap",style:e.normalizeStyle(g.value)},[e.createElementVNode("img",{class:"empty-image",src:o.value,alt:""},null,8,ie),n.showText?(e.openBlock(),e.createElementBlock("p",re,[e.renderSlot(x.$slots,"default",{},()=>[e.createTextVNode(e.toDisplayString(n.text),1)],!0)])):e.createCommentVNode("",!0)],4))}}),[["__scopeId","data-v-3c452901"]]),ce={class:"pull-refresh-content"},fe={key:0},de={key:1,class:"pull-text"},ue={key:2,class:"pull-text"},he={key:0,class:"content-loading-mask"},pe={key:1,class:"finished-text"},O=8,$=I(e.defineComponent({name:"InfiniteScroll",__name:"infinite-scroll",props:{loading:{type:Boolean,default:!1},finished:{type:Boolean,default:!1},isEmpty:{type:Boolean,default:!1},emptyText:{default:"暂无数据"},pullRefresh:{type:Boolean,default:!1},pullThreshold:{default:70},loadThreshold:{default:50},pullingText:{default:"下拉刷新"},loosingText:{default:"释放即可刷新"},refreshingText:{default:"加载中..."},loadingText:{default:"加载中..."},finishedText:{default:"没有更多了~"},errorText:{default:"加载失败,点击重试"},error:{type:Boolean,default:!1},contentLoading:{type:Boolean,default:!1}},emits:["refresh","load","retry"],setup(n,{expose:m,emit:g}){const o=n,x=g,a=e.ref(null),i=e.ref(null),b=e.ref(null),r=e.ref("idle"),u=e.ref(0),y=e.ref(!1);let k=0,w=0,v=0,T="none",h=!1,R=!1,S=!1,C=null,c=null,l=null,f=null,d=-1;function z(t,s){!o.pullRefresh||h||(k=t,w=s,v=0,T="none",r.value="idle")}function X(t,s,E){if(!o.pullRefresh||h||w===0)return!1;const H=t-k,B=s-w;if(T==="none"){const L=Math.abs(H),F=Math.abs(B);if(L>O||F>O)T=F>L*1.5?"vertical":"horizontal";else return!1}if(T==="horizontal")return!1;const D=ve()<=1;if(!D&&B<0){const L=a.value;return!!(L&&L.scrollHeight-L.scrollTop-L.clientHeight<=1&&E)}return D?(v=Math.max(0,Math.min(B,150)),y.value=!0,c===null&&(c=requestAnimationFrame(()=>{c=null,u.value=v*.5,v===0?r.value="idle":r.value=v>o.pullThreshold?"loosing":"pulling"})),B>0):!1}function Z(){!o.pullRefresh||h||(c!==null&&(cancelAnimationFrame(c),c=null),y.value=!1,v>o.pullThreshold?(h=!0,r.value="refreshing",u.value=50,x("refresh")):(u.value=0,r.value="idle"),ee())}function ye(){!o.pullRefresh||h||(c!==null&&(cancelAnimationFrame(c),c=null),y.value=!1,u.value=0,r.value="idle",ee())}function _(t){z(t.touches[0].clientX,t.touches[0].clientY)}function U(t){const s=t.touches[0];X(s.clientX,s.clientY,t.cancelable)&&t.cancelable&&t.preventDefault()}function K(){Z()}function G(){ye()}function J(t){!o.pullRefresh||h||t.button!==0||(S=!0,z(t.clientX,t.clientY))}function Q(t){S&&X(t.clientX,t.clientY,!0)&&t.preventDefault()}function W(){S&&(S=!1,Z())}function ee(){k=0,w=0,v=0,T="none"}function q(){o.loading||o.finished||o.error||R||C||(C=window.setTimeout(()=>{var D;C=null;const t=a.value;if(!t)return;const{scrollTop:s,clientHeight:E,scrollHeight:H}=t,B=((D=i.value)==null?void 0:D.clientHeight)||0;if(B<=E){if(d===B)return;d=B,te(!0);return}H-s-E<=o.loadThreshold&&te(!1)},100))}function te(t=!1){R=!0,x("load"),e.nextTick(()=>{var E;const s=a.value;s&&(t?s.scrollTop=s.scrollHeight:(E=b.value)==null||E.scrollIntoView({block:"end",behavior:"smooth"}))})}function ve(){var t;return((t=a.value)==null?void 0:t.scrollTop)??0}function j(){h=!1,u.value=0,l!==null&&clearTimeout(l),l=window.setTimeout(()=>{r.value="idle",l=null},250),d=-1,e.nextTick(()=>{V()})}function ne(){R=!1,e.nextTick(()=>{var s;const t=((s=i.value)==null?void 0:s.clientHeight)||0;d!==-1&&t===d||(d=-1,V())})}function V(){o.finished||o.loading||o.error||e.nextTick(()=>{var E,H;const t=((E=i.value)==null?void 0:E.clientHeight)||0,s=((H=a.value)==null?void 0:H.clientHeight)||0;t<=s&&!R&&q()})}function Te(){x("retry")}return e.watch(()=>o.loading,t=>{t||(R=!1)}),e.watch(()=>o.finished,t=>{t&&(d=-1)}),e.onMounted(()=>{const t=a.value;t&&(o.pullRefresh&&(t.addEventListener("touchstart",_,{passive:!0}),t.addEventListener("touchmove",U,{passive:!1}),t.addEventListener("touchend",K,{passive:!0}),t.addEventListener("touchcancel",G,{passive:!0}),t.addEventListener("mousedown",J),window.addEventListener("mousemove",Q),window.addEventListener("mouseup",W)),t.addEventListener("scroll",q,{passive:!0}),typeof ResizeObserver<"u"&&(f=new ResizeObserver(()=>{V()}),f.observe(t),i.value&&f.observe(i.value)),e.nextTick(()=>{V()}))}),e.onBeforeUnmount(()=>{const t=a.value;t&&(t.removeEventListener("touchstart",_),t.removeEventListener("touchmove",U),t.removeEventListener("touchend",K),t.removeEventListener("touchcancel",G),t.removeEventListener("mousedown",J),t.removeEventListener("scroll",q)),window.removeEventListener("mousemove",Q),window.removeEventListener("mouseup",W),f&&(f.disconnect(),f=null),c!==null&&(cancelAnimationFrame(c),c=null),C!==null&&(clearTimeout(C),C=null),l!==null&&(clearTimeout(l),l=null)}),m({refresh:j,finishRefresh:j,finishPullDown:j,finishLoad:ne,finishPullUp:ne,checkContentHeight:V}),(t,s)=>(e.openBlock(),e.createElementBlock("div",{ref_key:"containerRef",ref:a,class:"infinite-scroll"},[n.pullRefresh?(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass(["pull-refresh-indicator",{"no-transition":y.value}]),style:e.normalizeStyle({transform:`translateY(${u.value}px)`})},[e.withDirectives(e.createElementVNode("div",ce,[r.value==="refreshing"?(e.openBlock(),e.createElementBlock("span",fe)):r.value==="loosing"?(e.openBlock(),e.createElementBlock("span",de,e.toDisplayString(n.loosingText),1)):(e.openBlock(),e.createElementBlock("span",ue,e.toDisplayString(n.pullingText),1))],512),[[e.vShow,r.value!=="idle"]])],6)):e.createCommentVNode("",!0),e.createElementVNode("div",{ref_key:"contentRef",ref:i,class:e.normalizeClass(["infinite-scroll-content",{"no-transition":y.value}]),style:e.normalizeStyle(n.pullRefresh?{transform:`translateY(${u.value}px)`}:{})},[n.contentLoading?(e.openBlock(),e.createElementBlock("div",he,[e.createVNode(M,{text:n.refreshingText},null,8,["text"])])):e.createCommentVNode("",!0),n.isEmpty&&!n.loading?(e.openBlock(),e.createBlock(N,{key:1,text:n.emptyText},null,8,["text"])):e.createCommentVNode("",!0),e.renderSlot(t.$slots,"default",{},void 0,!0),n.isEmpty?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock("div",{key:2,ref_key:"indicatorRef",ref:b,class:"load-more-indicator"},[n.loading&&r.value!=="refreshing"?(e.openBlock(),e.createBlock(M,{key:0,text:n.loadingText},null,8,["text"])):n.finished?(e.openBlock(),e.createElementBlock("span",pe,e.toDisplayString(n.finishedText),1)):n.error?(e.openBlock(),e.createElementBlock("span",{key:2,class:"error-text",onClick:Te},e.toDisplayString(n.errorText),1)):e.createCommentVNode("",!0)],512))],6)],512))}}),[["__scopeId","data-v-bf5ca1d9"]]),Y=e.defineComponent({name:"InfiniteScrollV2",__name:"infinite-scroll-v2",props:{fetchFn:{},params:{default:()=>({})},pageSize:{default:10},autoReload:{type:Boolean,default:!0},immediate:{type:Boolean,default:!0},pullRefresh:{type:Boolean,default:!1},pullThreshold:{default:70},loadThreshold:{default:50},emptyText:{default:"暂无数据"},pullingText:{default:"下拉刷新"},loosingText:{default:"释放即可刷新"},refreshingText:{default:"加载中..."},loadingText:{default:"加载中..."},finishedText:{default:"没有更多了~"},errorText:{default:"加载失败,点击重试"}},emits:["success","error","update:list"],setup(n,{expose:m,emit:g}){const o=n,x=g,a=e.ref(null),i=e.ref([]),b=e.ref(!1),r=e.ref(!1),u=e.ref(!1),y=e.ref(!1),k=e.ref(0),w=e.ref(1),v=e.ref(!1);let T=0;async function h(l=!1){l&&(w.value=1,r.value=!1,u.value=!1),b.value=!0,y.value=!1,T+=1;const f=T;try{const d=await o.fetchFn({page:w.value,pageSize:o.pageSize,...o.params});if(f!==T)return;const z=(d==null?void 0:d.records)||[];l?(i.value=z,k.value=0):i.value=[...i.value,...z],k.value=Number((d==null?void 0:d.total)||0),r.value=i.value.length>=k.value,u.value=i.value.length===0,x("success",{records:z,total:k.value,reset:l}),x("update:list",i.value)}catch(d){if(f!==T)return;y.value=!0,x("error",d)}finally{f===T&&(b.value=!1)}}async function R(){var l;v.value=!0,(l=a.value)==null||l.finishRefresh(),await new Promise(f=>{setTimeout(()=>f(),250)}),await h(!0),v.value=!1}async function S(){var l,f;if(r.value){(l=a.value)==null||l.finishLoad();return}i.value.length>0&&(w.value+=1),await h(!1),(f=a.value)==null||f.finishLoad()}function C(){y.value=!1,i.value.length===0?h(!0):S()}async function c(){await h(!0)}return e.watch(()=>o.params,()=>{o.autoReload&&c()},{deep:!0}),e.watch(i,async()=>{var l;await e.nextTick(),(l=a.value)==null||l.checkContentHeight()},{deep:!0}),e.onMounted(()=>{o.immediate&&h(!0)}),m({reload:c,refresh:c,list:i,loading:b,finished:r,isEmpty:u,total:k,finishLoad:()=>{var l;return(l=a.value)==null?void 0:l.finishLoad()},finishRefresh:()=>{var l;return(l=a.value)==null?void 0:l.finishRefresh()},checkContentHeight:()=>{var l;return(l=a.value)==null?void 0:l.checkContentHeight()}}),(l,f)=>(e.openBlock(),e.createBlock($,{ref_key:"scrollRef",ref:a,loading:b.value,finished:r.value,"is-empty":u.value,error:y.value,"pull-refresh":n.pullRefresh,"pull-threshold":n.pullThreshold,"load-threshold":n.loadThreshold,"empty-text":n.emptyText,"pulling-text":n.pullingText,"loosing-text":n.loosingText,"refreshing-text":n.refreshingText,"loading-text":n.loadingText,"finished-text":n.finishedText,"error-text":n.errorText,"content-loading":v.value,onLoad:S,onRefresh:R,onRetry:C},{default:e.withCtx(()=>[e.renderSlot(l.$slots,"default",{list:i.value,loading:b.value,finished:r.value,isEmpty:u.value,error:y.value,total:k.value,reload:c})]),_:3},8,["loading","finished","is-empty","error","pull-refresh","pull-threshold","load-threshold","empty-text","pulling-text","loosing-text","refreshing-text","loading-text","finished-text","error-text","content-loading"]))}});let A=!1;const me=".loading-content[data-v-d89150ba]{display:flex;align-items:center;justify-content:center;gap:8px;padding:6px 12px;border-radius:16px;color:var(--zx-primary-color, #1e5efd);font-size:14px}.loading-spinner[data-v-d89150ba]{width:18px;height:18px;border-radius:50%;border:2.5px solid var(--zx-primary-color, #1e5efd);border-top-color:transparent;animation:spin-d89150ba .8s linear infinite}@keyframes spin-d89150ba{to{transform:rotate(360deg)}}.loading-container.fullscreen[data-v-d89150ba]{position:fixed;top:0;left:0;width:100%;height:100%;display:flex;align-items:center;justify-content:center;background-color:#ffffff80}.empty-wrap[data-v-3c452901]{display:flex;flex-direction:column;align-items:center}.empty-image[data-v-3c452901]{width:96px;height:80px}.empty-text[data-v-3c452901]{margin:12px 0 0;color:#8c8f97;font-size:12px;line-height:22px}.infinite-scroll[data-v-bf5ca1d9]{height:100%;position:relative;min-height:100%;overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;touch-action:pan-y;-webkit-overflow-scrolling:touch}.pull-refresh-indicator[data-v-bf5ca1d9]{position:absolute;top:-50px;left:0;right:0;height:50px;transition:transform .25s}.pull-refresh-indicator.no-transition[data-v-bf5ca1d9]{transition:none}.pull-refresh-content[data-v-bf5ca1d9]{display:flex;align-items:center;justify-content:center;height:100%;font-size:14px;color:#969799}.pull-text[data-v-bf5ca1d9]{color:var(--zx-primary-color, #1989fa);font-size:14px}.infinite-scroll-content[data-v-bf5ca1d9]{position:relative;transition:transform .25s;min-height:100%}.infinite-scroll-content.no-transition[data-v-bf5ca1d9]{transition:none}.content-loading-mask[data-v-bf5ca1d9]{position:absolute;top:0;left:0;right:0;bottom:0;background-color:#fffc;display:flex;align-items:center;justify-content:center;z-index:10;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.load-more-indicator[data-v-bf5ca1d9]{display:flex;align-items:center;justify-content:center;min-height:50px;padding:16px 0;font-size:14px;color:#8c8f97}.finished-text[data-v-bf5ca1d9]{color:#8c8f97;font-size:14px}.error-text[data-v-bf5ca1d9]{color:#ee0a24;font-size:14px;cursor:pointer}.error-text[data-v-bf5ca1d9]:active{opacity:.7}";function ge(){if(A||typeof document>"u")return;const n=document.createElement("style");n.setAttribute("data-source","zx-infinite-scroll"),n.textContent=me,document.head.appendChild(n),A=!0}ge();function P(n){n.component("InfiniteScroll",$),n.component("InfiniteScrollV2",Y),n.component("RequestLoading",M),n.component("EmptyComponent",N)}const xe={install:P};p.EmptyComponent=N,p.InfiniteScroll=$,p.InfiniteScrollV2=Y,p.RequestLoading=M,p.default=xe,p.install=P,Object.defineProperties(p,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
|
|
1
|
+
(function(p,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(p=typeof globalThis<"u"?globalThis:p||self,e(p.ZxInfiniteScroll={},p.Vue))})(this,function(p,e){"use strict";const le={class:"loading-content"},oe={class:"loading-text"},ie=e.defineComponent({name:"RequestLoading",__name:"request-loading",props:{text:{default:"加载中..."},fullscreen:{type:Boolean,default:!1}},setup(n){return(m,g)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["loading-container",{fullscreen:n.fullscreen}])},[e.createElementVNode("div",le,[g[0]||(g[0]=e.createElementVNode("span",{class:"loading-spinner"},null,-1)),e.createElementVNode("span",oe,e.toDisplayString(n.text),1)])],2))}}),I=(n,m)=>{const g=n.__vccOpts||n;for(const[o,x]of m)g[o]=x;return g},M=I(ie,[["__scopeId","data-v-a890d226"]]),ae=["src"],re={key:0,class:"empty-text"},se="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='80' viewBox='0 0 96 80' fill='none'%3E%3Cpath d='M8 16C8 12.6863 10.6863 10 14 10H38L44 16H82C85.3137 16 88 18.6863 88 22V66C88 69.3137 85.3137 72 82 72H14C10.6863 72 8 69.3137 8 66V16Z' fill='%23E8E8E8'/%3E%3Cpath d='M8 20C8 18.3431 9.34315 17 11 17H85C86.6569 17 88 18.3431 88 20V66C88 69.3137 85.3137 72 82 72H14C10.6863 72 8 69.3137 8 66V20Z' fill='%23F5F5F5'/%3E%3Cpath d='M38 42C38 40.8954 38.8954 40 40 40H56C57.1046 40 58 40.8954 58 42V44C58 45.1046 57.1046 46 56 46H40C38.8954 46 38 45.1046 38 44V42Z' fill='%23D9D9D9'/%3E%3C/svg%3E",N=I(e.defineComponent({name:"EmptyComponent",__name:"empty-component",props:{text:{default:"暂无数据"},showText:{type:Boolean,default:!0},paddingTop:{default:168},emptyImage:{default:""}},setup(n){const m=n,g=e.computed(()=>({paddingTop:typeof m.paddingTop=="number"?`${m.paddingTop}px`:m.paddingTop})),o=e.computed(()=>m.emptyImage||se);return(x,i)=>(e.openBlock(),e.createElementBlock("div",{class:"empty-wrap",style:e.normalizeStyle(g.value)},[e.createElementVNode("img",{class:"empty-image",src:o.value,alt:""},null,8,ae),n.showText?(e.openBlock(),e.createElementBlock("p",re,[e.renderSlot(x.$slots,"default",{},()=>[e.createTextVNode(e.toDisplayString(n.text),1)],!0)])):e.createCommentVNode("",!0)],4))}}),[["__scopeId","data-v-3c452901"]]),ce={class:"pull-refresh-content"},fe={key:0},de={key:1,class:"pull-text"},ue={key:2,class:"pull-text"},he={key:0,class:"content-loading-mask"},pe={key:1,class:"finished-text"},O=8,$=I(e.defineComponent({name:"InfiniteScroll",__name:"infinite-scroll",props:{loading:{type:Boolean,default:!1},finished:{type:Boolean,default:!1},isEmpty:{type:Boolean,default:!1},emptyText:{default:"暂无数据"},pullRefresh:{type:Boolean,default:!1},pullThreshold:{default:70},loadThreshold:{default:50},pullingText:{default:"下拉刷新"},loosingText:{default:"释放即可刷新"},refreshingText:{default:"加载中..."},loadingText:{default:"加载中..."},finishedText:{default:"没有更多了~"},errorText:{default:"加载失败,点击重试"},error:{type:Boolean,default:!1},contentLoading:{type:Boolean,default:!1}},emits:["refresh","load","retry"],setup(n,{expose:m,emit:g}){const o=n,x=g,i=e.ref(null),a=e.ref(null),w=e.ref(null),r=e.ref("idle"),u=e.ref(0),y=e.ref(!1);let k=0,C=0,v=0,T="none",h=!1,S=!1,L=!1,B=null,c=null,l=null,f=null,d=-1;function H(t,s){!o.pullRefresh||h||(k=t,C=s,v=0,T="none",r.value="idle")}function X(t,s,E){if(!o.pullRefresh||h||C===0)return!1;const V=t-k,R=s-C;if(T==="none"){const b=Math.abs(V),F=Math.abs(R);if(b>O||F>O)T=F>b*1.5?"vertical":"horizontal";else return!1}if(T==="horizontal")return!1;const D=ve()<=1;if(!D&&R<0){const b=i.value;return!!(b&&b.scrollHeight-b.scrollTop-b.clientHeight<=1&&E)}return D?(v=Math.max(0,Math.min(R,150)),y.value=!0,c===null&&(c=requestAnimationFrame(()=>{c=null,u.value=v*.5,v===0?r.value="idle":r.value=v>o.pullThreshold?"loosing":"pulling"})),R>0):!1}function Z(){!o.pullRefresh||h||(c!==null&&(cancelAnimationFrame(c),c=null),y.value=!1,v>o.pullThreshold?(h=!0,r.value="refreshing",u.value=50,x("refresh")):(u.value=0,r.value="idle"),ee())}function ye(){!o.pullRefresh||h||(c!==null&&(cancelAnimationFrame(c),c=null),y.value=!1,u.value=0,r.value="idle",ee())}function _(t){H(t.touches[0].clientX,t.touches[0].clientY)}function U(t){const s=t.touches[0];X(s.clientX,s.clientY,t.cancelable)&&t.cancelable&&t.preventDefault()}function K(){Z()}function G(){ye()}function J(t){!o.pullRefresh||h||t.button!==0||(L=!0,H(t.clientX,t.clientY))}function Q(t){L&&X(t.clientX,t.clientY,!0)&&t.preventDefault()}function W(){L&&(L=!1,Z())}function ee(){k=0,C=0,v=0,T="none"}function q(){o.loading||o.finished||o.error||S||B||(B=window.setTimeout(()=>{var D;B=null;const t=i.value;if(!t)return;const{scrollTop:s,clientHeight:E,scrollHeight:V}=t,R=((D=a.value)==null?void 0:D.clientHeight)||0;if(R<=E){if(d===R)return;d=R,te(!0);return}V-s-E<=o.loadThreshold&&te(!1)},100))}function te(t=!1){S=!0,x("load"),e.nextTick(()=>{var E;const s=i.value;s&&(t?s.scrollTop=s.scrollHeight:(E=w.value)==null||E.scrollIntoView({block:"end",behavior:"smooth"}))})}function ve(){var t;return((t=i.value)==null?void 0:t.scrollTop)??0}function j(){h=!1,u.value=0,l!==null&&clearTimeout(l),l=window.setTimeout(()=>{r.value="idle",l=null},250),d=-1,e.nextTick(()=>{z()})}function ne(){S=!1,e.nextTick(()=>{var s;const t=((s=a.value)==null?void 0:s.clientHeight)||0;d!==-1&&t===d||(d=-1,z())})}function z(){o.finished||o.loading||o.error||e.nextTick(()=>{var E,V;const t=((E=a.value)==null?void 0:E.clientHeight)||0,s=((V=i.value)==null?void 0:V.clientHeight)||0;t<=s&&!S&&q()})}function Te(){x("retry")}return e.watch(()=>o.loading,t=>{t||(S=!1)}),e.watch(()=>o.finished,t=>{t&&(d=-1)}),e.onMounted(()=>{const t=i.value;t&&(o.pullRefresh&&(t.addEventListener("touchstart",_,{passive:!0}),t.addEventListener("touchmove",U,{passive:!1}),t.addEventListener("touchend",K,{passive:!0}),t.addEventListener("touchcancel",G,{passive:!0}),t.addEventListener("mousedown",J),window.addEventListener("mousemove",Q),window.addEventListener("mouseup",W)),t.addEventListener("scroll",q,{passive:!0}),typeof ResizeObserver<"u"&&(f=new ResizeObserver(()=>{z()}),f.observe(t),a.value&&f.observe(a.value)),e.nextTick(()=>{z()}))}),e.onBeforeUnmount(()=>{const t=i.value;t&&(t.removeEventListener("touchstart",_),t.removeEventListener("touchmove",U),t.removeEventListener("touchend",K),t.removeEventListener("touchcancel",G),t.removeEventListener("mousedown",J),t.removeEventListener("scroll",q)),window.removeEventListener("mousemove",Q),window.removeEventListener("mouseup",W),f&&(f.disconnect(),f=null),c!==null&&(cancelAnimationFrame(c),c=null),B!==null&&(clearTimeout(B),B=null),l!==null&&(clearTimeout(l),l=null)}),m({refresh:j,finishRefresh:j,finishPullDown:j,finishLoad:ne,finishPullUp:ne,checkContentHeight:z}),(t,s)=>(e.openBlock(),e.createElementBlock("div",{ref_key:"containerRef",ref:i,class:"infinite-scroll"},[n.pullRefresh?(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass(["pull-refresh-indicator",{"no-transition":y.value}]),style:e.normalizeStyle({transform:`translateY(${u.value}px)`})},[e.withDirectives(e.createElementVNode("div",ce,[r.value==="refreshing"?(e.openBlock(),e.createElementBlock("span",fe)):r.value==="loosing"?(e.openBlock(),e.createElementBlock("span",de,e.toDisplayString(n.loosingText),1)):(e.openBlock(),e.createElementBlock("span",ue,e.toDisplayString(n.pullingText),1))],512),[[e.vShow,r.value!=="idle"]])],6)):e.createCommentVNode("",!0),e.createElementVNode("div",{ref_key:"contentRef",ref:a,class:e.normalizeClass(["infinite-scroll-content",{"no-transition":y.value}]),style:e.normalizeStyle(n.pullRefresh?{transform:`translateY(${u.value}px)`}:{})},[n.contentLoading?(e.openBlock(),e.createElementBlock("div",he,[e.createVNode(M,{text:n.refreshingText},null,8,["text"])])):e.createCommentVNode("",!0),n.isEmpty&&!n.loading?(e.openBlock(),e.createBlock(N,{key:1,text:n.emptyText},null,8,["text"])):e.createCommentVNode("",!0),e.renderSlot(t.$slots,"default",{},void 0,!0),n.isEmpty?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock("div",{key:2,ref_key:"indicatorRef",ref:w,class:"load-more-indicator"},[n.loading&&r.value!=="refreshing"?(e.openBlock(),e.createBlock(M,{key:0,text:n.loadingText},null,8,["text"])):n.finished?(e.openBlock(),e.createElementBlock("span",pe,e.toDisplayString(n.finishedText),1)):n.error?(e.openBlock(),e.createElementBlock("span",{key:2,class:"error-text",onClick:Te},e.toDisplayString(n.errorText),1)):e.createCommentVNode("",!0)],512))],6)],512))}}),[["__scopeId","data-v-fc5e471c"]]),Y=e.defineComponent({name:"InfiniteScrollV2",__name:"infinite-scroll-v2",props:{fetchFn:{},params:{default:()=>({})},pageSize:{default:10},autoReload:{type:Boolean,default:!0},immediate:{type:Boolean,default:!0},pullRefresh:{type:Boolean,default:!1},pullThreshold:{default:70},loadThreshold:{default:50},emptyText:{default:"暂无数据"},pullingText:{default:"下拉刷新"},loosingText:{default:"释放即可刷新"},refreshingText:{default:"加载中..."},loadingText:{default:"加载中..."},finishedText:{default:"没有更多了~"},errorText:{default:"加载失败,点击重试"}},emits:["success","error","update:list"],setup(n,{expose:m,emit:g}){const o=n,x=g,i=e.ref(null),a=e.ref([]),w=e.ref(!1),r=e.ref(!1),u=e.ref(!1),y=e.ref(!1),k=e.ref(0),C=e.ref(1),v=e.ref(!1);let T=0;async function h(l=!1){l&&(C.value=1,r.value=!1,u.value=!1),w.value=!0,y.value=!1,T+=1;const f=T;try{const d=await o.fetchFn({page:C.value,pageSize:o.pageSize,...o.params});if(f!==T)return;const H=(d==null?void 0:d.records)||[];l?(a.value=H,k.value=0):a.value=[...a.value,...H],k.value=Number((d==null?void 0:d.total)||0),r.value=a.value.length>=k.value,u.value=a.value.length===0,x("success",{records:H,total:k.value,reset:l}),x("update:list",a.value)}catch(d){if(f!==T)return;y.value=!0,x("error",d)}finally{f===T&&(w.value=!1)}}async function S(){var l;v.value=!0,(l=i.value)==null||l.finishRefresh(),await new Promise(f=>{setTimeout(()=>f(),250)}),await h(!0),v.value=!1}async function L(){var l,f;if(r.value){(l=i.value)==null||l.finishLoad();return}a.value.length>0&&(C.value+=1),await h(!1),(f=i.value)==null||f.finishLoad()}function B(){y.value=!1,a.value.length===0?h(!0):L()}async function c(){await h(!0)}return e.watch(()=>o.params,()=>{o.autoReload&&c()},{deep:!0}),e.watch(a,async()=>{var l;await e.nextTick(),(l=i.value)==null||l.checkContentHeight()},{deep:!0}),e.onMounted(()=>{o.immediate&&h(!0)}),m({reload:c,refresh:c,list:a,loading:w,finished:r,isEmpty:u,total:k,finishLoad:()=>{var l;return(l=i.value)==null?void 0:l.finishLoad()},finishRefresh:()=>{var l;return(l=i.value)==null?void 0:l.finishRefresh()},checkContentHeight:()=>{var l;return(l=i.value)==null?void 0:l.checkContentHeight()}}),(l,f)=>(e.openBlock(),e.createBlock($,{ref_key:"scrollRef",ref:i,loading:w.value,finished:r.value,"is-empty":u.value,error:y.value,"pull-refresh":n.pullRefresh,"pull-threshold":n.pullThreshold,"load-threshold":n.loadThreshold,"empty-text":n.emptyText,"pulling-text":n.pullingText,"loosing-text":n.loosingText,"refreshing-text":n.refreshingText,"loading-text":n.loadingText,"finished-text":n.finishedText,"error-text":n.errorText,"content-loading":v.value,onLoad:L,onRefresh:S,onRetry:B},{default:e.withCtx(()=>[e.renderSlot(l.$slots,"default",{list:a.value,loading:w.value,finished:r.value,isEmpty:u.value,error:y.value,total:k.value,reload:c})]),_:3},8,["loading","finished","is-empty","error","pull-refresh","pull-threshold","load-threshold","empty-text","pulling-text","loosing-text","refreshing-text","loading-text","finished-text","error-text","content-loading"]))}});let A=!1;const me=".loading-content[data-v-a890d226]{display:flex;align-items:center;justify-content:center;gap:8px;padding:6px 12px;border-radius:16px;color:#1989fa;font-size:14px}.loading-spinner[data-v-a890d226]{width:18px;height:18px;border-radius:50%;border:2.5px solid #1989fa;border-top-color:transparent;animation:spin-a890d226 .8s linear infinite}@keyframes spin-a890d226{to{transform:rotate(360deg)}}.loading-container.fullscreen[data-v-a890d226]{position:fixed;top:0;left:0;width:100%;height:100%;display:flex;align-items:center;justify-content:center;background-color:#ffffff80}.empty-wrap[data-v-3c452901]{display:flex;flex-direction:column;align-items:center}.empty-image[data-v-3c452901]{width:96px;height:80px}.empty-text[data-v-3c452901]{margin:12px 0 0;color:#8c8f97;font-size:12px;line-height:22px}.infinite-scroll[data-v-fc5e471c]{height:100%;position:relative;min-height:100%;overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;touch-action:pan-y;-webkit-overflow-scrolling:touch}.pull-refresh-indicator[data-v-fc5e471c]{position:absolute;top:-50px;left:0;right:0;height:50px;transition:transform .25s}.pull-refresh-indicator.no-transition[data-v-fc5e471c]{transition:none}.pull-refresh-content[data-v-fc5e471c]{display:flex;align-items:center;justify-content:center;height:100%;font-size:14px;color:#969799}.pull-text[data-v-fc5e471c]{color:#1989fa;font-size:14px}.infinite-scroll-content[data-v-fc5e471c]{position:relative;transition:transform .25s;min-height:100%}.infinite-scroll-content.no-transition[data-v-fc5e471c]{transition:none}.content-loading-mask[data-v-fc5e471c]{position:absolute;top:0;left:0;right:0;bottom:0;background-color:#fffc;display:flex;align-items:center;justify-content:center;z-index:10;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.load-more-indicator[data-v-fc5e471c]{display:flex;align-items:center;justify-content:center;min-height:50px;padding:16px 0;font-size:14px;color:#8c8f97}.finished-text[data-v-fc5e471c]{color:#8c8f97;font-size:14px}.error-text[data-v-fc5e471c]{color:#ee0a24;font-size:14px;cursor:pointer}.error-text[data-v-fc5e471c]:active{opacity:.7}";function ge(){if(A||typeof document>"u")return;const n=document.createElement("style");n.setAttribute("data-source","zx-infinite-scroll"),n.textContent=me,document.head.appendChild(n),A=!0}ge();function P(n){n.component("InfiniteScroll",$),n.component("InfiniteScrollV2",Y),n.component("RequestLoading",M),n.component("EmptyComponent",N)}const xe={install:P};p.EmptyComponent=N,p.InfiniteScroll=$,p.InfiniteScrollV2=Y,p.RequestLoading=M,p.default=xe,p.install=P,Object.defineProperties(p,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
|
|
2
2
|
//# sourceMappingURL=index.umd.js.map
|
package/dist/index.umd.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.umd.js","sources":["../src/components/request-loading.vue","../src/components/empty-component.vue","../src/components/infinite-scroll.vue","../src/components/infinite-scroll-v2.vue","../src/inject-style.ts","../src/index.ts"],"sourcesContent":["<script setup lang=\"ts\">\ndefineOptions({ name: 'RequestLoading' });\n\nwithDefaults(defineProps<{ text?: string; fullscreen?: boolean }>(), {\n text: '加载中...',\n fullscreen: false\n});\n</script>\n\n<template>\n <div class=\"loading-container\" :class=\"{ fullscreen: fullscreen }\">\n <div class=\"loading-content\">\n <span class=\"loading-spinner\"></span>\n <span class=\"loading-text\">{{ text }}</span>\n </div>\n </div>\n</template>\n\n<style scoped lang=\"scss\">\n.loading-content {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 6px 12px;\n border-radius: 16px;\n color: var(--zx-primary-color, #1e5efd);\n font-size: 14px;\n}\n\n.loading-spinner {\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: 2.5px solid var(--zx-primary-color, #1e5efd);\n border-top-color: transparent;\n animation: spin 0.8s linear infinite;\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n.loading-container.fullscreen {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: rgba(255, 255, 255, 0.5);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue';\n\ndefineOptions({ name: 'EmptyComponent' });\n\ninterface Props {\n text?: string;\n showText?: boolean;\n /** 顶部间距,可传数字(px)或带单位字符串,默认 168px */\n paddingTop?: number | string;\n /** 自定义图片 URL */\n emptyImage?: string;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n text: '暂无数据',\n showText: true,\n paddingTop: 168,\n emptyImage: ''\n});\n\nconst wrapStyle = computed(() => ({\n paddingTop: typeof props.paddingTop === 'number' ? `${props.paddingTop}px` : props.paddingTop\n}));\n\n// 默认空状态 SVG(简洁的空文件夹图标)\nconst defaultEmptySvg = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='80' viewBox='0 0 96 80' fill='none'%3E%3Cpath d='M8 16C8 12.6863 10.6863 10 14 10H38L44 16H82C85.3137 16 88 18.6863 88 22V66C88 69.3137 85.3137 72 82 72H14C10.6863 72 8 69.3137 8 66V16Z' fill='%23E8E8E8'/%3E%3Cpath d='M8 20C8 18.3431 9.34315 17 11 17H85C86.6569 17 88 18.3431 88 20V66C88 69.3137 85.3137 72 82 72H14C10.6863 72 8 69.3137 8 66V20Z' fill='%23F5F5F5'/%3E%3Cpath d='M38 42C38 40.8954 38.8954 40 40 40H56C57.1046 40 58 40.8954 58 42V44C58 45.1046 57.1046 46 56 46H40C38.8954 46 38 45.1046 38 44V42Z' fill='%23D9D9D9'/%3E%3C/svg%3E`;\n\nconst imageSrc = computed(() => props.emptyImage || defaultEmptySvg);\n</script>\n\n<template>\n <div class=\"empty-wrap\" :style=\"wrapStyle\">\n <img class=\"empty-image\" :src=\"imageSrc\" alt=\"\" />\n <p v-if=\"showText\" class=\"empty-text\">\n <slot>{{ text }}</slot>\n </p>\n </div>\n</template>\n\n<style scoped lang=\"scss\">\n.empty-wrap {\n display: flex;\n flex-direction: column;\n align-items: center;\n}\n\n.empty-image {\n width: 96px;\n height: 80px;\n}\n\n.empty-text {\n margin: 12px 0 0;\n color: #8c8f97;\n font-size: 12px;\n line-height: 22px;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';\nimport RequestLoading from './request-loading.vue';\nimport EmptyComponent from './empty-component.vue';\n\ndefineOptions({\n name: 'InfiniteScroll'\n});\n\ninterface Props {\n /** 是否处于加载中状态 */\n loading?: boolean;\n /** 是否已加载完所有数据 */\n finished?: boolean;\n /** 是否显示空状态 */\n isEmpty?: boolean;\n /** 空状态文案 */\n emptyText?: string;\n /** 是否启用下拉刷新 */\n pullRefresh?: boolean;\n /** 下拉刷新触发距离(px) */\n pullThreshold?: number;\n /** 上拉加载触发距离(距离底部 px) */\n loadThreshold?: number;\n /** 下拉中的文案 */\n pullingText?: string;\n /** 释放刷新的文案 */\n loosingText?: string;\n /** 刷新中的文案 */\n refreshingText?: string;\n /** 加载中的文案 */\n loadingText?: string;\n /** 加载完成的文案 */\n finishedText?: string;\n /** 加载失败的文案 */\n errorText?: string;\n /** 是否显示错误状态 */\n error?: boolean;\n /** 内容区域是否显示加载状态 */\n contentLoading?: boolean;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n loading: false,\n finished: false,\n isEmpty: false,\n emptyText: '暂无数据',\n pullRefresh: false,\n pullThreshold: 70,\n loadThreshold: 50,\n pullingText: '下拉刷新',\n loosingText: '释放即可刷新',\n refreshingText: '加载中...',\n loadingText: '加载中...',\n finishedText: '没有更多了~',\n errorText: '加载失败,点击重试',\n error: false,\n contentLoading: false\n});\n\nconst emit = defineEmits<{\n /** 触发下拉刷新 */\n refresh: [];\n /** 触发上拉加载 */\n load: [];\n /** 点击错误重试 */\n retry: [];\n}>();\n\nconst containerRef = ref<HTMLElement | null>(null);\nconst contentRef = ref<HTMLElement | null>(null);\nconst indicatorRef = ref<HTMLElement | null>(null);\n\n// 下拉刷新状态\nconst pullStatus = ref<'idle' | 'pulling' | 'loosing' | 'refreshing'>('idle');\nconst pullDistance = ref(0);\n// 拖动期间禁用 transition,避免 transform 变化时被 0.25s 补间拖慢\nconst isDragging = ref(false);\n\n// 触摸相关\nlet startX = 0;\nlet startY = 0;\nlet lastDistance = 0;\n// 手势方向锁:避免横向滑动被误判为下拉\nlet gestureLock: 'none' | 'vertical' | 'horizontal' = 'none';\nconst SLOPE_LOCK_DISTANCE = 8;\n\nlet isRefreshing = false;\nlet isLoading = false;\n// 鼠标拖拽下拉(PC 端)\nlet isMouseDown = false;\n\n// 节流相关\nlet scrollTimer: number | null = null;\nlet touchMoveRaf: number | null = null;\nlet idleTimer: number | null = null;\n// 监听容器尺寸变化\nlet resizeObserver: ResizeObserver | null = null;\n// 防止空页死循环:snapshot 触发 load 时的 contentHeight,下次完成后没增长就不再 auto-load\nlet lastTriggerContentHeight = -1;\n\n// 下拉刷新核心:按下(与指针类型无关,touch/mouse 共用)\nfunction pullStart(clientX: number, clientY: number) {\n if (!props.pullRefresh || isRefreshing) return;\n startX = clientX;\n startY = clientY;\n lastDistance = 0;\n gestureLock = 'none';\n pullStatus.value = 'idle';\n}\n\n// 下拉刷新核心:移动(rAF 节流,始终使用最新位置)\n// 返回 true 表示消费了本次移动(下拉进行中),调用方据此决定是否 preventDefault\nfunction pullMove(clientX: number, clientY: number, cancelable: boolean): boolean {\n if (!props.pullRefresh || isRefreshing || startY === 0) return false;\n\n const dx = clientX - startX;\n const dy = clientY - startY;\n\n // 方向判定:先到达 8px 锁定的方向才认为有意图,垂直要明显大于水平(1.5x)\n if (gestureLock === 'none') {\n const ax = Math.abs(dx);\n const ay = Math.abs(dy);\n if (ax > SLOPE_LOCK_DISTANCE || ay > SLOPE_LOCK_DISTANCE) {\n gestureLock = ay > ax * 1.5 ? 'vertical' : 'horizontal';\n } else {\n return false;\n }\n }\n if (gestureLock === 'horizontal') return false;\n\n // 子像素容差:≤1 视为已到顶,避免 X5 内核 scrollTop 偶发非整数判断失败\n const atTop = getScrollTop() <= 1;\n\n // iOS 15- 兜底:在 atBottom 且向上拖时阻止整页 rubber-band\n // (iOS 16+ overscroll-behavior 已处理,此处兜底兼容)\n if (!atTop && dy < 0) {\n const c = containerRef.value;\n if (c) {\n const atBottom = c.scrollHeight - c.scrollTop - c.clientHeight <= 1;\n if (atBottom && cancelable) {\n return true;\n }\n }\n return false;\n }\n if (!atTop) return false;\n\n // 反向拖动也要更新(让指示器跟着手指回退),夹紧到 [0, 150]\n const clamped = Math.max(0, Math.min(dy, 150));\n\n lastDistance = clamped;\n isDragging.value = true;\n\n if (touchMoveRaf === null) {\n touchMoveRaf = requestAnimationFrame(() => {\n touchMoveRaf = null;\n pullDistance.value = lastDistance * 0.5;\n if (lastDistance === 0) {\n pullStatus.value = 'idle';\n } else {\n pullStatus.value = lastDistance > props.pullThreshold ? 'loosing' : 'pulling';\n }\n });\n }\n\n // 仅在向下拖时消费事件(避免误吞用户向上滚动的意图)\n return dy > 0;\n}\n\n// 下拉刷新核心:松开\nfunction pullEnd() {\n if (!props.pullRefresh || isRefreshing) return;\n\n // 取消待执行的 rAF,避免松手后还有一帧异步更新把 UI 拉回 loosing 卡住\n if (touchMoveRaf !== null) {\n cancelAnimationFrame(touchMoveRaf);\n touchMoveRaf = null;\n }\n\n isDragging.value = false;\n\n // 用最新的 lastDistance 同步判定,不依赖可能尚未生效的 pullStatus\n if (lastDistance > props.pullThreshold) {\n isRefreshing = true;\n pullStatus.value = 'refreshing';\n pullDistance.value = 50;\n emit('refresh');\n } else {\n pullDistance.value = 0;\n pullStatus.value = 'idle';\n }\n\n resetTouch();\n}\n\n// 下拉刷新核心:取消(回到 idle)\nfunction pullCancel() {\n if (!props.pullRefresh || isRefreshing) return;\n\n if (touchMoveRaf !== null) {\n cancelAnimationFrame(touchMoveRaf);\n touchMoveRaf = null;\n }\n\n isDragging.value = false;\n pullDistance.value = 0;\n pullStatus.value = 'idle';\n resetTouch();\n}\n\n// 下拉刷新 - touchstart\nfunction handleTouchStart(e: TouchEvent) {\n pullStart(e.touches[0].clientX, e.touches[0].clientY);\n}\n\n// 下拉刷新 - touchmove\nfunction handleTouchMove(e: TouchEvent) {\n const touch = e.touches[0];\n if (pullMove(touch.clientX, touch.clientY, e.cancelable) && e.cancelable) {\n e.preventDefault();\n }\n}\n\n// 下拉刷新 - touchend\nfunction handleTouchEnd() {\n pullEnd();\n}\n\n// 下拉刷新 - touchcancel(微信 X5 内核会在系统手势介入时派发 cancel 而非 end)\nfunction handleTouchCancel() {\n pullCancel();\n}\n\n// 下拉刷新 - mousedown(PC 端鼠标拖拽)\nfunction handleMouseDown(e: MouseEvent) {\n // 仅左键触发\n if (!props.pullRefresh || isRefreshing || e.button !== 0) return;\n isMouseDown = true;\n pullStart(e.clientX, e.clientY);\n}\n\n// 下拉刷新 - mousemove(挂在 window 上,允许拖出容器)\nfunction handleMouseMove(e: MouseEvent) {\n if (!isMouseDown) return;\n if (pullMove(e.clientX, e.clientY, true)) {\n // 阻止拖拽时选中文本\n e.preventDefault();\n }\n}\n\n// 下拉刷新 - mouseup\nfunction handleMouseUp() {\n if (!isMouseDown) return;\n isMouseDown = false;\n pullEnd();\n}\n\nfunction resetTouch() {\n startX = 0;\n startY = 0;\n lastDistance = 0;\n gestureLock = 'none';\n}\n\n// 上拉加载 - scroll(节流处理)\nfunction handleScroll() {\n if (props.loading || props.finished || props.error || isLoading) return;\n if (scrollTimer) return;\n\n scrollTimer = window.setTimeout(() => {\n scrollTimer = null;\n const container = containerRef.value;\n if (!container) return;\n\n const { scrollTop, clientHeight, scrollHeight } = container;\n const contentHeight = contentRef.value?.clientHeight || 0;\n\n // 情况1:内容不足一屏,自动触发加载\n if (contentHeight <= clientHeight) {\n // 死循环防护:上一次 auto-load 后内容没增长,不再继续触发\n if (lastTriggerContentHeight === contentHeight) return;\n lastTriggerContentHeight = contentHeight;\n // 不足一屏时主动滚到底,让 loading 指示器进入视口\n triggerLoad(true);\n return;\n }\n\n // 情况2:滚动到距离底部阈值范围内\n if (scrollHeight - scrollTop - clientHeight <= props.loadThreshold) {\n // 用户已经手动滚到底,不再强制 scrollTop(避免打断惯性滚动)\n triggerLoad(false);\n }\n }, 100);\n}\n\nfunction triggerLoad(scrollToBottom = false) {\n isLoading = true;\n emit('load');\n nextTick(() => {\n const c = containerRef.value;\n if (!c) return;\n if (scrollToBottom) {\n // 内容不足一屏:直接滚到底(没有\"惯性\"可以打断)\n c.scrollTop = c.scrollHeight;\n } else {\n // 阈值触发:用 scrollIntoView 平滑进入视口,避免突兀打断;\n // 旧 WebKit 不识别 options 会降级为即时滚动,效果等价\n indicatorRef.value?.scrollIntoView({ block: 'end', behavior: 'smooth' });\n }\n });\n}\n\n// 获取滚动距离\nfunction getScrollTop(): number {\n return containerRef.value?.scrollTop ?? 0;\n}\n\n// 完成下拉刷新\nfunction finishRefresh() {\n isRefreshing = false;\n pullDistance.value = 0;\n // 让 transform snap-back 完成后再切 idle,避免 spinner 在动画中途突然消失\n if (idleTimer !== null) clearTimeout(idleTimer);\n idleTimer = window.setTimeout(() => {\n pullStatus.value = 'idle';\n idleTimer = null;\n }, 250);\n // 重置死循环计数\n lastTriggerContentHeight = -1;\n nextTick(() => {\n checkContentHeight();\n });\n}\n\n// 完成上拉加载\nfunction finishLoad() {\n isLoading = false;\n nextTick(() => {\n const contentHeight = contentRef.value?.clientHeight || 0;\n // 内容没增长就不再触发 auto-load,避免空页死循环\n if (lastTriggerContentHeight !== -1 && contentHeight === lastTriggerContentHeight) return;\n lastTriggerContentHeight = -1;\n checkContentHeight();\n });\n}\n\n// 检查内容高度,不足一屏时自动触发加载\nfunction checkContentHeight() {\n if (props.finished || props.loading || props.error) return;\n\n nextTick(() => {\n const contentHeight = contentRef.value?.clientHeight || 0;\n const clientHeight = containerRef.value?.clientHeight || 0;\n\n if (contentHeight <= clientHeight && !isLoading) {\n handleScroll();\n }\n });\n}\n\n// 点击错误重试 — 由父组件决定具体行为,避免 retry + load 双触发\nfunction handleRetry() {\n emit('retry');\n}\n\n// loading 完成时同步重置 isLoading\nwatch(\n () => props.loading,\n newVal => {\n if (!newVal) {\n isLoading = false;\n }\n }\n);\n\n// finished 翻为 true 时重置死循环计数\nwatch(\n () => props.finished,\n newVal => {\n if (newVal) {\n lastTriggerContentHeight = -1;\n }\n }\n);\n\nonMounted(() => {\n const container = containerRef.value;\n if (!container) return;\n\n if (props.pullRefresh) {\n container.addEventListener('touchstart', handleTouchStart, { passive: true });\n container.addEventListener('touchmove', handleTouchMove, { passive: false });\n container.addEventListener('touchend', handleTouchEnd, { passive: true });\n container.addEventListener('touchcancel', handleTouchCancel, { passive: true });\n // 鼠标拖拽(PC):move/up 挂在 window 上,允许拖出容器边界\n container.addEventListener('mousedown', handleMouseDown);\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUp);\n }\n\n container.addEventListener('scroll', handleScroll, { passive: true });\n\n // 监听容器/内容尺寸变化(旋转、WebView resize、软键盘弹出收起等)\n if (typeof ResizeObserver !== 'undefined') {\n resizeObserver = new ResizeObserver(() => {\n checkContentHeight();\n });\n resizeObserver.observe(container);\n if (contentRef.value) resizeObserver.observe(contentRef.value);\n }\n\n // 初始检查内容高度\n nextTick(() => {\n checkContentHeight();\n });\n});\n\nonBeforeUnmount(() => {\n const container = containerRef.value;\n if (container) {\n container.removeEventListener('touchstart', handleTouchStart);\n container.removeEventListener('touchmove', handleTouchMove);\n container.removeEventListener('touchend', handleTouchEnd);\n container.removeEventListener('touchcancel', handleTouchCancel);\n container.removeEventListener('mousedown', handleMouseDown);\n container.removeEventListener('scroll', handleScroll);\n }\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n if (resizeObserver) {\n resizeObserver.disconnect();\n resizeObserver = null;\n }\n if (touchMoveRaf !== null) {\n cancelAnimationFrame(touchMoveRaf);\n touchMoveRaf = null;\n }\n if (scrollTimer !== null) {\n clearTimeout(scrollTimer);\n scrollTimer = null;\n }\n if (idleTimer !== null) {\n clearTimeout(idleTimer);\n idleTimer = null;\n }\n});\n\ndefineExpose({\n refresh: finishRefresh,\n finishRefresh,\n finishPullDown: finishRefresh,\n finishLoad,\n finishPullUp: finishLoad,\n checkContentHeight\n});\n</script>\n\n<template>\n <div ref=\"containerRef\" class=\"infinite-scroll\">\n <!-- 下拉刷新指示器 -->\n <div\n v-if=\"pullRefresh\"\n class=\"pull-refresh-indicator\"\n :class=\"{ 'no-transition': isDragging }\"\n :style=\"{ transform: `translateY(${pullDistance}px)` }\"\n >\n <div v-show=\"pullStatus !== 'idle'\" class=\"pull-refresh-content\">\n <!-- <RequestLoading v-if=\"pullStatus === 'refreshing'\" text=\"\" /> -->\n <span v-if=\"pullStatus === 'refreshing'\"></span>\n <span v-else-if=\"pullStatus === 'loosing'\" class=\"pull-text\">{{ loosingText }}</span>\n <span v-else class=\"pull-text\">{{ pullingText }}</span>\n </div>\n </div>\n\n <!-- 内容区域 -->\n <div\n ref=\"contentRef\"\n class=\"infinite-scroll-content\"\n :class=\"{ 'no-transition': isDragging }\"\n :style=\"pullRefresh ? { transform: `translateY(${pullDistance}px)` } : {}\"\n >\n <!-- 内容区域加载遮罩 -->\n <div v-if=\"contentLoading\" class=\"content-loading-mask\">\n <RequestLoading :text=\"refreshingText\" />\n </div>\n\n <!-- 空状态 -->\n <EmptyComponent v-if=\"isEmpty && !loading\" :text=\"emptyText\" />\n\n <!-- 默认插槽 -->\n <slot></slot>\n\n <!-- 上拉加载指示器 -->\n <div v-if=\"!isEmpty\" ref=\"indicatorRef\" class=\"load-more-indicator\">\n <RequestLoading v-if=\"loading && pullStatus !== 'refreshing'\" :text=\"loadingText\" />\n <span v-else-if=\"finished\" class=\"finished-text\">{{ finishedText }}</span>\n <span v-else-if=\"error\" class=\"error-text\" @click=\"handleRetry\">{{ errorText }}</span>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped lang=\"scss\">\n.infinite-scroll {\n height: 100%;\n position: relative;\n min-height: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n // 阻止滚动到边界时把滚动链传递给祖先(修复 iOS 16+ / 微信 X5 下拉变成整页拖拽)\n overscroll-behavior: contain;\n // 显式声明只接受纵向手势,避免被外层 touch-action 影响\n touch-action: pan-y;\n // iOS 下让原生回弹有惯性\n -webkit-overflow-scrolling: touch;\n}\n\n.pull-refresh-indicator {\n position: absolute;\n top: -50px;\n left: 0;\n right: 0;\n height: 50px;\n transition: transform 0.25s;\n\n // 拖动期间禁用过渡,让 transform 1:1 跟随手指\n &.no-transition {\n transition: none;\n }\n}\n\n.pull-refresh-content {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n font-size: 14px;\n color: #969799;\n}\n\n.pull-text {\n color: var(--zx-primary-color, #1989fa);\n font-size: 14px;\n}\n\n.infinite-scroll-content {\n position: relative;\n transition: transform 0.25s;\n min-height: 100%;\n\n &.no-transition {\n transition: none;\n }\n}\n\n.content-loading-mask {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(255, 255, 255, 0.8);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10;\n backdrop-filter: blur(2px);\n}\n\n.load-more-indicator {\n display: flex;\n align-items: center;\n justify-content: center;\n // 预留高度避免 loading 渲染后被推到视口外造成遮挡\n min-height: 50px;\n padding: 16px 0;\n font-size: 14px;\n color: #8c8f97;\n}\n\n.finished-text {\n color: #8c8f97;\n font-size: 14px;\n}\n\n.error-text {\n color: #ee0a24;\n font-size: 14px;\n cursor: pointer;\n\n &:active {\n opacity: 0.7;\n }\n}\n</style>\n","<script setup lang=\"ts\" generic=\"T\">\nimport { type Ref, nextTick, onMounted, ref, watch } from 'vue';\nimport InfiniteScroll from './infinite-scroll.vue';\n\ndefineOptions({\n name: 'InfiniteScrollV2'\n});\n\nconst props = withDefaults(\n defineProps<{\n /** 数据请求函数,需返回 { records, total },失败时抛错 */\n fetchFn: (params: {\n page: number;\n pageSize: number;\n [key: string]: any;\n }) => Promise<{\n records: T[];\n total: number;\n }>;\n /** 业务查询参数(如筛选条件),变化时自动 reset 重新加载 */\n params?: Record<string, any>;\n /** 每页条数 */\n pageSize?: number;\n /** params 变化时是否自动重新加载 */\n autoReload?: boolean;\n /** 是否在挂载时自动加载首页 */\n immediate?: boolean;\n /** 是否启用下拉刷新 */\n pullRefresh?: boolean;\n /** 下拉刷新触发距离(px) */\n pullThreshold?: number;\n /** 上拉加载触发距离(距离底部 px) */\n loadThreshold?: number;\n /** 空状态文案 */\n emptyText?: string;\n /** 下拉中的文案 */\n pullingText?: string;\n /** 释放刷新的文案 */\n loosingText?: string;\n /** 刷新中的文案 */\n refreshingText?: string;\n /** 加载中的文案 */\n loadingText?: string;\n /** 加载完成的文案 */\n finishedText?: string;\n /** 加载失败的文案 */\n errorText?: string;\n }>(),\n {\n params: () => ({}),\n pageSize: 10,\n autoReload: true,\n immediate: true,\n pullRefresh: false,\n pullThreshold: 70,\n loadThreshold: 50,\n emptyText: '暂无数据',\n pullingText: '下拉刷新',\n loosingText: '释放即可刷新',\n refreshingText: '加载中...',\n loadingText: '加载中...',\n finishedText: '没有更多了~',\n errorText: '加载失败,点击重试'\n});\n\nconst emit = defineEmits<{\n /** 加载成功,每次成功(含分页)都会触发 */\n success: [payload: { records: T[]; total: number; reset: boolean }];\n /** 加载失败 */\n error: [err: unknown];\n /** 列表内容变化(v-model:list 支持) */\n 'update:list': [list: T[]];\n}>();\n\nconst scrollRef = ref<InstanceType<typeof InfiniteScroll> | null>(null);\n\nconst list = ref<T[]>([]) as Ref<T[]>;\nconst loading = ref(false);\nconst finished = ref(false);\nconst isEmpty = ref(false);\nconst loadError = ref(false);\nconst total = ref(0);\nconst page = ref(1);\nconst isRefreshing = ref(false);\n\nlet requestSeq = 0;\n\nasync function load(reset = false) {\n if (reset) {\n page.value = 1;\n finished.value = false;\n isEmpty.value = false;\n // 不立即清空 list,保留旧数据直到新数据到达\n }\n loading.value = true;\n loadError.value = false;\n\n requestSeq += 1;\n const seq = requestSeq;\n\n try {\n const result = await props.fetchFn({\n page: page.value,\n pageSize: props.pageSize,\n ...props.params\n });\n\n if (seq !== requestSeq) return;\n\n const records = result?.records || [];\n if (reset) {\n // reset 时替换整个列表\n list.value = records;\n total.value = 0;\n } else {\n list.value = [...list.value, ...records];\n }\n total.value = Number(result?.total || 0);\n finished.value = list.value.length >= total.value;\n isEmpty.value = list.value.length === 0;\n\n emit('success', { records, total: total.value, reset });\n emit('update:list', list.value);\n } catch (err) {\n if (seq !== requestSeq) return;\n loadError.value = true;\n emit('error', err);\n } finally {\n if (seq === requestSeq) {\n loading.value = false;\n }\n }\n}\n\nasync function handleRefresh() {\n isRefreshing.value = true;\n // 先让下拉刷新指示器收回\n scrollRef.value?.finishRefresh();\n // 等待 250ms 让指示器完全收回(对应 infinite-scroll.vue 的 transition 时长)\n await new Promise<void>(resolve => {\n setTimeout(() => resolve(), 250);\n });\n // 指示器收回后再开始请求新数据\n await load(true);\n isRefreshing.value = false;\n}\n\nasync function handleLoad() {\n if (finished.value) {\n scrollRef.value?.finishLoad();\n return;\n }\n // 列表为空时是首次加载(page 已经是 1),其它情况 page++\n if (list.value.length > 0) {\n page.value += 1;\n }\n await load(false);\n scrollRef.value?.finishLoad();\n}\n\nfunction handleRetry() {\n loadError.value = false;\n if (list.value.length === 0) {\n load(true);\n } else {\n handleLoad();\n }\n}\n\nasync function reload() {\n await load(true);\n}\n\nwatch(\n () => props.params,\n () => {\n if (props.autoReload) {\n reload();\n }\n },\n { deep: true }\n);\n\nwatch(\n list,\n async () => {\n await nextTick();\n scrollRef.value?.checkContentHeight();\n },\n { deep: true }\n);\n\nonMounted(() => {\n if (props.immediate) {\n load(true);\n }\n});\n\ndefineExpose({\n /** 重新加载第一页 */\n reload,\n /** 兼容别名 */\n refresh: reload,\n /** 当前列表数据 */\n list,\n /** 加载中状态 */\n loading,\n /** 是否已加载完 */\n finished,\n /** 是否空数据 */\n isEmpty,\n /** 总条数 */\n total,\n /** 透传 v1 方法 */\n finishLoad: () => scrollRef.value?.finishLoad(),\n finishRefresh: () => scrollRef.value?.finishRefresh(),\n checkContentHeight: () => scrollRef.value?.checkContentHeight()\n});\n</script>\n\n<template>\n <InfiniteScroll\n ref=\"scrollRef\"\n :loading=\"loading\"\n :finished=\"finished\"\n :is-empty=\"isEmpty\"\n :error=\"loadError\"\n :pull-refresh=\"pullRefresh\"\n :pull-threshold=\"pullThreshold\"\n :load-threshold=\"loadThreshold\"\n :empty-text=\"emptyText\"\n :pulling-text=\"pullingText\"\n :loosing-text=\"loosingText\"\n :refreshing-text=\"refreshingText\"\n :loading-text=\"loadingText\"\n :finished-text=\"finishedText\"\n :error-text=\"errorText\"\n :content-loading=\"isRefreshing\"\n @load=\"handleLoad\"\n @refresh=\"handleRefresh\"\n @retry=\"handleRetry\"\n >\n <slot\n :list=\"list\"\n :loading=\"loading\"\n :finished=\"finished\"\n :is-empty=\"isEmpty\"\n :error=\"loadError\"\n :total=\"total\"\n :reload=\"reload\"\n />\n </InfiniteScroll>\n</template>\n","// 样式自动注入\nlet styleInjected = false;\n\nconst cssContent = `.loading-content[data-v-d89150ba]{display:flex;align-items:center;justify-content:center;gap:8px;padding:6px 12px;border-radius:16px;color:var(--zx-primary-color, #1e5efd);font-size:14px}.loading-spinner[data-v-d89150ba]{width:18px;height:18px;border-radius:50%;border:2.5px solid var(--zx-primary-color, #1e5efd);border-top-color:transparent;animation:spin-d89150ba .8s linear infinite}@keyframes spin-d89150ba{to{transform:rotate(360deg)}}.loading-container.fullscreen[data-v-d89150ba]{position:fixed;top:0;left:0;width:100%;height:100%;display:flex;align-items:center;justify-content:center;background-color:#ffffff80}.empty-wrap[data-v-3c452901]{display:flex;flex-direction:column;align-items:center}.empty-image[data-v-3c452901]{width:96px;height:80px}.empty-text[data-v-3c452901]{margin:12px 0 0;color:#8c8f97;font-size:12px;line-height:22px}.infinite-scroll[data-v-bf5ca1d9]{height:100%;position:relative;min-height:100%;overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;touch-action:pan-y;-webkit-overflow-scrolling:touch}.pull-refresh-indicator[data-v-bf5ca1d9]{position:absolute;top:-50px;left:0;right:0;height:50px;transition:transform .25s}.pull-refresh-indicator.no-transition[data-v-bf5ca1d9]{transition:none}.pull-refresh-content[data-v-bf5ca1d9]{display:flex;align-items:center;justify-content:center;height:100%;font-size:14px;color:#969799}.pull-text[data-v-bf5ca1d9]{color:var(--zx-primary-color, #1989fa);font-size:14px}.infinite-scroll-content[data-v-bf5ca1d9]{position:relative;transition:transform .25s;min-height:100%}.infinite-scroll-content.no-transition[data-v-bf5ca1d9]{transition:none}.content-loading-mask[data-v-bf5ca1d9]{position:absolute;top:0;left:0;right:0;bottom:0;background-color:#fffc;display:flex;align-items:center;justify-content:center;z-index:10;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.load-more-indicator[data-v-bf5ca1d9]{display:flex;align-items:center;justify-content:center;min-height:50px;padding:16px 0;font-size:14px;color:#8c8f97}.finished-text[data-v-bf5ca1d9]{color:#8c8f97;font-size:14px}.error-text[data-v-bf5ca1d9]{color:#ee0a24;font-size:14px;cursor:pointer}.error-text[data-v-bf5ca1d9]:active{opacity:.7}`;\n\nexport function injectStyle() {\n if (styleInjected || typeof document === 'undefined') return;\n\n const style = document.createElement('style');\n style.setAttribute('data-source', 'zx-infinite-scroll');\n style.textContent = cssContent;\n document.head.appendChild(style);\n\n styleInjected = true;\n}\n","import { App } from 'vue';\nimport InfiniteScroll from './components/infinite-scroll.vue';\nimport InfiniteScrollV2 from './components/infinite-scroll-v2.vue';\nimport RequestLoading from './components/request-loading.vue';\nimport EmptyComponent from './components/empty-component.vue';\nimport { injectStyle } from './inject-style';\n\n// 自动注入样式(只要导入了这个包就会执行)\ninjectStyle();\n\n// 单独导出组件\nexport { InfiniteScroll, InfiniteScrollV2, RequestLoading, EmptyComponent };\n\n// Vue plugin install 函数\nexport function install(app: App) {\n app.component('InfiniteScroll', InfiniteScroll);\n app.component('InfiniteScrollV2', InfiniteScrollV2);\n app.component('RequestLoading', RequestLoading);\n app.component('EmptyComponent', EmptyComponent);\n}\n\n// 默认导出(支持 app.use() 安装)\nexport default {\n install\n};\n"],"names":["_createElementBlock","_normalizeClass","__props","_createElementVNode","_hoisted_1","_hoisted_2","_toDisplayString","defaultEmptySvg","props","wrapStyle","computed","imageSrc","_openBlock","_renderSlot","_ctx","SLOPE_LOCK_DISTANCE","emit","__emit","containerRef","ref","contentRef","indicatorRef","pullStatus","pullDistance","isDragging","startX","startY","lastDistance","gestureLock","isRefreshing","isLoading","isMouseDown","scrollTimer","touchMoveRaf","idleTimer","resizeObserver","lastTriggerContentHeight","pullStart","clientX","clientY","pullMove","cancelable","dx","dy","ax","ay","atTop","getScrollTop","c","pullEnd","resetTouch","pullCancel","handleTouchStart","e","handleTouchMove","touch","handleTouchEnd","handleTouchCancel","handleMouseDown","handleMouseMove","handleMouseUp","handleScroll","container","scrollTop","clientHeight","scrollHeight","contentHeight","_a","triggerLoad","scrollToBottom","nextTick","finishRefresh","checkContentHeight","finishLoad","_b","handleRetry","watch","newVal","onMounted","onBeforeUnmount","__expose","_withDirectives","_hoisted_3","_hoisted_4","_normalizeStyle","_hoisted_5","_createVNode","RequestLoading","_createBlock","EmptyComponent","_hoisted_6","scrollRef","list","loading","finished","isEmpty","loadError","total","page","requestSeq","load","reset","seq","result","records","err","handleRefresh","resolve","handleLoad","reload","InfiniteScroll","styleInjected","cssContent","injectStyle","style","install","app","InfiniteScrollV2","index"],"mappings":"ifAUEA,EAAAA,mBAKM,MAAA,CALD,MAAKC,EAAAA,eAAA,CAAC,oBAAmB,CAAA,WAAuBC,EAAA,WAAU,CAAA,CAAA,GAC7DC,EAAAA,mBAGM,MAHNC,GAGM,aAFJD,EAAAA,mBAAqC,OAAA,CAA/B,MAAM,iBAAA,EAAiB,KAAA,EAAA,GAC7BA,EAAAA,mBAA4C,OAA5CE,GAA4CC,EAAAA,gBAAdJ,EAAA,IAAI,EAAA,CAAA,CAAA,mKCalCK,GAAkB,izBAZxB,MAAMC,EAAQN,EAORO,EAAYC,EAAAA,SAAS,KAAO,CAChC,WAAY,OAAOF,EAAM,YAAe,SAAW,GAAGA,EAAM,UAAU,KAAOA,EAAM,UAAA,EACnF,EAKIG,EAAWD,EAAAA,SAAS,IAAMF,EAAM,YAAcD,EAAe,8BAIjEP,EAAAA,mBAKM,MAAA,CALD,MAAM,aAAc,uBAAOS,EAAA,KAAS,CAAA,GACvCN,EAAAA,mBAAkD,MAAA,CAA7C,MAAM,cAAe,IAAKQ,EAAA,MAAU,IAAI,EAAA,aACpCT,EAAA,UAATU,EAAAA,UAAA,EAAAZ,EAAAA,mBAEI,IAFJK,GAEI,CADFQ,EAAAA,WAAuBC,sBAAvB,IAAuB,qCAAdZ,EAAA,IAAI,EAAA,CAAA,CAAA,gQCkDba,EAAsB,gnBA3C5B,MAAMP,EAAQN,EAkBRc,EAAOC,EASPC,EAAeC,EAAAA,IAAwB,IAAI,EAC3CC,EAAaD,EAAAA,IAAwB,IAAI,EACzCE,EAAeF,EAAAA,IAAwB,IAAI,EAG3CG,EAAaH,EAAAA,IAAmD,MAAM,EACtEI,EAAeJ,EAAAA,IAAI,CAAC,EAEpBK,EAAaL,EAAAA,IAAI,EAAK,EAG5B,IAAIM,EAAS,EACTC,EAAS,EACTC,EAAe,EAEfC,EAAkD,OAGlDC,EAAe,GACfC,EAAY,GAEZC,EAAc,GAGdC,EAA6B,KAC7BC,EAA8B,KAC9BC,EAA2B,KAE3BC,EAAwC,KAExCC,EAA2B,GAG/B,SAASC,EAAUC,EAAiBC,EAAiB,CAC/C,CAAC/B,EAAM,aAAeqB,IAC1BJ,EAASa,EACTZ,EAASa,EACTZ,EAAe,EACfC,EAAc,OACdN,EAAW,MAAQ,OACrB,CAIA,SAASkB,EAASF,EAAiBC,EAAiBE,EAA8B,CAChF,GAAI,CAACjC,EAAM,aAAeqB,GAAgBH,IAAW,EAAG,MAAO,GAE/D,MAAMgB,EAAKJ,EAAUb,EACfkB,EAAKJ,EAAUb,EAGrB,GAAIE,IAAgB,OAAQ,CAC1B,MAAMgB,EAAK,KAAK,IAAIF,CAAE,EAChBG,EAAK,KAAK,IAAIF,CAAE,EACtB,GAAIC,EAAK7B,GAAuB8B,EAAK9B,EACnCa,EAAciB,EAAKD,EAAK,IAAM,WAAa,iBAE3C,OAAO,EAEX,CACA,GAAIhB,IAAgB,aAAc,MAAO,GAGzC,MAAMkB,EAAQC,MAAkB,EAIhC,GAAI,CAACD,GAASH,EAAK,EAAG,CACpB,MAAMK,EAAI9B,EAAa,MACvB,MAAI,GAAA8B,GACeA,EAAE,aAAeA,EAAE,UAAYA,EAAE,cAAgB,GAClDP,EAKpB,CACA,OAAKK,GAKLnB,EAFgB,KAAK,IAAI,EAAG,KAAK,IAAIgB,EAAI,GAAG,CAAC,EAG7CnB,EAAW,MAAQ,GAEfS,IAAiB,OACnBA,EAAe,sBAAsB,IAAM,CACzCA,EAAe,KACfV,EAAa,MAAQI,EAAe,GAChCA,IAAiB,EACnBL,EAAW,MAAQ,OAEnBA,EAAW,MAAQK,EAAenB,EAAM,cAAgB,UAAY,SAExE,CAAC,GAIImC,EAAK,GArBO,EAsBrB,CAGA,SAASM,GAAU,CACb,CAACzC,EAAM,aAAeqB,IAGtBI,IAAiB,OACnB,qBAAqBA,CAAY,EACjCA,EAAe,MAGjBT,EAAW,MAAQ,GAGfG,EAAenB,EAAM,eACvBqB,EAAe,GACfP,EAAW,MAAQ,aACnBC,EAAa,MAAQ,GACrBP,EAAK,SAAS,IAEdO,EAAa,MAAQ,EACrBD,EAAW,MAAQ,QAGrB4B,GAAA,EACF,CAGA,SAASC,IAAa,CAChB,CAAC3C,EAAM,aAAeqB,IAEtBI,IAAiB,OACnB,qBAAqBA,CAAY,EACjCA,EAAe,MAGjBT,EAAW,MAAQ,GACnBD,EAAa,MAAQ,EACrBD,EAAW,MAAQ,OACnB4B,GAAA,EACF,CAGA,SAASE,EAAiBC,EAAe,CACvChB,EAAUgB,EAAE,QAAQ,CAAC,EAAE,QAASA,EAAE,QAAQ,CAAC,EAAE,OAAO,CACtD,CAGA,SAASC,EAAgBD,EAAe,CACtC,MAAME,EAAQF,EAAE,QAAQ,CAAC,EACrBb,EAASe,EAAM,QAASA,EAAM,QAASF,EAAE,UAAU,GAAKA,EAAE,YAC5DA,EAAE,eAAA,CAEN,CAGA,SAASG,GAAiB,CACxBP,EAAA,CACF,CAGA,SAASQ,GAAoB,CAC3BN,GAAA,CACF,CAGA,SAASO,EAAgBL,EAAe,CAElC,CAAC7C,EAAM,aAAeqB,GAAgBwB,EAAE,SAAW,IACvDtB,EAAc,GACdM,EAAUgB,EAAE,QAASA,EAAE,OAAO,EAChC,CAGA,SAASM,EAAgBN,EAAe,CACjCtB,GACDS,EAASa,EAAE,QAASA,EAAE,QAAS,EAAI,GAErCA,EAAE,eAAA,CAEN,CAGA,SAASO,GAAgB,CAClB7B,IACLA,EAAc,GACdkB,EAAA,EACF,CAEA,SAASC,IAAa,CACpBzB,EAAS,EACTC,EAAS,EACTC,EAAe,EACfC,EAAc,MAChB,CAGA,SAASiC,GAAe,CAClBrD,EAAM,SAAWA,EAAM,UAAYA,EAAM,OAASsB,GAClDE,IAEJA,EAAc,OAAO,WAAW,IAAM,OACpCA,EAAc,KACd,MAAM8B,EAAY5C,EAAa,MAC/B,GAAI,CAAC4C,EAAW,OAEhB,KAAM,CAAE,UAAAC,EAAW,aAAAC,EAAc,aAAAC,CAAA,EAAiBH,EAC5CI,IAAgBC,EAAA/C,EAAW,QAAX,YAAA+C,EAAkB,eAAgB,EAGxD,GAAID,GAAiBF,EAAc,CAEjC,GAAI5B,IAA6B8B,EAAe,OAChD9B,EAA2B8B,EAE3BE,GAAY,EAAI,EAChB,MACF,CAGIH,EAAeF,EAAYC,GAAgBxD,EAAM,eAEnD4D,GAAY,EAAK,CAErB,EAAG,GAAG,EACR,CAEA,SAASA,GAAYC,EAAiB,GAAO,CAC3CvC,EAAY,GACZd,EAAK,MAAM,EACXsD,EAAAA,SAAS,IAAM,OACb,MAAMtB,EAAI9B,EAAa,MAClB8B,IACDqB,EAEFrB,EAAE,UAAYA,EAAE,cAIhBmB,EAAA9C,EAAa,QAAb,MAAA8C,EAAoB,eAAe,CAAE,MAAO,MAAO,SAAU,WAEjE,CAAC,CACH,CAGA,SAASpB,IAAuB,OAC9B,QAAOoB,EAAAjD,EAAa,QAAb,YAAAiD,EAAoB,YAAa,CAC1C,CAGA,SAASI,GAAgB,CACvB1C,EAAe,GACfN,EAAa,MAAQ,EAEjBW,IAAc,MAAM,aAAaA,CAAS,EAC9CA,EAAY,OAAO,WAAW,IAAM,CAClCZ,EAAW,MAAQ,OACnBY,EAAY,IACd,EAAG,GAAG,EAENE,EAA2B,GAC3BkC,EAAAA,SAAS,IAAM,CACbE,EAAA,CACF,CAAC,CACH,CAGA,SAASC,IAAa,CACpB3C,EAAY,GACZwC,EAAAA,SAAS,IAAM,OACb,MAAMJ,IAAgBC,EAAA/C,EAAW,QAAX,YAAA+C,EAAkB,eAAgB,EAEpD/B,IAA6B,IAAM8B,IAAkB9B,IACzDA,EAA2B,GAC3BoC,EAAA,EACF,CAAC,CACH,CAGA,SAASA,GAAqB,CACxBhE,EAAM,UAAYA,EAAM,SAAWA,EAAM,OAE7C8D,EAAAA,SAAS,IAAM,SACb,MAAMJ,IAAgBC,EAAA/C,EAAW,QAAX,YAAA+C,EAAkB,eAAgB,EAClDH,IAAeU,EAAAxD,EAAa,QAAb,YAAAwD,EAAoB,eAAgB,EAErDR,GAAiBF,GAAgB,CAAClC,GACpC+B,EAAA,CAEJ,CAAC,CACH,CAGA,SAASc,IAAc,CACrB3D,EAAK,OAAO,CACd,CAGA4D,OAAAA,EAAAA,MACE,IAAMpE,EAAM,QACZqE,GAAU,CACHA,IACH/C,EAAY,GAEhB,CAAA,EAIF8C,EAAAA,MACE,IAAMpE,EAAM,SACZqE,GAAU,CACJA,IACFzC,EAA2B,GAE/B,CAAA,EAGF0C,EAAAA,UAAU,IAAM,CACd,MAAMhB,EAAY5C,EAAa,MAC1B4C,IAEDtD,EAAM,cACRsD,EAAU,iBAAiB,aAAcV,EAAkB,CAAE,QAAS,GAAM,EAC5EU,EAAU,iBAAiB,YAAaR,EAAiB,CAAE,QAAS,GAAO,EAC3EQ,EAAU,iBAAiB,WAAYN,EAAgB,CAAE,QAAS,GAAM,EACxEM,EAAU,iBAAiB,cAAeL,EAAmB,CAAE,QAAS,GAAM,EAE9EK,EAAU,iBAAiB,YAAaJ,CAAe,EACvD,OAAO,iBAAiB,YAAaC,CAAe,EACpD,OAAO,iBAAiB,UAAWC,CAAa,GAGlDE,EAAU,iBAAiB,SAAUD,EAAc,CAAE,QAAS,GAAM,EAGhE,OAAO,eAAmB,MAC5B1B,EAAiB,IAAI,eAAe,IAAM,CACxCqC,EAAA,CACF,CAAC,EACDrC,EAAe,QAAQ2B,CAAS,EAC5B1C,EAAW,OAAOe,EAAe,QAAQf,EAAW,KAAK,GAI/DkD,EAAAA,SAAS,IAAM,CACbE,EAAA,CACF,CAAC,EACH,CAAC,EAEDO,EAAAA,gBAAgB,IAAM,CACpB,MAAMjB,EAAY5C,EAAa,MAC3B4C,IACFA,EAAU,oBAAoB,aAAcV,CAAgB,EAC5DU,EAAU,oBAAoB,YAAaR,CAAe,EAC1DQ,EAAU,oBAAoB,WAAYN,CAAc,EACxDM,EAAU,oBAAoB,cAAeL,CAAiB,EAC9DK,EAAU,oBAAoB,YAAaJ,CAAe,EAC1DI,EAAU,oBAAoB,SAAUD,CAAY,GAEtD,OAAO,oBAAoB,YAAaF,CAAe,EACvD,OAAO,oBAAoB,UAAWC,CAAa,EAC/CzB,IACFA,EAAe,WAAA,EACfA,EAAiB,MAEfF,IAAiB,OACnB,qBAAqBA,CAAY,EACjCA,EAAe,MAEbD,IAAgB,OAClB,aAAaA,CAAW,EACxBA,EAAc,MAEZE,IAAc,OAChB,aAAaA,CAAS,EACtBA,EAAY,KAEhB,CAAC,EAED8C,EAAa,CACX,QAAST,EACT,cAAAA,EACA,eAAgBA,EAChB,WAAAE,GACA,aAAcA,GACd,mBAAAD,CAAA,CACD,wBAICxE,EAAAA,mBAyCM,MAAA,SAzCG,eAAJ,IAAIkB,EAAe,MAAM,iBAAA,GAGpBhB,EAAA,2BADRF,EAAAA,mBAYM,MAAA,OAVJ,MAAKC,EAAAA,eAAA,CAAC,yBAAwB,CAAA,gBACHuB,EAAA,KAAA,CAAU,CAAA,EACpC,gDAAkCD,EAAA,KAAY,MAAA,CAAA,GAE/C0D,iBAAA9E,EAAAA,mBAKM,MALNC,GAKM,CAHQkB,EAAA,QAAU,4BAAtBtB,EAAAA,mBAAgD,OAAAK,EAAA,GAC/BiB,EAAA,QAAU,yBAA3BtB,EAAAA,mBAAqF,OAArFkF,GAAqF5E,EAAAA,gBAArBJ,EAAA,WAAW,EAAA,CAAA,kBAC3EF,EAAAA,mBAAuD,OAAvDmF,GAAuD7E,EAAAA,gBAArBJ,EAAA,WAAW,EAAA,CAAA,EAAA,iBAJlCoB,EAAA,QAAU,MAAA,CAAA,oCASzBnB,EAAAA,mBAuBM,MAAA,SAtBA,aAAJ,IAAIiB,EACJ,MAAKnB,EAAAA,eAAA,CAAC,0BAAyB,CAAA,gBACJuB,EAAA,KAAA,CAAU,CAAA,EACpC,MAAK4D,EAAAA,eAAElF,EAAA,YAAW,CAAA,UAAA,cAA8BqB,EAAA,KAAY,KAAA,EAAA,CAAA,CAAA,CAAA,GAGlDrB,EAAA,gBAAXU,EAAAA,UAAA,EAAAZ,EAAAA,mBAEM,MAFNqF,GAEM,CADJC,cAAyCC,EAAA,CAAxB,KAAMrF,EAAA,cAAA,EAAc,KAAA,EAAA,CAAA,MAAA,CAAA,CAAA,gCAIjBA,EAAA,UAAYA,EAAA,uBAAlCsF,EAAAA,YAA+DC,EAAA,OAAnB,KAAMvF,EAAA,SAAA,gDAGlDW,EAAAA,WAAaC,EAAA,OAAA,UAAA,CAAA,EAAA,OAAA,EAAA,EAGDZ,EAAA,mDAAZF,EAAAA,mBAIM,MAAA,eAJmB,eAAJ,IAAIqB,EAAe,MAAM,qBAAA,GACtBnB,EAAA,SAAWoB,EAAA,QAAU,4BAA3CkE,EAAAA,YAAoFD,EAAA,OAArB,KAAMrF,EAAA,WAAA,oBACpDA,EAAA,wBAAjBF,EAAAA,mBAA0E,OAA1E0F,GAA0EpF,EAAAA,gBAAtBJ,EAAA,YAAY,EAAA,CAAA,GAC/CA,EAAA,qBAAjBF,EAAAA,mBAAsF,OAAA,OAA9D,MAAM,aAAc,QAAO2E,EAAA,oBAAgBzE,EAAA,SAAS,EAAA,CAAA,mqBCzepF,MAAMM,EAAQN,EAyDRc,EAAOC,EASP0E,EAAYxE,EAAAA,IAAgD,IAAI,EAEhEyE,EAAOzE,EAAAA,IAAS,EAAE,EAClB0E,EAAU1E,EAAAA,IAAI,EAAK,EACnB2E,EAAW3E,EAAAA,IAAI,EAAK,EACpB4E,EAAU5E,EAAAA,IAAI,EAAK,EACnB6E,EAAY7E,EAAAA,IAAI,EAAK,EACrB8E,EAAQ9E,EAAAA,IAAI,CAAC,EACb+E,EAAO/E,EAAAA,IAAI,CAAC,EACZU,EAAeV,EAAAA,IAAI,EAAK,EAE9B,IAAIgF,EAAa,EAEjB,eAAeC,EAAKC,EAAQ,GAAO,CAC7BA,IACFH,EAAK,MAAQ,EACbJ,EAAS,MAAQ,GACjBC,EAAQ,MAAQ,IAGlBF,EAAQ,MAAQ,GAChBG,EAAU,MAAQ,GAElBG,GAAc,EACd,MAAMG,EAAMH,EAEZ,GAAI,CACF,MAAMI,EAAS,MAAM/F,EAAM,QAAQ,CACjC,KAAM0F,EAAK,MACX,SAAU1F,EAAM,SAChB,GAAGA,EAAM,MAAA,CACV,EAED,GAAI8F,IAAQH,EAAY,OAExB,MAAMK,GAAUD,GAAA,YAAAA,EAAQ,UAAW,CAAA,EAC/BF,GAEFT,EAAK,MAAQY,EACbP,EAAM,MAAQ,GAEdL,EAAK,MAAQ,CAAC,GAAGA,EAAK,MAAO,GAAGY,CAAO,EAEzCP,EAAM,MAAQ,QAAOM,GAAA,YAAAA,EAAQ,QAAS,CAAC,EACvCT,EAAS,MAAQF,EAAK,MAAM,QAAUK,EAAM,MAC5CF,EAAQ,MAAQH,EAAK,MAAM,SAAW,EAEtC5E,EAAK,UAAW,CAAE,QAAAwF,EAAS,MAAOP,EAAM,MAAO,MAAAI,EAAO,EACtDrF,EAAK,cAAe4E,EAAK,KAAK,CAChC,OAASa,EAAK,CACZ,GAAIH,IAAQH,EAAY,OACxBH,EAAU,MAAQ,GAClBhF,EAAK,QAASyF,CAAG,CACnB,QAAA,CACMH,IAAQH,IACVN,EAAQ,MAAQ,GAEpB,CACF,CAEA,eAAea,GAAgB,OAC7B7E,EAAa,MAAQ,IAErBsC,EAAAwB,EAAU,QAAV,MAAAxB,EAAiB,gBAEjB,MAAM,IAAI,QAAcwC,GAAW,CACjC,WAAW,IAAMA,EAAA,EAAW,GAAG,CACjC,CAAC,EAED,MAAMP,EAAK,EAAI,EACfvE,EAAa,MAAQ,EACvB,CAEA,eAAe+E,GAAa,SAC1B,GAAId,EAAS,MAAO,EAClB3B,EAAAwB,EAAU,QAAV,MAAAxB,EAAiB,aACjB,MACF,CAEIyB,EAAK,MAAM,OAAS,IACtBM,EAAK,OAAS,GAEhB,MAAME,EAAK,EAAK,GAChB1B,EAAAiB,EAAU,QAAV,MAAAjB,EAAiB,YACnB,CAEA,SAASC,GAAc,CACrBqB,EAAU,MAAQ,GACdJ,EAAK,MAAM,SAAW,EACxBQ,EAAK,EAAI,EAETQ,EAAA,CAEJ,CAEA,eAAeC,GAAS,CACtB,MAAMT,EAAK,EAAI,CACjB,CAEAxB,OAAAA,EAAAA,MACE,IAAMpE,EAAM,OACZ,IAAM,CACAA,EAAM,YACRqG,EAAA,CAEJ,EACA,CAAE,KAAM,EAAA,CAAK,EAGfjC,EAAAA,MACEgB,EACA,SAAY,OACV,MAAMtB,WAAA,GACNH,EAAAwB,EAAU,QAAV,MAAAxB,EAAiB,oBACnB,EACA,CAAE,KAAM,EAAA,CAAK,EAGfW,EAAAA,UAAU,IAAM,CACVtE,EAAM,WACR4F,EAAK,EAAI,CAEb,CAAC,EAEDpB,EAAa,CAEX,OAAA6B,EAEA,QAASA,EAET,KAAAjB,EAEA,QAAAC,EAEA,SAAAC,EAEA,QAAAC,EAEA,MAAAE,EAEA,WAAY,IAAA,OAAM,OAAA9B,EAAAwB,EAAU,QAAV,YAAAxB,EAAiB,cACnC,cAAe,IAAA,OAAM,OAAAA,EAAAwB,EAAU,QAAV,YAAAxB,EAAiB,iBACtC,mBAAoB,IAAA,OAAM,OAAAA,EAAAwB,EAAU,QAAV,YAAAxB,EAAiB,qBAAmB,CAC/D,wBAICqB,EAAAA,YA8BiBsB,EAAA,SA7BX,YAAJ,IAAInB,EACH,QAASE,EAAA,MACT,SAAUC,EAAA,MACV,WAAUC,EAAA,MACV,MAAOC,EAAA,MACP,eAAc9F,EAAA,YACd,iBAAgBA,EAAA,cAChB,iBAAgBA,EAAA,cAChB,aAAYA,EAAA,UACZ,eAAcA,EAAA,YACd,eAAcA,EAAA,YACd,kBAAiBA,EAAA,eACjB,eAAcA,EAAA,YACd,gBAAeA,EAAA,aACf,aAAYA,EAAA,UACZ,kBAAiB2B,EAAA,MACjB,OAAM+E,EACN,UAASF,EACT,QAAO/B,CAAA,qBAER,IAQE,CARF9D,aAQEC,EAAA,OAAA,UAAA,CAPC,KAAM8E,EAAA,MACN,QAASC,EAAA,MACT,SAAUC,EAAA,MACV,QAAUC,EAAA,MACV,MAAOC,EAAA,MACP,MAAOC,EAAA,MACP,OAAAY,CAAA,uOCxPP,IAAIE,EAAgB,GAEpB,MAAMC,GAAa,upEAEZ,SAASC,IAAc,CAC5B,GAAIF,GAAiB,OAAO,SAAa,IAAa,OAEtD,MAAMG,EAAQ,SAAS,cAAc,OAAO,EAC5CA,EAAM,aAAa,cAAe,oBAAoB,EACtDA,EAAM,YAAcF,GACpB,SAAS,KAAK,YAAYE,CAAK,EAE/BH,EAAgB,EAClB,CCNAE,GAAA,EAMO,SAASE,EAAQC,EAAU,CAChCA,EAAI,UAAU,iBAAkBN,CAAc,EAC9CM,EAAI,UAAU,mBAAoBC,CAAgB,EAClDD,EAAI,UAAU,iBAAkB7B,CAAc,EAC9C6B,EAAI,UAAU,iBAAkB3B,CAAc,CAChD,CAGA,MAAA6B,GAAe,CACb,QAAAH,CACF"}
|
|
1
|
+
{"version":3,"file":"index.umd.js","sources":["../src/components/request-loading.vue","../src/components/empty-component.vue","../src/components/infinite-scroll.vue","../src/components/infinite-scroll-v2.vue","../src/inject-style.ts","../src/index.ts"],"sourcesContent":["<script setup lang=\"ts\">\ndefineOptions({ name: 'RequestLoading' });\n\nwithDefaults(defineProps<{ text?: string; fullscreen?: boolean }>(), {\n text: '加载中...',\n fullscreen: false\n});\n</script>\n\n<template>\n <div class=\"loading-container\" :class=\"{ fullscreen: fullscreen }\">\n <div class=\"loading-content\">\n <span class=\"loading-spinner\"></span>\n <span class=\"loading-text\">{{ text }}</span>\n </div>\n </div>\n</template>\n\n<style scoped lang=\"scss\">\n.loading-content {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 6px 12px;\n border-radius: 16px;\n color: #1989fa;\n font-size: 14px;\n}\n\n.loading-spinner {\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: 2.5px solid #1989fa;\n border-top-color: transparent;\n animation: spin 0.8s linear infinite;\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n.loading-container.fullscreen {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: rgba(255, 255, 255, 0.5);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue';\n\ndefineOptions({ name: 'EmptyComponent' });\n\ninterface Props {\n text?: string;\n showText?: boolean;\n /** 顶部间距,可传数字(px)或带单位字符串,默认 168px */\n paddingTop?: number | string;\n /** 自定义图片 URL */\n emptyImage?: string;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n text: '暂无数据',\n showText: true,\n paddingTop: 168,\n emptyImage: ''\n});\n\nconst wrapStyle = computed(() => ({\n paddingTop: typeof props.paddingTop === 'number' ? `${props.paddingTop}px` : props.paddingTop\n}));\n\n// 默认空状态 SVG(简洁的空文件夹图标)\nconst defaultEmptySvg = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='80' viewBox='0 0 96 80' fill='none'%3E%3Cpath d='M8 16C8 12.6863 10.6863 10 14 10H38L44 16H82C85.3137 16 88 18.6863 88 22V66C88 69.3137 85.3137 72 82 72H14C10.6863 72 8 69.3137 8 66V16Z' fill='%23E8E8E8'/%3E%3Cpath d='M8 20C8 18.3431 9.34315 17 11 17H85C86.6569 17 88 18.3431 88 20V66C88 69.3137 85.3137 72 82 72H14C10.6863 72 8 69.3137 8 66V20Z' fill='%23F5F5F5'/%3E%3Cpath d='M38 42C38 40.8954 38.8954 40 40 40H56C57.1046 40 58 40.8954 58 42V44C58 45.1046 57.1046 46 56 46H40C38.8954 46 38 45.1046 38 44V42Z' fill='%23D9D9D9'/%3E%3C/svg%3E`;\n\nconst imageSrc = computed(() => props.emptyImage || defaultEmptySvg);\n</script>\n\n<template>\n <div class=\"empty-wrap\" :style=\"wrapStyle\">\n <img class=\"empty-image\" :src=\"imageSrc\" alt=\"\" />\n <p v-if=\"showText\" class=\"empty-text\">\n <slot>{{ text }}</slot>\n </p>\n </div>\n</template>\n\n<style scoped lang=\"scss\">\n.empty-wrap {\n display: flex;\n flex-direction: column;\n align-items: center;\n}\n\n.empty-image {\n width: 96px;\n height: 80px;\n}\n\n.empty-text {\n margin: 12px 0 0;\n color: #8c8f97;\n font-size: 12px;\n line-height: 22px;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';\nimport RequestLoading from './request-loading.vue';\nimport EmptyComponent from './empty-component.vue';\n\ndefineOptions({\n name: 'InfiniteScroll'\n});\n\ninterface Props {\n /** 是否处于加载中状态 */\n loading?: boolean;\n /** 是否已加载完所有数据 */\n finished?: boolean;\n /** 是否显示空状态 */\n isEmpty?: boolean;\n /** 空状态文案 */\n emptyText?: string;\n /** 是否启用下拉刷新 */\n pullRefresh?: boolean;\n /** 下拉刷新触发距离(px) */\n pullThreshold?: number;\n /** 上拉加载触发距离(距离底部 px) */\n loadThreshold?: number;\n /** 下拉中的文案 */\n pullingText?: string;\n /** 释放刷新的文案 */\n loosingText?: string;\n /** 刷新中的文案 */\n refreshingText?: string;\n /** 加载中的文案 */\n loadingText?: string;\n /** 加载完成的文案 */\n finishedText?: string;\n /** 加载失败的文案 */\n errorText?: string;\n /** 是否显示错误状态 */\n error?: boolean;\n /** 内容区域是否显示加载状态 */\n contentLoading?: boolean;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n loading: false,\n finished: false,\n isEmpty: false,\n emptyText: '暂无数据',\n pullRefresh: false,\n pullThreshold: 70,\n loadThreshold: 50,\n pullingText: '下拉刷新',\n loosingText: '释放即可刷新',\n refreshingText: '加载中...',\n loadingText: '加载中...',\n finishedText: '没有更多了~',\n errorText: '加载失败,点击重试',\n error: false,\n contentLoading: false\n});\n\nconst emit = defineEmits<{\n /** 触发下拉刷新 */\n refresh: [];\n /** 触发上拉加载 */\n load: [];\n /** 点击错误重试 */\n retry: [];\n}>();\n\nconst containerRef = ref<HTMLElement | null>(null);\nconst contentRef = ref<HTMLElement | null>(null);\nconst indicatorRef = ref<HTMLElement | null>(null);\n\n// 下拉刷新状态\nconst pullStatus = ref<'idle' | 'pulling' | 'loosing' | 'refreshing'>('idle');\nconst pullDistance = ref(0);\n// 拖动期间禁用 transition,避免 transform 变化时被 0.25s 补间拖慢\nconst isDragging = ref(false);\n\n// 触摸相关\nlet startX = 0;\nlet startY = 0;\nlet lastDistance = 0;\n// 手势方向锁:避免横向滑动被误判为下拉\nlet gestureLock: 'none' | 'vertical' | 'horizontal' = 'none';\nconst SLOPE_LOCK_DISTANCE = 8;\n\nlet isRefreshing = false;\nlet isLoading = false;\n// 鼠标拖拽下拉(PC 端)\nlet isMouseDown = false;\n\n// 节流相关\nlet scrollTimer: number | null = null;\nlet touchMoveRaf: number | null = null;\nlet idleTimer: number | null = null;\n// 监听容器尺寸变化\nlet resizeObserver: ResizeObserver | null = null;\n// 防止空页死循环:snapshot 触发 load 时的 contentHeight,下次完成后没增长就不再 auto-load\nlet lastTriggerContentHeight = -1;\n\n// 下拉刷新核心:按下(与指针类型无关,touch/mouse 共用)\nfunction pullStart(clientX: number, clientY: number) {\n if (!props.pullRefresh || isRefreshing) return;\n startX = clientX;\n startY = clientY;\n lastDistance = 0;\n gestureLock = 'none';\n pullStatus.value = 'idle';\n}\n\n// 下拉刷新核心:移动(rAF 节流,始终使用最新位置)\n// 返回 true 表示消费了本次移动(下拉进行中),调用方据此决定是否 preventDefault\nfunction pullMove(clientX: number, clientY: number, cancelable: boolean): boolean {\n if (!props.pullRefresh || isRefreshing || startY === 0) return false;\n\n const dx = clientX - startX;\n const dy = clientY - startY;\n\n // 方向判定:先到达 8px 锁定的方向才认为有意图,垂直要明显大于水平(1.5x)\n if (gestureLock === 'none') {\n const ax = Math.abs(dx);\n const ay = Math.abs(dy);\n if (ax > SLOPE_LOCK_DISTANCE || ay > SLOPE_LOCK_DISTANCE) {\n gestureLock = ay > ax * 1.5 ? 'vertical' : 'horizontal';\n } else {\n return false;\n }\n }\n if (gestureLock === 'horizontal') return false;\n\n // 子像素容差:≤1 视为已到顶,避免 X5 内核 scrollTop 偶发非整数判断失败\n const atTop = getScrollTop() <= 1;\n\n // iOS 15- 兜底:在 atBottom 且向上拖时阻止整页 rubber-band\n // (iOS 16+ overscroll-behavior 已处理,此处兜底兼容)\n if (!atTop && dy < 0) {\n const c = containerRef.value;\n if (c) {\n const atBottom = c.scrollHeight - c.scrollTop - c.clientHeight <= 1;\n if (atBottom && cancelable) {\n return true;\n }\n }\n return false;\n }\n if (!atTop) return false;\n\n // 反向拖动也要更新(让指示器跟着手指回退),夹紧到 [0, 150]\n const clamped = Math.max(0, Math.min(dy, 150));\n\n lastDistance = clamped;\n isDragging.value = true;\n\n if (touchMoveRaf === null) {\n touchMoveRaf = requestAnimationFrame(() => {\n touchMoveRaf = null;\n pullDistance.value = lastDistance * 0.5;\n if (lastDistance === 0) {\n pullStatus.value = 'idle';\n } else {\n pullStatus.value = lastDistance > props.pullThreshold ? 'loosing' : 'pulling';\n }\n });\n }\n\n // 仅在向下拖时消费事件(避免误吞用户向上滚动的意图)\n return dy > 0;\n}\n\n// 下拉刷新核心:松开\nfunction pullEnd() {\n if (!props.pullRefresh || isRefreshing) return;\n\n // 取消待执行的 rAF,避免松手后还有一帧异步更新把 UI 拉回 loosing 卡住\n if (touchMoveRaf !== null) {\n cancelAnimationFrame(touchMoveRaf);\n touchMoveRaf = null;\n }\n\n isDragging.value = false;\n\n // 用最新的 lastDistance 同步判定,不依赖可能尚未生效的 pullStatus\n if (lastDistance > props.pullThreshold) {\n isRefreshing = true;\n pullStatus.value = 'refreshing';\n pullDistance.value = 50;\n emit('refresh');\n } else {\n pullDistance.value = 0;\n pullStatus.value = 'idle';\n }\n\n resetTouch();\n}\n\n// 下拉刷新核心:取消(回到 idle)\nfunction pullCancel() {\n if (!props.pullRefresh || isRefreshing) return;\n\n if (touchMoveRaf !== null) {\n cancelAnimationFrame(touchMoveRaf);\n touchMoveRaf = null;\n }\n\n isDragging.value = false;\n pullDistance.value = 0;\n pullStatus.value = 'idle';\n resetTouch();\n}\n\n// 下拉刷新 - touchstart\nfunction handleTouchStart(e: TouchEvent) {\n pullStart(e.touches[0].clientX, e.touches[0].clientY);\n}\n\n// 下拉刷新 - touchmove\nfunction handleTouchMove(e: TouchEvent) {\n const touch = e.touches[0];\n if (pullMove(touch.clientX, touch.clientY, e.cancelable) && e.cancelable) {\n e.preventDefault();\n }\n}\n\n// 下拉刷新 - touchend\nfunction handleTouchEnd() {\n pullEnd();\n}\n\n// 下拉刷新 - touchcancel(微信 X5 内核会在系统手势介入时派发 cancel 而非 end)\nfunction handleTouchCancel() {\n pullCancel();\n}\n\n// 下拉刷新 - mousedown(PC 端鼠标拖拽)\nfunction handleMouseDown(e: MouseEvent) {\n // 仅左键触发\n if (!props.pullRefresh || isRefreshing || e.button !== 0) return;\n isMouseDown = true;\n pullStart(e.clientX, e.clientY);\n}\n\n// 下拉刷新 - mousemove(挂在 window 上,允许拖出容器)\nfunction handleMouseMove(e: MouseEvent) {\n if (!isMouseDown) return;\n if (pullMove(e.clientX, e.clientY, true)) {\n // 阻止拖拽时选中文本\n e.preventDefault();\n }\n}\n\n// 下拉刷新 - mouseup\nfunction handleMouseUp() {\n if (!isMouseDown) return;\n isMouseDown = false;\n pullEnd();\n}\n\nfunction resetTouch() {\n startX = 0;\n startY = 0;\n lastDistance = 0;\n gestureLock = 'none';\n}\n\n// 上拉加载 - scroll(节流处理)\nfunction handleScroll() {\n if (props.loading || props.finished || props.error || isLoading) return;\n if (scrollTimer) return;\n\n scrollTimer = window.setTimeout(() => {\n scrollTimer = null;\n const container = containerRef.value;\n if (!container) return;\n\n const { scrollTop, clientHeight, scrollHeight } = container;\n const contentHeight = contentRef.value?.clientHeight || 0;\n\n // 情况1:内容不足一屏,自动触发加载\n if (contentHeight <= clientHeight) {\n // 死循环防护:上一次 auto-load 后内容没增长,不再继续触发\n if (lastTriggerContentHeight === contentHeight) return;\n lastTriggerContentHeight = contentHeight;\n // 不足一屏时主动滚到底,让 loading 指示器进入视口\n triggerLoad(true);\n return;\n }\n\n // 情况2:滚动到距离底部阈值范围内\n if (scrollHeight - scrollTop - clientHeight <= props.loadThreshold) {\n // 用户已经手动滚到底,不再强制 scrollTop(避免打断惯性滚动)\n triggerLoad(false);\n }\n }, 100);\n}\n\nfunction triggerLoad(scrollToBottom = false) {\n isLoading = true;\n emit('load');\n nextTick(() => {\n const c = containerRef.value;\n if (!c) return;\n if (scrollToBottom) {\n // 内容不足一屏:直接滚到底(没有\"惯性\"可以打断)\n c.scrollTop = c.scrollHeight;\n } else {\n // 阈值触发:用 scrollIntoView 平滑进入视口,避免突兀打断;\n // 旧 WebKit 不识别 options 会降级为即时滚动,效果等价\n indicatorRef.value?.scrollIntoView({ block: 'end', behavior: 'smooth' });\n }\n });\n}\n\n// 获取滚动距离\nfunction getScrollTop(): number {\n return containerRef.value?.scrollTop ?? 0;\n}\n\n// 完成下拉刷新\nfunction finishRefresh() {\n isRefreshing = false;\n pullDistance.value = 0;\n // 让 transform snap-back 完成后再切 idle,避免 spinner 在动画中途突然消失\n if (idleTimer !== null) clearTimeout(idleTimer);\n idleTimer = window.setTimeout(() => {\n pullStatus.value = 'idle';\n idleTimer = null;\n }, 250);\n // 重置死循环计数\n lastTriggerContentHeight = -1;\n nextTick(() => {\n checkContentHeight();\n });\n}\n\n// 完成上拉加载\nfunction finishLoad() {\n isLoading = false;\n nextTick(() => {\n const contentHeight = contentRef.value?.clientHeight || 0;\n // 内容没增长就不再触发 auto-load,避免空页死循环\n if (lastTriggerContentHeight !== -1 && contentHeight === lastTriggerContentHeight) return;\n lastTriggerContentHeight = -1;\n checkContentHeight();\n });\n}\n\n// 检查内容高度,不足一屏时自动触发加载\nfunction checkContentHeight() {\n if (props.finished || props.loading || props.error) return;\n\n nextTick(() => {\n const contentHeight = contentRef.value?.clientHeight || 0;\n const clientHeight = containerRef.value?.clientHeight || 0;\n\n if (contentHeight <= clientHeight && !isLoading) {\n handleScroll();\n }\n });\n}\n\n// 点击错误重试 — 由父组件决定具体行为,避免 retry + load 双触发\nfunction handleRetry() {\n emit('retry');\n}\n\n// loading 完成时同步重置 isLoading\nwatch(\n () => props.loading,\n newVal => {\n if (!newVal) {\n isLoading = false;\n }\n }\n);\n\n// finished 翻为 true 时重置死循环计数\nwatch(\n () => props.finished,\n newVal => {\n if (newVal) {\n lastTriggerContentHeight = -1;\n }\n }\n);\n\nonMounted(() => {\n const container = containerRef.value;\n if (!container) return;\n\n if (props.pullRefresh) {\n container.addEventListener('touchstart', handleTouchStart, { passive: true });\n container.addEventListener('touchmove', handleTouchMove, { passive: false });\n container.addEventListener('touchend', handleTouchEnd, { passive: true });\n container.addEventListener('touchcancel', handleTouchCancel, { passive: true });\n // 鼠标拖拽(PC):move/up 挂在 window 上,允许拖出容器边界\n container.addEventListener('mousedown', handleMouseDown);\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUp);\n }\n\n container.addEventListener('scroll', handleScroll, { passive: true });\n\n // 监听容器/内容尺寸变化(旋转、WebView resize、软键盘弹出收起等)\n if (typeof ResizeObserver !== 'undefined') {\n resizeObserver = new ResizeObserver(() => {\n checkContentHeight();\n });\n resizeObserver.observe(container);\n if (contentRef.value) resizeObserver.observe(contentRef.value);\n }\n\n // 初始检查内容高度\n nextTick(() => {\n checkContentHeight();\n });\n});\n\nonBeforeUnmount(() => {\n const container = containerRef.value;\n if (container) {\n container.removeEventListener('touchstart', handleTouchStart);\n container.removeEventListener('touchmove', handleTouchMove);\n container.removeEventListener('touchend', handleTouchEnd);\n container.removeEventListener('touchcancel', handleTouchCancel);\n container.removeEventListener('mousedown', handleMouseDown);\n container.removeEventListener('scroll', handleScroll);\n }\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n if (resizeObserver) {\n resizeObserver.disconnect();\n resizeObserver = null;\n }\n if (touchMoveRaf !== null) {\n cancelAnimationFrame(touchMoveRaf);\n touchMoveRaf = null;\n }\n if (scrollTimer !== null) {\n clearTimeout(scrollTimer);\n scrollTimer = null;\n }\n if (idleTimer !== null) {\n clearTimeout(idleTimer);\n idleTimer = null;\n }\n});\n\ndefineExpose({\n refresh: finishRefresh,\n finishRefresh,\n finishPullDown: finishRefresh,\n finishLoad,\n finishPullUp: finishLoad,\n checkContentHeight\n});\n</script>\n\n<template>\n <div ref=\"containerRef\" class=\"infinite-scroll\">\n <!-- 下拉刷新指示器 -->\n <div\n v-if=\"pullRefresh\"\n class=\"pull-refresh-indicator\"\n :class=\"{ 'no-transition': isDragging }\"\n :style=\"{ transform: `translateY(${pullDistance}px)` }\"\n >\n <div v-show=\"pullStatus !== 'idle'\" class=\"pull-refresh-content\">\n <!-- <RequestLoading v-if=\"pullStatus === 'refreshing'\" text=\"\" /> -->\n <span v-if=\"pullStatus === 'refreshing'\"></span>\n <span v-else-if=\"pullStatus === 'loosing'\" class=\"pull-text\">{{ loosingText }}</span>\n <span v-else class=\"pull-text\">{{ pullingText }}</span>\n </div>\n </div>\n\n <!-- 内容区域 -->\n <div\n ref=\"contentRef\"\n class=\"infinite-scroll-content\"\n :class=\"{ 'no-transition': isDragging }\"\n :style=\"pullRefresh ? { transform: `translateY(${pullDistance}px)` } : {}\"\n >\n <!-- 内容区域加载遮罩 -->\n <div v-if=\"contentLoading\" class=\"content-loading-mask\">\n <RequestLoading :text=\"refreshingText\" />\n </div>\n\n <!-- 空状态 -->\n <EmptyComponent v-if=\"isEmpty && !loading\" :text=\"emptyText\" />\n\n <!-- 默认插槽 -->\n <slot></slot>\n\n <!-- 上拉加载指示器 -->\n <div v-if=\"!isEmpty\" ref=\"indicatorRef\" class=\"load-more-indicator\">\n <RequestLoading v-if=\"loading && pullStatus !== 'refreshing'\" :text=\"loadingText\" />\n <span v-else-if=\"finished\" class=\"finished-text\">{{ finishedText }}</span>\n <span v-else-if=\"error\" class=\"error-text\" @click=\"handleRetry\">{{ errorText }}</span>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped lang=\"scss\">\n.infinite-scroll {\n height: 100%;\n position: relative;\n min-height: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n // 阻止滚动到边界时把滚动链传递给祖先(修复 iOS 16+ / 微信 X5 下拉变成整页拖拽)\n overscroll-behavior: contain;\n // 显式声明只接受纵向手势,避免被外层 touch-action 影响\n touch-action: pan-y;\n // iOS 下让原生回弹有惯性\n -webkit-overflow-scrolling: touch;\n}\n\n.pull-refresh-indicator {\n position: absolute;\n top: -50px;\n left: 0;\n right: 0;\n height: 50px;\n transition: transform 0.25s;\n\n // 拖动期间禁用过渡,让 transform 1:1 跟随手指\n &.no-transition {\n transition: none;\n }\n}\n\n.pull-refresh-content {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n font-size: 14px;\n color: #969799;\n}\n\n.pull-text {\n color: #1989fa;\n font-size: 14px;\n}\n\n.infinite-scroll-content {\n position: relative;\n transition: transform 0.25s;\n min-height: 100%;\n\n &.no-transition {\n transition: none;\n }\n}\n\n.content-loading-mask {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(255, 255, 255, 0.8);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10;\n backdrop-filter: blur(2px);\n}\n\n.load-more-indicator {\n display: flex;\n align-items: center;\n justify-content: center;\n // 预留高度避免 loading 渲染后被推到视口外造成遮挡\n min-height: 50px;\n padding: 16px 0;\n font-size: 14px;\n color: #8c8f97;\n}\n\n.finished-text {\n color: #8c8f97;\n font-size: 14px;\n}\n\n.error-text {\n color: #ee0a24;\n font-size: 14px;\n cursor: pointer;\n\n &:active {\n opacity: 0.7;\n }\n}\n</style>\n","<script setup lang=\"ts\" generic=\"T\">\nimport { type Ref, nextTick, onMounted, ref, watch } from 'vue';\nimport InfiniteScroll from './infinite-scroll.vue';\n\ndefineOptions({\n name: 'InfiniteScrollV2'\n});\n\nconst props = withDefaults(\n defineProps<{\n /** 数据请求函数,需返回 { records, total },失败时抛错 */\n fetchFn: (params: {\n page: number;\n pageSize: number;\n [key: string]: any;\n }) => Promise<{\n records: T[];\n total: number;\n }>;\n /** 业务查询参数(如筛选条件),变化时自动 reset 重新加载 */\n params?: Record<string, any>;\n /** 每页条数 */\n pageSize?: number;\n /** params 变化时是否自动重新加载 */\n autoReload?: boolean;\n /** 是否在挂载时自动加载首页 */\n immediate?: boolean;\n /** 是否启用下拉刷新 */\n pullRefresh?: boolean;\n /** 下拉刷新触发距离(px) */\n pullThreshold?: number;\n /** 上拉加载触发距离(距离底部 px) */\n loadThreshold?: number;\n /** 空状态文案 */\n emptyText?: string;\n /** 下拉中的文案 */\n pullingText?: string;\n /** 释放刷新的文案 */\n loosingText?: string;\n /** 刷新中的文案 */\n refreshingText?: string;\n /** 加载中的文案 */\n loadingText?: string;\n /** 加载完成的文案 */\n finishedText?: string;\n /** 加载失败的文案 */\n errorText?: string;\n }>(),\n {\n params: () => ({}),\n pageSize: 10,\n autoReload: true,\n immediate: true,\n pullRefresh: false,\n pullThreshold: 70,\n loadThreshold: 50,\n emptyText: '暂无数据',\n pullingText: '下拉刷新',\n loosingText: '释放即可刷新',\n refreshingText: '加载中...',\n loadingText: '加载中...',\n finishedText: '没有更多了~',\n errorText: '加载失败,点击重试'\n});\n\nconst emit = defineEmits<{\n /** 加载成功,每次成功(含分页)都会触发 */\n success: [payload: { records: T[]; total: number; reset: boolean }];\n /** 加载失败 */\n error: [err: unknown];\n /** 列表内容变化(v-model:list 支持) */\n 'update:list': [list: T[]];\n}>();\n\nconst scrollRef = ref<InstanceType<typeof InfiniteScroll> | null>(null);\n\nconst list = ref<T[]>([]) as Ref<T[]>;\nconst loading = ref(false);\nconst finished = ref(false);\nconst isEmpty = ref(false);\nconst loadError = ref(false);\nconst total = ref(0);\nconst page = ref(1);\nconst isRefreshing = ref(false);\n\nlet requestSeq = 0;\n\nasync function load(reset = false) {\n if (reset) {\n page.value = 1;\n finished.value = false;\n isEmpty.value = false;\n // 不立即清空 list,保留旧数据直到新数据到达\n }\n loading.value = true;\n loadError.value = false;\n\n requestSeq += 1;\n const seq = requestSeq;\n\n try {\n const result = await props.fetchFn({\n page: page.value,\n pageSize: props.pageSize,\n ...props.params\n });\n\n if (seq !== requestSeq) return;\n\n const records = result?.records || [];\n if (reset) {\n // reset 时替换整个列表\n list.value = records;\n total.value = 0;\n } else {\n list.value = [...list.value, ...records];\n }\n total.value = Number(result?.total || 0);\n finished.value = list.value.length >= total.value;\n isEmpty.value = list.value.length === 0;\n\n emit('success', { records, total: total.value, reset });\n emit('update:list', list.value);\n } catch (err) {\n if (seq !== requestSeq) return;\n loadError.value = true;\n emit('error', err);\n } finally {\n if (seq === requestSeq) {\n loading.value = false;\n }\n }\n}\n\nasync function handleRefresh() {\n isRefreshing.value = true;\n // 先让下拉刷新指示器收回\n scrollRef.value?.finishRefresh();\n // 等待 250ms 让指示器完全收回(对应 infinite-scroll.vue 的 transition 时长)\n await new Promise<void>(resolve => {\n setTimeout(() => resolve(), 250);\n });\n // 指示器收回后再开始请求新数据\n await load(true);\n isRefreshing.value = false;\n}\n\nasync function handleLoad() {\n if (finished.value) {\n scrollRef.value?.finishLoad();\n return;\n }\n // 列表为空时是首次加载(page 已经是 1),其它情况 page++\n if (list.value.length > 0) {\n page.value += 1;\n }\n await load(false);\n scrollRef.value?.finishLoad();\n}\n\nfunction handleRetry() {\n loadError.value = false;\n if (list.value.length === 0) {\n load(true);\n } else {\n handleLoad();\n }\n}\n\nasync function reload() {\n await load(true);\n}\n\nwatch(\n () => props.params,\n () => {\n if (props.autoReload) {\n reload();\n }\n },\n { deep: true }\n);\n\nwatch(\n list,\n async () => {\n await nextTick();\n scrollRef.value?.checkContentHeight();\n },\n { deep: true }\n);\n\nonMounted(() => {\n if (props.immediate) {\n load(true);\n }\n});\n\ndefineExpose({\n /** 重新加载第一页 */\n reload,\n /** 兼容别名 */\n refresh: reload,\n /** 当前列表数据 */\n list,\n /** 加载中状态 */\n loading,\n /** 是否已加载完 */\n finished,\n /** 是否空数据 */\n isEmpty,\n /** 总条数 */\n total,\n /** 透传 v1 方法 */\n finishLoad: () => scrollRef.value?.finishLoad(),\n finishRefresh: () => scrollRef.value?.finishRefresh(),\n checkContentHeight: () => scrollRef.value?.checkContentHeight()\n});\n</script>\n\n<template>\n <InfiniteScroll\n ref=\"scrollRef\"\n :loading=\"loading\"\n :finished=\"finished\"\n :is-empty=\"isEmpty\"\n :error=\"loadError\"\n :pull-refresh=\"pullRefresh\"\n :pull-threshold=\"pullThreshold\"\n :load-threshold=\"loadThreshold\"\n :empty-text=\"emptyText\"\n :pulling-text=\"pullingText\"\n :loosing-text=\"loosingText\"\n :refreshing-text=\"refreshingText\"\n :loading-text=\"loadingText\"\n :finished-text=\"finishedText\"\n :error-text=\"errorText\"\n :content-loading=\"isRefreshing\"\n @load=\"handleLoad\"\n @refresh=\"handleRefresh\"\n @retry=\"handleRetry\"\n >\n <slot\n :list=\"list\"\n :loading=\"loading\"\n :finished=\"finished\"\n :is-empty=\"isEmpty\"\n :error=\"loadError\"\n :total=\"total\"\n :reload=\"reload\"\n />\n </InfiniteScroll>\n</template>\n","// 样式自动注入\nlet styleInjected = false;\n\nconst cssContent = `.loading-content[data-v-a890d226]{display:flex;align-items:center;justify-content:center;gap:8px;padding:6px 12px;border-radius:16px;color:#1989fa;font-size:14px}.loading-spinner[data-v-a890d226]{width:18px;height:18px;border-radius:50%;border:2.5px solid #1989fa;border-top-color:transparent;animation:spin-a890d226 .8s linear infinite}@keyframes spin-a890d226{to{transform:rotate(360deg)}}.loading-container.fullscreen[data-v-a890d226]{position:fixed;top:0;left:0;width:100%;height:100%;display:flex;align-items:center;justify-content:center;background-color:#ffffff80}.empty-wrap[data-v-3c452901]{display:flex;flex-direction:column;align-items:center}.empty-image[data-v-3c452901]{width:96px;height:80px}.empty-text[data-v-3c452901]{margin:12px 0 0;color:#8c8f97;font-size:12px;line-height:22px}.infinite-scroll[data-v-fc5e471c]{height:100%;position:relative;min-height:100%;overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;touch-action:pan-y;-webkit-overflow-scrolling:touch}.pull-refresh-indicator[data-v-fc5e471c]{position:absolute;top:-50px;left:0;right:0;height:50px;transition:transform .25s}.pull-refresh-indicator.no-transition[data-v-fc5e471c]{transition:none}.pull-refresh-content[data-v-fc5e471c]{display:flex;align-items:center;justify-content:center;height:100%;font-size:14px;color:#969799}.pull-text[data-v-fc5e471c]{color:#1989fa;font-size:14px}.infinite-scroll-content[data-v-fc5e471c]{position:relative;transition:transform .25s;min-height:100%}.infinite-scroll-content.no-transition[data-v-fc5e471c]{transition:none}.content-loading-mask[data-v-fc5e471c]{position:absolute;top:0;left:0;right:0;bottom:0;background-color:#fffc;display:flex;align-items:center;justify-content:center;z-index:10;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.load-more-indicator[data-v-fc5e471c]{display:flex;align-items:center;justify-content:center;min-height:50px;padding:16px 0;font-size:14px;color:#8c8f97}.finished-text[data-v-fc5e471c]{color:#8c8f97;font-size:14px}.error-text[data-v-fc5e471c]{color:#ee0a24;font-size:14px;cursor:pointer}.error-text[data-v-fc5e471c]:active{opacity:.7}`;\n\nexport function injectStyle() {\n if (styleInjected || typeof document === 'undefined') return;\n\n const style = document.createElement('style');\n style.setAttribute('data-source', 'zx-infinite-scroll');\n style.textContent = cssContent;\n document.head.appendChild(style);\n\n styleInjected = true;\n}\n","import { App } from 'vue';\nimport InfiniteScroll from './components/infinite-scroll.vue';\nimport InfiniteScrollV2 from './components/infinite-scroll-v2.vue';\nimport RequestLoading from './components/request-loading.vue';\nimport EmptyComponent from './components/empty-component.vue';\nimport { injectStyle } from './inject-style';\n\n// 自动注入样式(只要导入了这个包就会执行)\ninjectStyle();\n\n// 单独导出组件\nexport { InfiniteScroll, InfiniteScrollV2, RequestLoading, EmptyComponent };\n\n// Vue plugin install 函数\nexport function install(app: App) {\n app.component('InfiniteScroll', InfiniteScroll);\n app.component('InfiniteScrollV2', InfiniteScrollV2);\n app.component('RequestLoading', RequestLoading);\n app.component('EmptyComponent', EmptyComponent);\n}\n\n// 默认导出(支持 app.use() 安装)\nexport default {\n install\n};\n"],"names":["_createElementBlock","_normalizeClass","__props","_createElementVNode","_hoisted_1","_hoisted_2","_toDisplayString","defaultEmptySvg","props","wrapStyle","computed","imageSrc","_openBlock","_renderSlot","_ctx","SLOPE_LOCK_DISTANCE","emit","__emit","containerRef","ref","contentRef","indicatorRef","pullStatus","pullDistance","isDragging","startX","startY","lastDistance","gestureLock","isRefreshing","isLoading","isMouseDown","scrollTimer","touchMoveRaf","idleTimer","resizeObserver","lastTriggerContentHeight","pullStart","clientX","clientY","pullMove","cancelable","dx","dy","ax","ay","atTop","getScrollTop","c","pullEnd","resetTouch","pullCancel","handleTouchStart","e","handleTouchMove","touch","handleTouchEnd","handleTouchCancel","handleMouseDown","handleMouseMove","handleMouseUp","handleScroll","container","scrollTop","clientHeight","scrollHeight","contentHeight","_a","triggerLoad","scrollToBottom","nextTick","finishRefresh","checkContentHeight","finishLoad","_b","handleRetry","watch","newVal","onMounted","onBeforeUnmount","__expose","_withDirectives","_hoisted_3","_hoisted_4","_normalizeStyle","_hoisted_5","_createVNode","RequestLoading","_createBlock","EmptyComponent","_hoisted_6","scrollRef","list","loading","finished","isEmpty","loadError","total","page","requestSeq","load","reset","seq","result","records","err","handleRefresh","resolve","handleLoad","reload","InfiniteScroll","styleInjected","cssContent","injectStyle","style","install","app","InfiniteScrollV2","index"],"mappings":"ifAUEA,EAAAA,mBAKM,MAAA,CALD,MAAKC,EAAAA,eAAA,CAAC,oBAAmB,CAAA,WAAuBC,EAAA,WAAU,CAAA,CAAA,GAC7DC,EAAAA,mBAGM,MAHNC,GAGM,aAFJD,EAAAA,mBAAqC,OAAA,CAA/B,MAAM,iBAAA,EAAiB,KAAA,EAAA,GAC7BA,EAAAA,mBAA4C,OAA5CE,GAA4CC,EAAAA,gBAAdJ,EAAA,IAAI,EAAA,CAAA,CAAA,mKCalCK,GAAkB,izBAZxB,MAAMC,EAAQN,EAORO,EAAYC,EAAAA,SAAS,KAAO,CAChC,WAAY,OAAOF,EAAM,YAAe,SAAW,GAAGA,EAAM,UAAU,KAAOA,EAAM,UAAA,EACnF,EAKIG,EAAWD,EAAAA,SAAS,IAAMF,EAAM,YAAcD,EAAe,8BAIjEP,EAAAA,mBAKM,MAAA,CALD,MAAM,aAAc,uBAAOS,EAAA,KAAS,CAAA,GACvCN,EAAAA,mBAAkD,MAAA,CAA7C,MAAM,cAAe,IAAKQ,EAAA,MAAU,IAAI,EAAA,aACpCT,EAAA,UAATU,EAAAA,UAAA,EAAAZ,EAAAA,mBAEI,IAFJK,GAEI,CADFQ,EAAAA,WAAuBC,sBAAvB,IAAuB,qCAAdZ,EAAA,IAAI,EAAA,CAAA,CAAA,gQCkDba,EAAsB,gnBA3C5B,MAAMP,EAAQN,EAkBRc,EAAOC,EASPC,EAAeC,EAAAA,IAAwB,IAAI,EAC3CC,EAAaD,EAAAA,IAAwB,IAAI,EACzCE,EAAeF,EAAAA,IAAwB,IAAI,EAG3CG,EAAaH,EAAAA,IAAmD,MAAM,EACtEI,EAAeJ,EAAAA,IAAI,CAAC,EAEpBK,EAAaL,EAAAA,IAAI,EAAK,EAG5B,IAAIM,EAAS,EACTC,EAAS,EACTC,EAAe,EAEfC,EAAkD,OAGlDC,EAAe,GACfC,EAAY,GAEZC,EAAc,GAGdC,EAA6B,KAC7BC,EAA8B,KAC9BC,EAA2B,KAE3BC,EAAwC,KAExCC,EAA2B,GAG/B,SAASC,EAAUC,EAAiBC,EAAiB,CAC/C,CAAC/B,EAAM,aAAeqB,IAC1BJ,EAASa,EACTZ,EAASa,EACTZ,EAAe,EACfC,EAAc,OACdN,EAAW,MAAQ,OACrB,CAIA,SAASkB,EAASF,EAAiBC,EAAiBE,EAA8B,CAChF,GAAI,CAACjC,EAAM,aAAeqB,GAAgBH,IAAW,EAAG,MAAO,GAE/D,MAAMgB,EAAKJ,EAAUb,EACfkB,EAAKJ,EAAUb,EAGrB,GAAIE,IAAgB,OAAQ,CAC1B,MAAMgB,EAAK,KAAK,IAAIF,CAAE,EAChBG,EAAK,KAAK,IAAIF,CAAE,EACtB,GAAIC,EAAK7B,GAAuB8B,EAAK9B,EACnCa,EAAciB,EAAKD,EAAK,IAAM,WAAa,iBAE3C,OAAO,EAEX,CACA,GAAIhB,IAAgB,aAAc,MAAO,GAGzC,MAAMkB,EAAQC,MAAkB,EAIhC,GAAI,CAACD,GAASH,EAAK,EAAG,CACpB,MAAMK,EAAI9B,EAAa,MACvB,MAAI,GAAA8B,GACeA,EAAE,aAAeA,EAAE,UAAYA,EAAE,cAAgB,GAClDP,EAKpB,CACA,OAAKK,GAKLnB,EAFgB,KAAK,IAAI,EAAG,KAAK,IAAIgB,EAAI,GAAG,CAAC,EAG7CnB,EAAW,MAAQ,GAEfS,IAAiB,OACnBA,EAAe,sBAAsB,IAAM,CACzCA,EAAe,KACfV,EAAa,MAAQI,EAAe,GAChCA,IAAiB,EACnBL,EAAW,MAAQ,OAEnBA,EAAW,MAAQK,EAAenB,EAAM,cAAgB,UAAY,SAExE,CAAC,GAIImC,EAAK,GArBO,EAsBrB,CAGA,SAASM,GAAU,CACb,CAACzC,EAAM,aAAeqB,IAGtBI,IAAiB,OACnB,qBAAqBA,CAAY,EACjCA,EAAe,MAGjBT,EAAW,MAAQ,GAGfG,EAAenB,EAAM,eACvBqB,EAAe,GACfP,EAAW,MAAQ,aACnBC,EAAa,MAAQ,GACrBP,EAAK,SAAS,IAEdO,EAAa,MAAQ,EACrBD,EAAW,MAAQ,QAGrB4B,GAAA,EACF,CAGA,SAASC,IAAa,CAChB,CAAC3C,EAAM,aAAeqB,IAEtBI,IAAiB,OACnB,qBAAqBA,CAAY,EACjCA,EAAe,MAGjBT,EAAW,MAAQ,GACnBD,EAAa,MAAQ,EACrBD,EAAW,MAAQ,OACnB4B,GAAA,EACF,CAGA,SAASE,EAAiBC,EAAe,CACvChB,EAAUgB,EAAE,QAAQ,CAAC,EAAE,QAASA,EAAE,QAAQ,CAAC,EAAE,OAAO,CACtD,CAGA,SAASC,EAAgBD,EAAe,CACtC,MAAME,EAAQF,EAAE,QAAQ,CAAC,EACrBb,EAASe,EAAM,QAASA,EAAM,QAASF,EAAE,UAAU,GAAKA,EAAE,YAC5DA,EAAE,eAAA,CAEN,CAGA,SAASG,GAAiB,CACxBP,EAAA,CACF,CAGA,SAASQ,GAAoB,CAC3BN,GAAA,CACF,CAGA,SAASO,EAAgBL,EAAe,CAElC,CAAC7C,EAAM,aAAeqB,GAAgBwB,EAAE,SAAW,IACvDtB,EAAc,GACdM,EAAUgB,EAAE,QAASA,EAAE,OAAO,EAChC,CAGA,SAASM,EAAgBN,EAAe,CACjCtB,GACDS,EAASa,EAAE,QAASA,EAAE,QAAS,EAAI,GAErCA,EAAE,eAAA,CAEN,CAGA,SAASO,GAAgB,CAClB7B,IACLA,EAAc,GACdkB,EAAA,EACF,CAEA,SAASC,IAAa,CACpBzB,EAAS,EACTC,EAAS,EACTC,EAAe,EACfC,EAAc,MAChB,CAGA,SAASiC,GAAe,CAClBrD,EAAM,SAAWA,EAAM,UAAYA,EAAM,OAASsB,GAClDE,IAEJA,EAAc,OAAO,WAAW,IAAM,OACpCA,EAAc,KACd,MAAM8B,EAAY5C,EAAa,MAC/B,GAAI,CAAC4C,EAAW,OAEhB,KAAM,CAAE,UAAAC,EAAW,aAAAC,EAAc,aAAAC,CAAA,EAAiBH,EAC5CI,IAAgBC,EAAA/C,EAAW,QAAX,YAAA+C,EAAkB,eAAgB,EAGxD,GAAID,GAAiBF,EAAc,CAEjC,GAAI5B,IAA6B8B,EAAe,OAChD9B,EAA2B8B,EAE3BE,GAAY,EAAI,EAChB,MACF,CAGIH,EAAeF,EAAYC,GAAgBxD,EAAM,eAEnD4D,GAAY,EAAK,CAErB,EAAG,GAAG,EACR,CAEA,SAASA,GAAYC,EAAiB,GAAO,CAC3CvC,EAAY,GACZd,EAAK,MAAM,EACXsD,EAAAA,SAAS,IAAM,OACb,MAAMtB,EAAI9B,EAAa,MAClB8B,IACDqB,EAEFrB,EAAE,UAAYA,EAAE,cAIhBmB,EAAA9C,EAAa,QAAb,MAAA8C,EAAoB,eAAe,CAAE,MAAO,MAAO,SAAU,WAEjE,CAAC,CACH,CAGA,SAASpB,IAAuB,OAC9B,QAAOoB,EAAAjD,EAAa,QAAb,YAAAiD,EAAoB,YAAa,CAC1C,CAGA,SAASI,GAAgB,CACvB1C,EAAe,GACfN,EAAa,MAAQ,EAEjBW,IAAc,MAAM,aAAaA,CAAS,EAC9CA,EAAY,OAAO,WAAW,IAAM,CAClCZ,EAAW,MAAQ,OACnBY,EAAY,IACd,EAAG,GAAG,EAENE,EAA2B,GAC3BkC,EAAAA,SAAS,IAAM,CACbE,EAAA,CACF,CAAC,CACH,CAGA,SAASC,IAAa,CACpB3C,EAAY,GACZwC,EAAAA,SAAS,IAAM,OACb,MAAMJ,IAAgBC,EAAA/C,EAAW,QAAX,YAAA+C,EAAkB,eAAgB,EAEpD/B,IAA6B,IAAM8B,IAAkB9B,IACzDA,EAA2B,GAC3BoC,EAAA,EACF,CAAC,CACH,CAGA,SAASA,GAAqB,CACxBhE,EAAM,UAAYA,EAAM,SAAWA,EAAM,OAE7C8D,EAAAA,SAAS,IAAM,SACb,MAAMJ,IAAgBC,EAAA/C,EAAW,QAAX,YAAA+C,EAAkB,eAAgB,EAClDH,IAAeU,EAAAxD,EAAa,QAAb,YAAAwD,EAAoB,eAAgB,EAErDR,GAAiBF,GAAgB,CAAClC,GACpC+B,EAAA,CAEJ,CAAC,CACH,CAGA,SAASc,IAAc,CACrB3D,EAAK,OAAO,CACd,CAGA4D,OAAAA,EAAAA,MACE,IAAMpE,EAAM,QACZqE,GAAU,CACHA,IACH/C,EAAY,GAEhB,CAAA,EAIF8C,EAAAA,MACE,IAAMpE,EAAM,SACZqE,GAAU,CACJA,IACFzC,EAA2B,GAE/B,CAAA,EAGF0C,EAAAA,UAAU,IAAM,CACd,MAAMhB,EAAY5C,EAAa,MAC1B4C,IAEDtD,EAAM,cACRsD,EAAU,iBAAiB,aAAcV,EAAkB,CAAE,QAAS,GAAM,EAC5EU,EAAU,iBAAiB,YAAaR,EAAiB,CAAE,QAAS,GAAO,EAC3EQ,EAAU,iBAAiB,WAAYN,EAAgB,CAAE,QAAS,GAAM,EACxEM,EAAU,iBAAiB,cAAeL,EAAmB,CAAE,QAAS,GAAM,EAE9EK,EAAU,iBAAiB,YAAaJ,CAAe,EACvD,OAAO,iBAAiB,YAAaC,CAAe,EACpD,OAAO,iBAAiB,UAAWC,CAAa,GAGlDE,EAAU,iBAAiB,SAAUD,EAAc,CAAE,QAAS,GAAM,EAGhE,OAAO,eAAmB,MAC5B1B,EAAiB,IAAI,eAAe,IAAM,CACxCqC,EAAA,CACF,CAAC,EACDrC,EAAe,QAAQ2B,CAAS,EAC5B1C,EAAW,OAAOe,EAAe,QAAQf,EAAW,KAAK,GAI/DkD,EAAAA,SAAS,IAAM,CACbE,EAAA,CACF,CAAC,EACH,CAAC,EAEDO,EAAAA,gBAAgB,IAAM,CACpB,MAAMjB,EAAY5C,EAAa,MAC3B4C,IACFA,EAAU,oBAAoB,aAAcV,CAAgB,EAC5DU,EAAU,oBAAoB,YAAaR,CAAe,EAC1DQ,EAAU,oBAAoB,WAAYN,CAAc,EACxDM,EAAU,oBAAoB,cAAeL,CAAiB,EAC9DK,EAAU,oBAAoB,YAAaJ,CAAe,EAC1DI,EAAU,oBAAoB,SAAUD,CAAY,GAEtD,OAAO,oBAAoB,YAAaF,CAAe,EACvD,OAAO,oBAAoB,UAAWC,CAAa,EAC/CzB,IACFA,EAAe,WAAA,EACfA,EAAiB,MAEfF,IAAiB,OACnB,qBAAqBA,CAAY,EACjCA,EAAe,MAEbD,IAAgB,OAClB,aAAaA,CAAW,EACxBA,EAAc,MAEZE,IAAc,OAChB,aAAaA,CAAS,EACtBA,EAAY,KAEhB,CAAC,EAED8C,EAAa,CACX,QAAST,EACT,cAAAA,EACA,eAAgBA,EAChB,WAAAE,GACA,aAAcA,GACd,mBAAAD,CAAA,CACD,wBAICxE,EAAAA,mBAyCM,MAAA,SAzCG,eAAJ,IAAIkB,EAAe,MAAM,iBAAA,GAGpBhB,EAAA,2BADRF,EAAAA,mBAYM,MAAA,OAVJ,MAAKC,EAAAA,eAAA,CAAC,yBAAwB,CAAA,gBACHuB,EAAA,KAAA,CAAU,CAAA,EACpC,gDAAkCD,EAAA,KAAY,MAAA,CAAA,GAE/C0D,iBAAA9E,EAAAA,mBAKM,MALNC,GAKM,CAHQkB,EAAA,QAAU,4BAAtBtB,EAAAA,mBAAgD,OAAAK,EAAA,GAC/BiB,EAAA,QAAU,yBAA3BtB,EAAAA,mBAAqF,OAArFkF,GAAqF5E,EAAAA,gBAArBJ,EAAA,WAAW,EAAA,CAAA,kBAC3EF,EAAAA,mBAAuD,OAAvDmF,GAAuD7E,EAAAA,gBAArBJ,EAAA,WAAW,EAAA,CAAA,EAAA,iBAJlCoB,EAAA,QAAU,MAAA,CAAA,oCASzBnB,EAAAA,mBAuBM,MAAA,SAtBA,aAAJ,IAAIiB,EACJ,MAAKnB,EAAAA,eAAA,CAAC,0BAAyB,CAAA,gBACJuB,EAAA,KAAA,CAAU,CAAA,EACpC,MAAK4D,EAAAA,eAAElF,EAAA,YAAW,CAAA,UAAA,cAA8BqB,EAAA,KAAY,KAAA,EAAA,CAAA,CAAA,CAAA,GAGlDrB,EAAA,gBAAXU,EAAAA,UAAA,EAAAZ,EAAAA,mBAEM,MAFNqF,GAEM,CADJC,cAAyCC,EAAA,CAAxB,KAAMrF,EAAA,cAAA,EAAc,KAAA,EAAA,CAAA,MAAA,CAAA,CAAA,gCAIjBA,EAAA,UAAYA,EAAA,uBAAlCsF,EAAAA,YAA+DC,EAAA,OAAnB,KAAMvF,EAAA,SAAA,gDAGlDW,EAAAA,WAAaC,EAAA,OAAA,UAAA,CAAA,EAAA,OAAA,EAAA,EAGDZ,EAAA,mDAAZF,EAAAA,mBAIM,MAAA,eAJmB,eAAJ,IAAIqB,EAAe,MAAM,qBAAA,GACtBnB,EAAA,SAAWoB,EAAA,QAAU,4BAA3CkE,EAAAA,YAAoFD,EAAA,OAArB,KAAMrF,EAAA,WAAA,oBACpDA,EAAA,wBAAjBF,EAAAA,mBAA0E,OAA1E0F,GAA0EpF,EAAAA,gBAAtBJ,EAAA,YAAY,EAAA,CAAA,GAC/CA,EAAA,qBAAjBF,EAAAA,mBAAsF,OAAA,OAA9D,MAAM,aAAc,QAAO2E,EAAA,oBAAgBzE,EAAA,SAAS,EAAA,CAAA,mqBCzepF,MAAMM,EAAQN,EAyDRc,EAAOC,EASP0E,EAAYxE,EAAAA,IAAgD,IAAI,EAEhEyE,EAAOzE,EAAAA,IAAS,EAAE,EAClB0E,EAAU1E,EAAAA,IAAI,EAAK,EACnB2E,EAAW3E,EAAAA,IAAI,EAAK,EACpB4E,EAAU5E,EAAAA,IAAI,EAAK,EACnB6E,EAAY7E,EAAAA,IAAI,EAAK,EACrB8E,EAAQ9E,EAAAA,IAAI,CAAC,EACb+E,EAAO/E,EAAAA,IAAI,CAAC,EACZU,EAAeV,EAAAA,IAAI,EAAK,EAE9B,IAAIgF,EAAa,EAEjB,eAAeC,EAAKC,EAAQ,GAAO,CAC7BA,IACFH,EAAK,MAAQ,EACbJ,EAAS,MAAQ,GACjBC,EAAQ,MAAQ,IAGlBF,EAAQ,MAAQ,GAChBG,EAAU,MAAQ,GAElBG,GAAc,EACd,MAAMG,EAAMH,EAEZ,GAAI,CACF,MAAMI,EAAS,MAAM/F,EAAM,QAAQ,CACjC,KAAM0F,EAAK,MACX,SAAU1F,EAAM,SAChB,GAAGA,EAAM,MAAA,CACV,EAED,GAAI8F,IAAQH,EAAY,OAExB,MAAMK,GAAUD,GAAA,YAAAA,EAAQ,UAAW,CAAA,EAC/BF,GAEFT,EAAK,MAAQY,EACbP,EAAM,MAAQ,GAEdL,EAAK,MAAQ,CAAC,GAAGA,EAAK,MAAO,GAAGY,CAAO,EAEzCP,EAAM,MAAQ,QAAOM,GAAA,YAAAA,EAAQ,QAAS,CAAC,EACvCT,EAAS,MAAQF,EAAK,MAAM,QAAUK,EAAM,MAC5CF,EAAQ,MAAQH,EAAK,MAAM,SAAW,EAEtC5E,EAAK,UAAW,CAAE,QAAAwF,EAAS,MAAOP,EAAM,MAAO,MAAAI,EAAO,EACtDrF,EAAK,cAAe4E,EAAK,KAAK,CAChC,OAASa,EAAK,CACZ,GAAIH,IAAQH,EAAY,OACxBH,EAAU,MAAQ,GAClBhF,EAAK,QAASyF,CAAG,CACnB,QAAA,CACMH,IAAQH,IACVN,EAAQ,MAAQ,GAEpB,CACF,CAEA,eAAea,GAAgB,OAC7B7E,EAAa,MAAQ,IAErBsC,EAAAwB,EAAU,QAAV,MAAAxB,EAAiB,gBAEjB,MAAM,IAAI,QAAcwC,GAAW,CACjC,WAAW,IAAMA,EAAA,EAAW,GAAG,CACjC,CAAC,EAED,MAAMP,EAAK,EAAI,EACfvE,EAAa,MAAQ,EACvB,CAEA,eAAe+E,GAAa,SAC1B,GAAId,EAAS,MAAO,EAClB3B,EAAAwB,EAAU,QAAV,MAAAxB,EAAiB,aACjB,MACF,CAEIyB,EAAK,MAAM,OAAS,IACtBM,EAAK,OAAS,GAEhB,MAAME,EAAK,EAAK,GAChB1B,EAAAiB,EAAU,QAAV,MAAAjB,EAAiB,YACnB,CAEA,SAASC,GAAc,CACrBqB,EAAU,MAAQ,GACdJ,EAAK,MAAM,SAAW,EACxBQ,EAAK,EAAI,EAETQ,EAAA,CAEJ,CAEA,eAAeC,GAAS,CACtB,MAAMT,EAAK,EAAI,CACjB,CAEAxB,OAAAA,EAAAA,MACE,IAAMpE,EAAM,OACZ,IAAM,CACAA,EAAM,YACRqG,EAAA,CAEJ,EACA,CAAE,KAAM,EAAA,CAAK,EAGfjC,EAAAA,MACEgB,EACA,SAAY,OACV,MAAMtB,WAAA,GACNH,EAAAwB,EAAU,QAAV,MAAAxB,EAAiB,oBACnB,EACA,CAAE,KAAM,EAAA,CAAK,EAGfW,EAAAA,UAAU,IAAM,CACVtE,EAAM,WACR4F,EAAK,EAAI,CAEb,CAAC,EAEDpB,EAAa,CAEX,OAAA6B,EAEA,QAASA,EAET,KAAAjB,EAEA,QAAAC,EAEA,SAAAC,EAEA,QAAAC,EAEA,MAAAE,EAEA,WAAY,IAAA,OAAM,OAAA9B,EAAAwB,EAAU,QAAV,YAAAxB,EAAiB,cACnC,cAAe,IAAA,OAAM,OAAAA,EAAAwB,EAAU,QAAV,YAAAxB,EAAiB,iBACtC,mBAAoB,IAAA,OAAM,OAAAA,EAAAwB,EAAU,QAAV,YAAAxB,EAAiB,qBAAmB,CAC/D,wBAICqB,EAAAA,YA8BiBsB,EAAA,SA7BX,YAAJ,IAAInB,EACH,QAASE,EAAA,MACT,SAAUC,EAAA,MACV,WAAUC,EAAA,MACV,MAAOC,EAAA,MACP,eAAc9F,EAAA,YACd,iBAAgBA,EAAA,cAChB,iBAAgBA,EAAA,cAChB,aAAYA,EAAA,UACZ,eAAcA,EAAA,YACd,eAAcA,EAAA,YACd,kBAAiBA,EAAA,eACjB,eAAcA,EAAA,YACd,gBAAeA,EAAA,aACf,aAAYA,EAAA,UACZ,kBAAiB2B,EAAA,MACjB,OAAM+E,EACN,UAASF,EACT,QAAO/B,CAAA,qBAER,IAQE,CARF9D,aAQEC,EAAA,OAAA,UAAA,CAPC,KAAM8E,EAAA,MACN,QAASC,EAAA,MACT,SAAUC,EAAA,MACV,QAAUC,EAAA,MACV,MAAOC,EAAA,MACP,MAAOC,EAAA,MACP,OAAAY,CAAA,uOCxPP,IAAIE,EAAgB,GAEpB,MAAMC,GAAa,4kEAEZ,SAASC,IAAc,CAC5B,GAAIF,GAAiB,OAAO,SAAa,IAAa,OAEtD,MAAMG,EAAQ,SAAS,cAAc,OAAO,EAC5CA,EAAM,aAAa,cAAe,oBAAoB,EACtDA,EAAM,YAAcF,GACpB,SAAS,KAAK,YAAYE,CAAK,EAE/BH,EAAgB,EAClB,CCNAE,GAAA,EAMO,SAASE,EAAQC,EAAU,CAChCA,EAAI,UAAU,iBAAkBN,CAAc,EAC9CM,EAAI,UAAU,mBAAoBC,CAAgB,EAClDD,EAAI,UAAU,iBAAkB7B,CAAc,EAC9C6B,EAAI,UAAU,iBAAkB3B,CAAc,CAChD,CAGA,MAAA6B,GAAe,CACb,QAAAH,CACF"}
|
package/dist/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.loading-content[data-v-
|
|
1
|
+
.loading-content[data-v-a890d226]{display:flex;align-items:center;justify-content:center;gap:8px;padding:6px 12px;border-radius:16px;color:#1989fa;font-size:14px}.loading-spinner[data-v-a890d226]{width:18px;height:18px;border-radius:50%;border:2.5px solid #1989fa;border-top-color:transparent;animation:spin-a890d226 .8s linear infinite}@keyframes spin-a890d226{to{transform:rotate(360deg)}}.loading-container.fullscreen[data-v-a890d226]{position:fixed;top:0;left:0;width:100%;height:100%;display:flex;align-items:center;justify-content:center;background-color:#ffffff80}.empty-wrap[data-v-3c452901]{display:flex;flex-direction:column;align-items:center}.empty-image[data-v-3c452901]{width:96px;height:80px}.empty-text[data-v-3c452901]{margin:12px 0 0;color:#8c8f97;font-size:12px;line-height:22px}.infinite-scroll[data-v-fc5e471c]{height:100%;position:relative;min-height:100%;overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;touch-action:pan-y;-webkit-overflow-scrolling:touch}.pull-refresh-indicator[data-v-fc5e471c]{position:absolute;top:-50px;left:0;right:0;height:50px;transition:transform .25s}.pull-refresh-indicator.no-transition[data-v-fc5e471c]{transition:none}.pull-refresh-content[data-v-fc5e471c]{display:flex;align-items:center;justify-content:center;height:100%;font-size:14px;color:#969799}.pull-text[data-v-fc5e471c]{color:#1989fa;font-size:14px}.infinite-scroll-content[data-v-fc5e471c]{position:relative;transition:transform .25s;min-height:100%}.infinite-scroll-content.no-transition[data-v-fc5e471c]{transition:none}.content-loading-mask[data-v-fc5e471c]{position:absolute;top:0;left:0;right:0;bottom:0;background-color:#fffc;display:flex;align-items:center;justify-content:center;z-index:10;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.load-more-indicator[data-v-fc5e471c]{display:flex;align-items:center;justify-content:center;min-height:50px;padding:16px 0;font-size:14px;color:#8c8f97}.finished-text[data-v-fc5e471c]{color:#8c8f97;font-size:14px}.error-text[data-v-fc5e471c]{color:#ee0a24;font-size:14px;cursor:pointer}.error-text[data-v-fc5e471c]:active{opacity:.7}
|