clxx 2.1.4 → 2.1.6

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.
Files changed (43) hide show
  1. package/README.md +766 -422
  2. package/build/Alert/style.js +41 -58
  3. package/build/AutoGrid/index.js +32 -43
  4. package/build/AutoGrid/style.d.ts +3 -4
  5. package/build/AutoGrid/style.js +7 -19
  6. package/build/CarouselNotice/style.js +6 -11
  7. package/build/Clickable/index.d.ts +1 -0
  8. package/build/Clickable/index.js +77 -41
  9. package/build/Container/index.js +46 -80
  10. package/build/Dialog/style.js +2 -2
  11. package/build/Fixed/index.d.ts +5 -0
  12. package/build/Fixed/index.js +37 -0
  13. package/build/Indicator/index.js +5 -5
  14. package/build/Loading/style.js +16 -17
  15. package/build/Overlay/index.js +4 -32
  16. package/build/ScrollView/index.js +65 -47
  17. package/build/ScrollView/style.js +12 -13
  18. package/build/Toast/index.js +5 -3
  19. package/build/Toast/style.js +11 -14
  20. package/build/context.d.ts +2 -3
  21. package/build/context.js +1 -4
  22. package/build/index.d.ts +1 -1
  23. package/build/index.js +1 -1
  24. package/build/utils/Countdown.js +11 -4
  25. package/build/utils/ago.js +39 -52
  26. package/build/utils/createApp.d.ts +1 -2
  27. package/build/utils/createApp.js +23 -12
  28. package/build/utils/cssUtil.d.ts +0 -9
  29. package/build/utils/cssUtil.js +0 -38
  30. package/build/utils/defaultScroll.d.ts +4 -4
  31. package/build/utils/defaultScroll.js +6 -15
  32. package/build/utils/dom.js +5 -8
  33. package/build/utils/jsonp.js +7 -4
  34. package/build/utils/request.js +23 -33
  35. package/build/utils/tick.js +7 -14
  36. package/build/utils/uniqKey.js +7 -7
  37. package/build/utils/wait.js +1 -1
  38. package/package.json +10 -10
  39. package/test/eslint.config.js +5 -2
  40. package/test/package.json +11 -11
  41. package/test/src/ago/index.jsx +3 -1
  42. package/test/src/dialog/index.module.css +1 -1
  43. package/test/src/index.jsx +3 -2
@@ -0,0 +1,37 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { jsx as _jsx } from "@emotion/react/jsx-runtime";
13
+ export function Fixed(props) {
14
+ const { children, position = "bottom" } = props, extra = __rest(props, ["children", "position"]);
15
+ const styles = {
16
+ position: "fixed",
17
+ };
18
+ if (position === "top") {
19
+ styles.top = 0;
20
+ styles.width = "100%";
21
+ styles.left = 0;
22
+ }
23
+ else if (position === "bottom") {
24
+ styles.bottom = 0;
25
+ styles.width = "100%";
26
+ styles.left = 0;
27
+ }
28
+ else if (position === "left") {
29
+ styles.left = 0;
30
+ styles.height = "100%";
31
+ }
32
+ else if (position === "right") {
33
+ styles.right = 0;
34
+ styles.height = "100%";
35
+ }
36
+ return (_jsx("div", Object.assign({}, props, { css: styles }, extra, { children: props.children })));
37
+ }
@@ -12,7 +12,7 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  import { jsx as _jsx } from "@emotion/react/jsx-runtime";
13
13
  import { css } from '@emotion/react';
14
14
  import React from 'react';
15
- import { adaptive, normalizeUnit } from '../utils/cssUtil';
15
+ import { normalizeUnit } from '../utils/cssUtil';
16
16
  import { getBarChangeKeyFrames } from './style';
17
17
  /**
18
18
  * SVG转圈指示器,一般用作loading效果
@@ -39,10 +39,10 @@ export function Indicator(props) {
39
39
  typeof size !== 'undefined' ? {
40
40
  width: normalizeUnit(size),
41
41
  height: normalizeUnit(size),
42
- } : adaptive({
43
- width: 60,
44
- height: 60,
45
- })
42
+ } : {
43
+ width: '.6rem',
44
+ height: '.6rem',
45
+ }
46
46
  ], [size]);
47
47
  const svgStyle = React.useMemo(() => css({
48
48
  width: '100%',
@@ -1,5 +1,4 @@
1
1
  import { keyframes } from "@emotion/react";
2
- import { adaptive } from "../utils/cssUtil";
3
2
  export const LoadingShow = keyframes `
4
3
  from {
5
4
  opacity: 0;
@@ -17,14 +16,14 @@ export const LoadingHide = keyframes `
17
16
  }
18
17
  `;
19
18
  export const style = {
20
- boxCommon: adaptive({
19
+ boxCommon: {
21
20
  backgroundColor: `rgba(0, 0, 0, .8)`,
22
- borderRadius: 16,
23
- }),
24
- box: adaptive({
25
- width: 160,
26
- height: 160,
27
- }),
21
+ borderRadius: '.16rem',
22
+ },
23
+ box: {
24
+ width: '1.6rem',
25
+ height: '1.6rem',
26
+ },
28
27
  boxShow: {
29
28
  animation: `${LoadingShow} 200ms`,
30
29
  },
@@ -32,18 +31,18 @@ export const style = {
32
31
  animation: `${LoadingHide} 200ms`,
33
32
  },
34
33
  boxWithExtra: [
35
- adaptive({ padding: 30 }),
34
+ { padding: '.3rem' },
36
35
  {
37
- "> div:first-of-type": adaptive({
38
- width: 48,
39
- height: 48,
40
- }),
36
+ "> div:first-of-type": {
37
+ width: '.48rem',
38
+ height: '.48rem',
39
+ },
41
40
  },
42
41
  ],
43
- hint: adaptive({
42
+ hint: {
44
43
  color: "#f5f5f5dd",
45
44
  whiteSpace: "nowrap",
46
- fontSize: 28,
47
- marginLeft: 20,
48
- }),
45
+ fontSize: '.28rem',
46
+ marginLeft: '.2rem',
47
+ },
49
48
  };
@@ -10,10 +10,8 @@ var __rest = (this && this.__rest) || function (s, e) {
10
10
  return t;
11
11
  };
12
12
  import { jsx as _jsx } from "@emotion/react/jsx-runtime";
13
- import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
13
+ import { useLayoutEffect, useMemo, useState } from "react";
14
14
  import { createPortal } from "react-dom";
15
- import { getContextValue } from "../context";
16
- import { useWindowResize } from "../Effect/useWindowResize";
17
15
  /**
18
16
  * 覆盖层,可以作为通用遮罩
19
17
  * @param props
@@ -22,14 +20,6 @@ import { useWindowResize } from "../Effect/useWindowResize";
22
20
  export function Overlay(props) {
23
21
  const { children, outside = false, centerContent = true, fullScreen = true, maskColor = "rgba(0, 0, 0, .6)" } = props, extra = __rest(props, ["children", "outside", "centerContent", "fullScreen", "maskColor"]);
24
22
  const [mount, setMount] = useState(null);
25
- const [innerWidth, setInnerWidth] = useState(window.innerWidth);
26
- // 这里是为了修复一个非挂载状态触发resize事件的bug
27
- const isUnmount = useRef(false);
28
- useEffect(() => {
29
- return () => {
30
- isUnmount.current = true;
31
- };
32
- }, []);
33
23
  useLayoutEffect(() => {
34
24
  if (outside) {
35
25
  const div = document.createElement("div");
@@ -40,36 +30,18 @@ export function Overlay(props) {
40
30
  };
41
31
  }
42
32
  }, [outside]);
43
- // 页面大小变化时,innerWidth 也会更新
44
- useWindowResize(() => {
45
- if (!isUnmount.current) {
46
- setInnerWidth(window.innerWidth);
47
- }
48
- });
49
- const ctx = getContextValue();
50
33
  // 使用 useMemo 缓存样式计算,避免每次渲染都重新计算
51
34
  const style = useMemo(() => {
52
35
  const styles = [];
53
36
  // 如果是全屏,设置全屏样式
54
37
  if (fullScreen) {
55
- // 获取宽度
56
- let width = innerWidth;
57
- if (width >= ctx.maxDocWidth) {
58
- width = ctx.maxDocWidth;
59
- }
60
- else if (width <= ctx.minDocWidth) {
61
- width = ctx.minDocWidth;
62
- }
63
38
  styles.push({
64
39
  zIndex: 9999,
65
40
  position: "fixed",
66
41
  top: 0,
67
- left: "50%",
68
- marginLeft: `-${width / 2}px`,
69
- width: `${width}px`,
42
+ left: 0,
43
+ width: "100%",
70
44
  height: "100%",
71
- maxWidth: `${ctx.maxDocWidth}px`,
72
- minWidth: `${ctx.minDocWidth}px`,
73
45
  backgroundColor: maskColor,
74
46
  });
75
47
  }
@@ -82,7 +54,7 @@ export function Overlay(props) {
82
54
  });
83
55
  }
84
56
  return styles;
85
- }, [fullScreen, innerWidth, ctx.maxDocWidth, ctx.minDocWidth, maskColor, centerContent]);
57
+ }, [fullScreen, maskColor, centerContent]);
86
58
  const content = (_jsx("div", Object.assign({ css: style }, extra, { children: children })));
87
59
  /**
88
60
  * 如果是挂载到当前位置,直接返回
@@ -10,7 +10,7 @@ var __rest = (this && this.__rest) || function (s, e) {
10
10
  return t;
11
11
  };
12
12
  import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
13
- import { useCallback, useLayoutEffect, useRef, useState } from "react";
13
+ import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
14
14
  import { Indicator } from "../Indicator";
15
15
  import { RowCenter } from "../Flex/Row";
16
16
  import { style } from "./style";
@@ -31,19 +31,22 @@ export function ScrollView(props) {
31
31
  // 节流控制
32
32
  const throttleTimer = useRef(undefined);
33
33
  const lastCallTime = useRef(0);
34
- // 使用 ref 保存最新的回调函数,避免闭包陈旧
35
- const callbacksRef = useRef({
34
+ // 使用 ref 保存所有滚动处理需要的 props,彻底消除陈旧闭包
35
+ const propsRef = useRef({
36
36
  onScroll,
37
37
  onReachTop,
38
38
  onReachBottom,
39
+ reachTopThreshold,
40
+ reachBottomThreshold,
39
41
  });
40
- // 每次渲染都更新 ref 中的回调
41
- callbacksRef.current = {
42
+ propsRef.current = {
42
43
  onScroll,
43
44
  onReachTop,
44
45
  onReachBottom,
46
+ reachTopThreshold,
47
+ reachBottomThreshold,
45
48
  };
46
- // container是否有滚动条
49
+ // container 是否有滚动条
47
50
  const [hasScrollBar, setHasScrollBar] = useState(false);
48
51
  // 检查是否有滚动条
49
52
  const checkScrollBar = useCallback(() => {
@@ -72,41 +75,24 @@ export function ScrollView(props) {
72
75
  resizeObserver.disconnect();
73
76
  };
74
77
  }, [checkScrollBar]);
75
- // 滚动回调(带节流)
76
- const scrollCallback = useCallback((rawEvent) => {
77
- const now = Date.now();
78
- // 节流控制
79
- if (scrollThrottle > 0 && now - lastCallTime.current < scrollThrottle) {
80
- // 清除之前的定时器
81
- if (throttleTimer.current) {
82
- clearTimeout(throttleTimer.current);
83
- }
84
- // 设置新的定时器,确保最后一次调用会被执行
85
- throttleTimer.current = window.setTimeout(() => {
86
- handleScroll(rawEvent);
87
- }, scrollThrottle);
88
- return;
89
- }
90
- lastCallTime.current = now;
91
- handleScroll(rawEvent);
92
- }, [scrollThrottle, reachTopThreshold, reachBottomThreshold]);
93
- // 实际的滚动处理逻辑
94
- const handleScroll = useCallback((rawEvent) => {
95
- var _a, _b, _c, _d, _e, _f;
78
+ // 核心滚动处理逻辑
79
+ // 所有外部值从 ref 读取,deps 为空,引用永远稳定,不存在闭包过期问题
80
+ const processScroll = useCallback((rawEvent) => {
96
81
  const box = container.current;
97
82
  if (!box)
98
83
  return;
99
- // 已经滚动的距离
84
+ const { onScroll, onReachTop, onReachBottom, reachTopThreshold, reachBottomThreshold, } = propsRef.current;
100
85
  const scrollTop = box.scrollTop;
101
- // 滚动容器的包含滚动内容的高度
102
86
  const contentHeight = box.scrollHeight;
103
- // 滚动容器的视口高度
104
- const containerHeight = Math.min(box.clientHeight, box.offsetHeight);
105
- // 最大可滚动距离
87
+ // clientHeight 即可视区域高度(不含 border),无需 Math.min(clientHeight, offsetHeight)
88
+ const containerHeight = box.clientHeight;
106
89
  const maxScroll = contentHeight - containerHeight;
107
- // 计算滚动方向
108
- const direction = scrollTop > lastScrollTop.current ? "downward" : "upward";
109
- // 生成滚动事件参数
90
+ // 防止零位移时误判方向(如内容变化触发的 scroll 事件)
91
+ if (scrollTop === lastScrollTop.current && lastScrollTop.current !== 0) {
92
+ return;
93
+ }
94
+ // scrollTop 增大 => 向下滚动;相等(初始 0→0)视为向下
95
+ const direction = scrollTop >= lastScrollTop.current ? "downward" : "upward";
110
96
  const event = {
111
97
  containerHeight,
112
98
  contentHeight,
@@ -115,42 +101,74 @@ export function ScrollView(props) {
115
101
  direction,
116
102
  rawEvent,
117
103
  };
118
- // 调用通用滚动事件(使用 ref 中的最新回调)
119
- (_b = (_a = callbacksRef.current).onScroll) === null || _b === void 0 ? void 0 : _b.call(_a, event);
104
+ onScroll === null || onScroll === void 0 ? void 0 : onScroll(event);
120
105
  // 触顶逻辑(防止重复触发)
121
106
  if (direction === "upward" && scrollTop <= reachTopThreshold) {
122
107
  if (!hasReachedTop.current) {
123
108
  hasReachedTop.current = true;
124
- hasReachedBottom.current = false; // 重置触底标记
125
- (_d = (_c = callbacksRef.current).onReachTop) === null || _d === void 0 ? void 0 : _d.call(_c, event);
109
+ hasReachedBottom.current = false;
110
+ onReachTop === null || onReachTop === void 0 ? void 0 : onReachTop(event);
126
111
  }
127
112
  }
128
113
  else if (scrollTop > reachTopThreshold) {
129
114
  hasReachedTop.current = false;
130
115
  }
131
116
  // 触底逻辑(防止重复触发)
132
- if (direction === "downward" && scrollTop >= maxScroll - reachBottomThreshold) {
117
+ if (direction === "downward" &&
118
+ maxScroll > 0 &&
119
+ scrollTop >= maxScroll - reachBottomThreshold) {
133
120
  if (!hasReachedBottom.current) {
134
121
  hasReachedBottom.current = true;
135
- hasReachedTop.current = false; // 重置触顶标记
136
- (_f = (_e = callbacksRef.current).onReachBottom) === null || _f === void 0 ? void 0 : _f.call(_e, event);
122
+ hasReachedTop.current = false;
123
+ onReachBottom === null || onReachBottom === void 0 ? void 0 : onReachBottom(event);
137
124
  }
138
125
  }
139
126
  else if (scrollTop < maxScroll - reachBottomThreshold) {
140
127
  hasReachedBottom.current = false;
141
128
  }
142
- // 更新scrollTop上次的值
143
129
  lastScrollTop.current = scrollTop;
144
- }, [reachTopThreshold, reachBottomThreshold]);
130
+ }, []);
131
+ // 节流滚动回调(leading + trailing)
132
+ const scrollCallback = useCallback((rawEvent) => {
133
+ // 不节流时直接执行
134
+ if (scrollThrottle <= 0) {
135
+ processScroll(rawEvent);
136
+ return;
137
+ }
138
+ const now = Date.now();
139
+ const elapsed = now - lastCallTime.current;
140
+ if (elapsed >= scrollThrottle) {
141
+ // 前沿立即执行
142
+ lastCallTime.current = now;
143
+ processScroll(rawEvent);
144
+ // 消除挂起的尾部定时器
145
+ if (throttleTimer.current !== undefined) {
146
+ clearTimeout(throttleTimer.current);
147
+ throttleTimer.current = undefined;
148
+ }
149
+ }
150
+ else {
151
+ // 尾部调用:按剩余时间调度,保证滚动停止后最终状态被处理
152
+ if (throttleTimer.current !== undefined) {
153
+ clearTimeout(throttleTimer.current);
154
+ }
155
+ throttleTimer.current = window.setTimeout(() => {
156
+ lastCallTime.current = Date.now();
157
+ throttleTimer.current = undefined;
158
+ // 尾部调用不传 rawEvent(已过期),processScroll 从 DOM 读取实时位置
159
+ processScroll();
160
+ }, scrollThrottle - elapsed);
161
+ }
162
+ }, [scrollThrottle, processScroll]);
145
163
  // 清理节流定时器
146
- useLayoutEffect(() => {
164
+ useEffect(() => {
147
165
  return () => {
148
- if (throttleTimer.current) {
166
+ if (throttleTimer.current !== undefined) {
149
167
  clearTimeout(throttleTimer.current);
150
168
  }
151
169
  };
152
170
  }, []);
153
- // loading内容
171
+ // loading 内容
154
172
  let showLoadingContent = null;
155
173
  if (showLoading) {
156
174
  if (!loadingContent) {
@@ -1,4 +1,3 @@
1
- import { adaptive } from "../utils/cssUtil";
2
1
  export const style = {
3
2
  container: {
4
3
  overflow: "auto",
@@ -6,24 +5,24 @@ export const style = {
6
5
  WebkitOverflowScrolling: "touch",
7
6
  },
8
7
  loading: [
9
- adaptive({
10
- paddingTop: 15,
11
- paddingBottom: 15,
12
- }),
13
8
  {
14
- "> div": adaptive({
15
- width: 30,
16
- height: 30,
17
- }),
9
+ paddingTop: '.15rem',
10
+ paddingBottom: '.15rem',
11
+ },
12
+ {
13
+ "> div": {
14
+ width: '.3rem',
15
+ height: '.3rem',
16
+ },
18
17
  "> p": [
19
18
  {
20
19
  color: "#666",
21
20
  lineHeight: 1,
22
21
  },
23
- adaptive({
24
- marginLeft: 16,
25
- fontSize: 24,
26
- }),
22
+ {
23
+ marginLeft: '.16rem',
24
+ fontSize: '.24rem',
25
+ },
27
26
  ],
28
27
  },
29
28
  ],
@@ -26,11 +26,13 @@ export function showToast(option) {
26
26
  */
27
27
  let portalDOM = null;
28
28
  export function showUniqToast(option) {
29
- if (!portalDOM) {
30
- portalDOM = createPortalDOM();
29
+ // 先清理上一个 Toast 的 DOM 容器,避免快速连续调用时旧容器泄漏
30
+ if (portalDOM) {
31
+ portalDOM.unmount();
32
+ portalDOM = null;
31
33
  }
34
+ portalDOM = createPortalDOM();
32
35
  let props = {};
33
- // 默认Toast是唯一的
34
36
  if (React.isValidElement(option) || typeof option !== 'object') {
35
37
  props.content = option;
36
38
  }
@@ -1,5 +1,4 @@
1
1
  import { css, keyframes } from "@emotion/react";
2
- import { adaptive } from "../utils/cssUtil";
3
2
  export const middleShowAnimation = keyframes `
4
3
  from {
5
4
  opacity: 0;
@@ -93,16 +92,15 @@ export const style = {
93
92
  left: "50%",
94
93
  transform: "translateX(-50%)",
95
94
  zIndex: 9999,
96
- }, adaptive({
97
- maxWidth: 600,
98
- }));
95
+ maxWidth: '6rem',
96
+ });
99
97
  },
100
98
  top(offset) {
101
- return adaptive({ top: offset });
99
+ return css({ top: offset / 100 + 'rem' });
102
100
  },
103
101
  middle: css({ top: "50%" }),
104
102
  bottom(offset) {
105
- return adaptive({ bottom: offset });
103
+ return css({ bottom: offset / 100 + 'rem' });
106
104
  },
107
105
  content: (radius) => {
108
106
  return css({
@@ -114,14 +112,13 @@ export const style = {
114
112
  textOverflow: "ellipsis",
115
113
  overflow: "hidden",
116
114
  lineHeight: 1,
117
- }, adaptive({
118
- fontSize: 26,
119
- paddingLeft: 30,
120
- paddingRight: 30,
121
- paddingTop: 40,
122
- paddingBottom: 40,
123
- borderRadius: radius !== null && radius !== void 0 ? radius : 0,
124
- }));
115
+ fontSize: '.26rem',
116
+ paddingLeft: '.3rem',
117
+ paddingRight: '.3rem',
118
+ paddingTop: '.4rem',
119
+ paddingBottom: '.4rem',
120
+ borderRadius: radius ? radius / 100 + 'rem' : 0,
121
+ });
125
122
  },
126
123
  contentMiddle: {
127
124
  transform: `translateY(-50%)`,
@@ -1,6 +1,5 @@
1
1
  export interface ContextValue {
2
- maxDocWidth: number;
3
- minDocWidth: number;
2
+ [key: string]: any;
4
3
  }
5
4
  /**
6
5
  * 设置环境变量的值
@@ -12,4 +11,4 @@ export declare function setContextValue(value: Partial<ContextValue>): void;
12
11
  * @param key
13
12
  * @returns
14
13
  */
15
- export declare function getContextValue(key?: keyof ContextValue): number | ContextValue;
14
+ export declare function getContextValue(key?: string): any;
package/build/context.js CHANGED
@@ -1,7 +1,4 @@
1
- let context = {
2
- maxDocWidth: 576,
3
- minDocWidth: 312,
4
- };
1
+ let context = {};
5
2
  /**
6
3
  * 设置环境变量的值
7
4
  * @param envValue
package/build/index.d.ts CHANGED
@@ -9,7 +9,7 @@ export { Countdown } from './utils/Countdown';
9
9
  export { defaultScroll } from './utils/defaultScroll';
10
10
  export { is } from './utils/is';
11
11
  export { waitFor, waitUntil } from './utils/wait';
12
- export { normalizeUnit, splitValue, adaptive } from './utils/cssUtil';
12
+ export { normalizeUnit, splitValue } from './utils/cssUtil';
13
13
  export { createApp, history, getHistory } from './utils/createApp';
14
14
  export { createPortalDOM } from './utils/dom';
15
15
  export { useInterval } from './Effect/useInterval';
package/build/index.js CHANGED
@@ -9,7 +9,7 @@ export { Countdown } from './utils/Countdown';
9
9
  export { defaultScroll } from './utils/defaultScroll';
10
10
  export { is } from './utils/is';
11
11
  export { waitFor, waitUntil } from './utils/wait';
12
- export { normalizeUnit, splitValue, adaptive } from './utils/cssUtil';
12
+ export { normalizeUnit, splitValue } from './utils/cssUtil';
13
13
  export { createApp, history, getHistory } from './utils/createApp';
14
14
  export { createPortalDOM } from './utils/dom';
15
15
  export { useInterval } from './Effect/useInterval';
@@ -14,8 +14,14 @@ export class Countdown {
14
14
  * s:秒
15
15
  */
16
16
  this.format = ['d', 'h', 'i', 's'];
17
- if (typeof option.remain === 'number' && option.remain >= 0) {
18
- this.total = this.remain = option.remain;
17
+ if (typeof option.remain === 'string') {
18
+ const parsed = parseFloat(option.remain);
19
+ if (!isNaN(parsed) && parsed >= 0) {
20
+ this.total = this.remain = Math.floor(parsed);
21
+ }
22
+ }
23
+ else if (typeof option.remain === 'number' && option.remain >= 0) {
24
+ this.total = this.remain = Math.floor(option.remain);
19
25
  }
20
26
  // 倒计时需要展示的时间格式
21
27
  if (typeof option.format === 'string') {
@@ -75,11 +81,12 @@ export class Countdown {
75
81
  }
76
82
  }, 1000); // ← 添加 1000ms 间隔
77
83
  }
78
- // 停止倒计时
84
+ // 停止倒计时(暂停并保留当前剩余时间,可再次 start 恢复)
79
85
  stop() {
80
86
  var _a;
81
- this.total = this.remain;
82
87
  (_a = this._stopTick) === null || _a === void 0 ? void 0 : _a.call(this);
88
+ this._stopTick = undefined;
89
+ this.total = this.remain;
83
90
  }
84
91
  /**
85
92
  * 格式化每次更新的值