@hlw-uni/mp-vue 2.1.57 → 2.1.59

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 (49) hide show
  1. package/dist/app.d.ts +12 -1
  2. package/dist/composables/ad/index.d.ts +26 -0
  3. package/dist/composables/device/index.d.ts +14 -0
  4. package/dist/composables/index.d.ts +1 -1
  5. package/dist/composables/msg/index.d.ts +44 -3
  6. package/dist/composables/navigator/index.d.ts +37 -1
  7. package/dist/composables/refs/index.d.ts +15 -1
  8. package/dist/composables/request/client.d.ts +87 -0
  9. package/dist/composables/request/index.d.ts +1 -1
  10. package/dist/composables/request/service.d.ts +73 -0
  11. package/dist/composables/request/types.d.ts +50 -13
  12. package/dist/composables/share/index.d.ts +38 -0
  13. package/dist/composables/theme/appearance.d.ts +30 -4
  14. package/dist/composables/theme/font.d.ts +23 -0
  15. package/dist/composables/theme/index.d.ts +19 -6
  16. package/dist/composables/theme/palette.d.ts +23 -0
  17. package/dist/composables/theme/typography.d.ts +9 -1
  18. package/dist/composables/utils/index.d.ts +120 -13
  19. package/dist/directives/copy.d.ts +5 -0
  20. package/dist/hlw.d.ts +10 -0
  21. package/dist/index.js +310 -199
  22. package/dist/index.mjs +311 -200
  23. package/dist/stores/theme.d.ts +3 -0
  24. package/package.json +2 -2
  25. package/src/app.ts +20 -3
  26. package/src/components/hlw-add-mini/README.md +10 -11
  27. package/src/components/hlw-add-mini/index.vue +93 -66
  28. package/src/components/hlw-button/index.vue +33 -18
  29. package/src/components/hlw-custom/hlw-custom.vue +118 -0
  30. package/src/composables/ad/index.ts +136 -62
  31. package/src/composables/device/index.ts +32 -2
  32. package/src/composables/index.ts +18 -1
  33. package/src/composables/msg/index.ts +70 -16
  34. package/src/composables/navigator/index.ts +45 -1
  35. package/src/composables/refs/index.ts +27 -4
  36. package/src/composables/request/client.ts +149 -0
  37. package/src/composables/request/index.ts +1 -1
  38. package/src/composables/request/service.ts +72 -0
  39. package/src/composables/request/types.ts +53 -13
  40. package/src/composables/share/index.ts +48 -0
  41. package/src/composables/theme/appearance.ts +31 -4
  42. package/src/composables/theme/font.ts +23 -0
  43. package/src/composables/theme/index.ts +23 -7
  44. package/src/composables/theme/palette.ts +32 -0
  45. package/src/composables/theme/typography.ts +9 -1
  46. package/src/composables/utils/index.ts +227 -127
  47. package/src/directives/copy.ts +31 -19
  48. package/src/hlw.ts +11 -0
  49. package/src/stores/theme.ts +28 -5
@@ -1,33 +1,49 @@
1
1
  /**
2
2
  * 小程序广告工具。
3
+ * 提供插屏广告 (Interstitial Ad) 与激励视频广告 (Rewarded Video Ad) 的注册、缓存与展示能力。
3
4
  */
4
5
 
6
+ declare const uni: any;
5
7
  declare const wx: any;
6
8
 
9
+ /**
10
+ * 广告播放/加载结果数据结构。
11
+ */
7
12
  export interface AdRes {
13
+ /** 广告是否正常加载或成功展示完成 */
8
14
  ok: boolean;
15
+ /** 激励视频是否完全播放完毕 (仅激励视频有此属性) */
9
16
  isEnded?: boolean;
17
+ /** 加载或展示失败时的错误对象 */
10
18
  err?: unknown;
11
19
  }
12
20
 
13
21
  type AdDone = (res: AdRes) => void;
14
22
 
15
- let popupAd: any = null;
23
+ // 缓存不同 Unit ID 的广告实例
24
+ const popupCache = new Map<string, any>();
25
+ const rewardCache = new Map<string, any>();
26
+
27
+ let activePopupAdId = "";
16
28
  let popupDone: ((ok: boolean) => void) | undefined;
17
- let popupClose: (() => void) | null = null;
18
- let popupError: ((err: unknown) => void) | null = null;
19
29
 
20
- let rewardAd: any = null;
30
+ let activeRewardAdId = "";
21
31
  let rewardDone: AdDone | undefined;
22
32
  let rewardPromise: Promise<AdRes> | null = null;
23
33
  let rewardResolve: ((res: AdRes) => void) | null = null;
24
- let rewardClose: ((res: { isEnded?: boolean }) => void) | null = null;
25
- let rewardError: ((err: unknown) => void) | null = null;
26
34
 
27
- function api() {
28
- return typeof wx === "undefined" ? null : wx;
35
+ /**
36
+ * 获取当前环境的小程序全局 API 实例。
37
+ */
38
+ function getAdApi() {
39
+ if (typeof uni !== "undefined") return uni;
40
+ if (typeof wx !== "undefined") return wx;
41
+ return null;
29
42
  }
30
43
 
44
+ /**
45
+ * 触发激励视频广告结束的回调并 resolve Promise。
46
+ */
31
47
  function finish(res: AdRes) {
32
48
  rewardDone?.(res);
33
49
  rewardResolve?.(res);
@@ -35,46 +51,75 @@ function finish(res: AdRes) {
35
51
  rewardPromise = null;
36
52
  }
37
53
 
38
- function clearReward() {
39
- if (!rewardAd) return;
40
- if (rewardClose) rewardAd.offClose?.(rewardClose);
41
- if (rewardError) rewardAd.offError?.(rewardError);
42
- rewardClose = null;
43
- rewardError = null;
44
- }
45
-
54
+ /**
55
+ * 小程序广告 Composables。
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * const { setAdPopup, showAdPopup, setAdReward, showAdReward } = useHlwAd();
60
+ *
61
+ * // 1. 插屏广告
62
+ * setAdPopup('ad-unit-id');
63
+ * await showAdPopup();
64
+ *
65
+ * // 2. 激励视频
66
+ * await setAdReward('ad-unit-id');
67
+ * const res = await showAdReward();
68
+ * if (res.ok && res.isEnded) {
69
+ * // 发放奖励
70
+ * }
71
+ * ```
72
+ */
46
73
  export function useHlwAd() {
47
- function clearPopup() {
48
- if (!popupAd) return;
49
- if (popupClose) popupAd.offClose?.(popupClose);
50
- if (popupError) popupAd.offError?.(popupError);
51
- popupClose = null;
52
- popupError = null;
53
- }
54
-
74
+ /**
75
+ * 配置/预加载插屏广告。
76
+ *
77
+ * @param adId 广告单元 ID
78
+ * @param done 广告关闭后的回调(可选)
79
+ * @returns 是否配置成功
80
+ */
55
81
  function setAdPopup(adId: string, done?: (ok: boolean) => void): boolean {
56
82
  popupDone = done;
57
- const wxApi = api();
58
- if (!adId || !wxApi?.createInterstitialAd) return false;
59
-
60
- clearPopup();
61
- popupAd = wxApi.createInterstitialAd({ adUnitId: adId });
62
- popupAd.onLoad?.(() => {});
63
- popupError = (err: unknown) => {
64
- console.error("插屏广告加载失败", err);
65
- popupDone?.(false);
66
- };
67
- popupClose = () => {
68
- popupDone?.(true);
69
- };
70
- popupAd.onError?.(popupError);
71
- popupAd.onClose?.(popupClose);
83
+ if (!adId) return false;
84
+
85
+ const api = getAdApi();
86
+ if (!api?.createInterstitialAd) return false;
87
+
88
+ activePopupAdId = adId;
89
+ if (!popupCache.has(adId)) {
90
+ try {
91
+ const ad = api.createInterstitialAd({ adUnitId: adId });
92
+ ad.onLoad?.(() => console.log(`[HlwAd] Interstitial loaded: ${adId}`));
93
+ ad.onError?.((err: unknown) => {
94
+ console.error("[HlwAd] Interstitial load error:", err);
95
+ if (activePopupAdId === adId) {
96
+ popupDone?.(false);
97
+ }
98
+ });
99
+ ad.onClose?.(() => {
100
+ if (activePopupAdId === adId) {
101
+ popupDone?.(true);
102
+ }
103
+ });
104
+ popupCache.set(adId, ad);
105
+ } catch (e) {
106
+ console.error("[HlwAd] Interstitial creation failed:", e);
107
+ return false;
108
+ }
109
+ }
72
110
  return true;
73
111
  }
74
112
 
113
+ /**
114
+ * 延迟展示已配置的插屏广告。
115
+ *
116
+ * @param delay 延迟毫秒数,默认 3000ms
117
+ * @returns 返回 Promise,resolve 是否成功显示且用户关闭了它
118
+ */
75
119
  function showAdPopup(delay = 3000): Promise<boolean> {
76
120
  return new Promise((resolve) => {
77
- if (!popupAd) {
121
+ const ad = popupCache.get(activePopupAdId);
122
+ if (!ad) {
78
123
  resolve(false);
79
124
  return;
80
125
  }
@@ -86,44 +131,72 @@ export function useHlwAd() {
86
131
  };
87
132
 
88
133
  setTimeout(() => {
89
- popupAd.show().catch((err: unknown) => {
90
- console.error("插屏广告显示失败", err);
134
+ ad.show().catch((err: unknown) => {
135
+ console.error("[HlwAd] Interstitial show error:", err);
91
136
  popupDone?.(false);
92
137
  });
93
138
  }, Math.max(0, delay));
94
139
  });
95
140
  }
96
141
 
97
-
142
+ /**
143
+ * 配置/预加载激励视频广告。
144
+ *
145
+ * @param adId 广告单元 ID
146
+ * @param done 播放结束的回调(可选)
147
+ * @returns 返回 Promise<AdRes>,在加载或创建失败时直接 resolve
148
+ */
98
149
  function setAdReward(adId: string, done?: AdDone): Promise<AdRes> {
99
150
  rewardDone = done;
100
151
  rewardPromise = new Promise((resolve) => {
101
152
  rewardResolve = resolve;
102
153
  });
103
154
 
104
- const wxApi = api();
105
- if (!adId || !wxApi?.createRewardedVideoAd) {
155
+ if (!adId) {
106
156
  finish({ ok: false });
107
157
  return rewardPromise;
108
158
  }
109
159
 
110
- clearReward();
111
- rewardAd = wxApi.createRewardedVideoAd({ adUnitId: adId });
112
- rewardAd.onLoad?.(() => {});
113
- rewardClose = (res: { isEnded?: boolean }) => {
114
- finish({ ok: !!res?.isEnded, isEnded: !!res?.isEnded });
115
- };
116
- rewardError = (err: unknown) => {
117
- console.error("激励视频广告加载失败", err);
118
- finish({ ok: false, err });
119
- };
120
- rewardAd.onClose?.(rewardClose);
121
- rewardAd.onError?.(rewardError);
160
+ const api = getAdApi();
161
+ if (!api?.createRewardedVideoAd) {
162
+ finish({ ok: false });
163
+ return rewardPromise;
164
+ }
165
+
166
+ activeRewardAdId = adId;
167
+ if (!rewardCache.has(adId)) {
168
+ try {
169
+ const ad = api.createRewardedVideoAd({ adUnitId: adId });
170
+ ad.onLoad?.(() => console.log(`[HlwAd] Rewarded video loaded: ${adId}`));
171
+ ad.onError?.((err: unknown) => {
172
+ console.error("[HlwAd] Rewarded video load error:", err);
173
+ if (activeRewardAdId === adId) {
174
+ finish({ ok: false, err });
175
+ }
176
+ });
177
+ ad.onClose?.((res: { isEnded?: boolean }) => {
178
+ if (activeRewardAdId === adId) {
179
+ const isEnded = !!res?.isEnded;
180
+ finish({ ok: isEnded, isEnded });
181
+ }
182
+ });
183
+ rewardCache.set(adId, ad);
184
+ } catch (e) {
185
+ console.error("[HlwAd] Rewarded video creation failed:", e);
186
+ finish({ ok: false, err: e });
187
+ }
188
+ }
122
189
  return rewardPromise;
123
190
  }
124
191
 
192
+ /**
193
+ * 立即播放已加载的激励视频广告。
194
+ *
195
+ * @returns 返回 Promise<AdRes>,指示广告是否正常播放完毕
196
+ */
125
197
  function showAdReward(): Promise<AdRes> {
126
- if (!rewardAd) {
198
+ const ad = rewardCache.get(activeRewardAdId);
199
+ if (!ad) {
127
200
  return Promise.resolve({ ok: false });
128
201
  }
129
202
 
@@ -132,11 +205,11 @@ export function useHlwAd() {
132
205
  });
133
206
  rewardPromise = current;
134
207
 
135
- rewardAd.show().catch(() => {
136
- rewardAd.load()
137
- .then(() => rewardAd.show())
208
+ ad.show().catch(() => {
209
+ ad.load()
210
+ .then(() => ad.show())
138
211
  .catch((err: unknown) => {
139
- console.error("激励视频广告显示失败", err);
212
+ console.error("[HlwAd] Rewarded video show error:", err);
140
213
  finish({ ok: false, err });
141
214
  });
142
215
  });
@@ -151,3 +224,4 @@ export function useHlwAd() {
151
224
  showAdReward,
152
225
  };
153
226
  }
227
+
@@ -1,8 +1,12 @@
1
1
  /**
2
2
  * useDevice - 设备信息与接口 query
3
+ * 提供一致的、缓存后的多端设备系统信息接口。
3
4
  */
4
- import { useUtils } from "../utils";
5
+ import { toQuery } from "../utils";
5
6
 
7
+ /**
8
+ * 完整设备系统信息接口,包含小程序环境与宿主系统的关键元数据。
9
+ */
6
10
  export interface DeviceInfo {
7
11
  /** 小程序 appId */
8
12
  appid: string;
@@ -62,6 +66,9 @@ export interface DeviceInfo {
62
66
  version: string;
63
67
  }
64
68
 
69
+ /**
70
+ * 过滤后常用于接口公共请求 Query 的设备字段子集。
71
+ */
65
72
  export type DeviceQueryInfo = Pick<DeviceInfo,
66
73
  | "appid"
67
74
  | "device_brand"
@@ -86,6 +93,9 @@ export type DeviceQueryInfo = Pick<DeviceInfo,
86
93
 
87
94
  let deviceCache: DeviceInfo | null = null;
88
95
 
96
+ /**
97
+ * 安全地执行获取系统信息的函数,防止环境不支持导致异常崩溃。
98
+ */
89
99
  function readSafe(fn: (() => unknown) | undefined): Record<string, unknown> {
90
100
  try {
91
101
  return (fn?.() ?? {}) as Record<string, unknown>;
@@ -94,6 +104,9 @@ function readSafe(fn: (() => unknown) | undefined): Record<string, unknown> {
94
104
  }
95
105
  }
96
106
 
107
+ /**
108
+ * 从运行期 API 采集设备与系统属性,建立标准化数据。
109
+ */
97
110
  function collectDevice(): DeviceInfo {
98
111
  // @ts-ignore - 新 API 在旧版 @dcloudio/types 中可能未声明。
99
112
  let device = readSafe(uni.getDeviceInfo);
@@ -142,6 +155,9 @@ function collectDevice(): DeviceInfo {
142
155
  };
143
156
  }
144
157
 
158
+ /**
159
+ * 尝试从小程序运行期 context 中读取 AppId。
160
+ */
145
161
  function getAppid(device: Record<string, unknown>) {
146
162
  try {
147
163
  const account = uni.getAccountInfoSync() as { miniProgram?: { appId?: string } };
@@ -151,11 +167,17 @@ function getAppid(device: Record<string, unknown>) {
151
167
  }
152
168
  }
153
169
 
170
+ /**
171
+ * 读取或延迟初始化缓存的设备信息。
172
+ */
154
173
  function getDevice() {
155
174
  deviceCache ??= collectDevice();
156
175
  return deviceCache;
157
176
  }
158
177
 
178
+ /**
179
+ * 抽取供接口调用的缩略版设备 query 字段。
180
+ */
159
181
  function getQueryInfo(info: DeviceInfo): DeviceQueryInfo {
160
182
  return {
161
183
  appid: info.appid,
@@ -180,9 +202,13 @@ function getQueryInfo(info: DeviceInfo): DeviceQueryInfo {
180
202
  };
181
203
  }
182
204
 
205
+ /**
206
+ * 访问当前设备配置信息的 hooks。
207
+ *
208
+ * @returns 包含 `info` (原始数据) 和 `query` (用于 HTTP 报头/URL query 的 urlencoded 字符串)
209
+ */
183
210
  export function useDevice() {
184
211
  const info = getDevice();
185
- const { toQuery } = useUtils();
186
212
 
187
213
  return {
188
214
  info,
@@ -190,6 +216,10 @@ export function useDevice() {
190
216
  };
191
217
  }
192
218
 
219
+ /**
220
+ * 清除本地设备信息缓存,使下一次读取重新走系统调用收集。
221
+ */
193
222
  export function clearDeviceCache(): void {
194
223
  deviceCache = null;
195
224
  }
225
+
@@ -15,7 +15,24 @@ export {
15
15
  type ShareConfig,
16
16
  } from "./share";
17
17
  export { useHlwAd, type AdRes } from "./ad";
18
- export { useUtils, type DownloadOpt, type DownloadRes } from "./utils";
18
+ export {
19
+ useUtils,
20
+ withQuery,
21
+ toQuery,
22
+ signText,
23
+ toNumber,
24
+ toBoolean,
25
+ copy,
26
+ paste,
27
+ auth,
28
+ saveImage,
29
+ saveVideoFile,
30
+ download,
31
+ saveImageUrl,
32
+ saveVideoUrl,
33
+ type DownloadOpt,
34
+ type DownloadRes,
35
+ } from "./utils";
19
36
  export { useNavigate, type NavigateType, type NavigateOptions } from "./navigator";
20
37
 
21
38
  // Theme(mp-vue 自带)
@@ -1,52 +1,111 @@
1
1
  /**
2
2
  * useMsg - 消息提示 composable
3
+ * 封装并统一小程序原生的 Toast、Loading 与模态弹窗 API。
3
4
  */
4
- export type ToastIcon = "success" | "fail" | "exception" | "none";
5
+
6
+ /** Toast 支持的图标类型 */
7
+ export type ToastIcon = "success" | "loading" | "error" | "none" | "fail" | "exception";
8
+ /** Toast 持续时间的预设档位 */
5
9
  export type ToastDuration = "short" | "long";
6
10
 
11
+ /**
12
+ * Toast 轻提示配置项。
13
+ */
7
14
  export interface ToastOptions {
15
+ /** 提示的消息内容 */
8
16
  message: string;
17
+ /** 显示的图标类型,默认为 'none' */
9
18
  icon?: ToastIcon;
19
+ /** 自定义图标的本地/网络图片路径(如传入,将忽略 icon 属性) */
10
20
  image?: string;
21
+ /** 持续时间,单位毫秒,默认 2000ms */
11
22
  duration?: number;
23
+ /** 是否显示透明蒙层防止穿透点击,默认 false */
12
24
  mask?: boolean;
25
+ /** 提示框的悬浮位置,仅在某些平台下生效 */
13
26
  position?: "top" | "center" | "bottom";
14
27
  }
15
28
 
29
+ /**
30
+ * 模态确认对话框配置项。
31
+ */
16
32
  export interface ModalOptions {
33
+ /** 弹窗标题,默认 '提示' */
17
34
  title?: string;
35
+ /** 弹窗内容 */
18
36
  content: string;
37
+ /** 确认按钮的文字,默认 '确定' */
19
38
  confirmText?: string;
39
+ /** 取消按钮的文字,默认 '取消' */
20
40
  cancelText?: string;
41
+ /** 确认按钮的文字颜色,默认使用主题蓝色 */
21
42
  confirmColor?: string;
43
+ /** 取消按钮的文字颜色,默认灰色 */
22
44
  cancelColor?: string;
23
- /** false=隐藏取消按钮(纯提示弹窗用) */
45
+ /** 是否显示取消按钮,若为 false 则只有确认按钮,默认 true */
24
46
  showCancel?: boolean;
25
47
  }
26
48
 
49
+ /**
50
+ * useMsg 返回的方法与接口实例。
51
+ */
27
52
  export interface HlwMsg {
53
+ /** 显示普通 Toast 轻提示,支持配置对象或纯文本 */
28
54
  toast(opts: ToastOptions | string): void;
55
+ /** 显示成功提示 (含成功图标) */
29
56
  success(message: string): void;
57
+ /** 显示失败提示 (含错误图标) */
30
58
  error(message: string): void;
59
+ /** 显示失败提示 (含错误图标) —— error 方法的别名 */
31
60
  fail(message: string): void;
61
+ /** 显示全局模态 Loading 状态,默认显示 "加载中..." */
32
62
  showLoading(message?: string): void;
63
+ /** 关闭全局 Loading 状态 */
33
64
  hideLoading(): void;
65
+ /** 弹出确认模态框,返回 Promise<boolean> 代表用户是否点击了“确认” */
34
66
  confirm(opts: ModalOptions): Promise<boolean>;
67
+ /** 弹出确认模态框 —— confirm 方法的别名 */
35
68
  modal(opts: ModalOptions): Promise<boolean>;
69
+ /** 利用手机端导航栏标题动态展现一个文本模拟的进度条 */
36
70
  setLoadingBar(progress: number): void;
37
71
  }
38
72
 
39
73
  /**
40
- * 统一的消息提示与弹窗能力。
74
+ * 统一的消息提示与弹窗能力 hook。
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * const msg = useMsg();
79
+ * msg.toast('操作成功');
80
+ * msg.showLoading('保存中...');
81
+ * const ok = await msg.confirm({ content: '确定删除吗?' });
82
+ * ```
41
83
  */
42
84
  export function useMsg(): HlwMsg {
43
85
  /**
44
86
  * 显示普通 toast,支持字符串或完整配置。
45
87
  */
46
88
  function toast(opts: ToastOptions | string) {
47
- const normalized: ToastOptions = typeof opts === "string" ? { message: opts } : opts;
48
- const { message, icon = "none", image, duration = 2000, mask = false, position = "center" } = normalized;
49
- uni.showToast({ title: message, icon, image, duration, mask, position });
89
+ const {
90
+ message,
91
+ icon = "none",
92
+ image = undefined,
93
+ duration = 2000,
94
+ mask = false,
95
+ position = "center",
96
+ } = typeof opts === "string" ? { message: opts } : opts;
97
+
98
+ // 兼容映射旧版自定义失败图标到标准 error 图标
99
+ const mappedIcon = (icon === "fail" || icon === "exception") ? "error" : icon;
100
+
101
+ uni.showToast({
102
+ title: message,
103
+ icon: mappedIcon as "success" | "loading" | "error" | "none",
104
+ image,
105
+ duration,
106
+ mask,
107
+ position,
108
+ });
50
109
  }
51
110
 
52
111
  /**
@@ -60,7 +119,7 @@ export function useMsg(): HlwMsg {
60
119
  * 显示失败提示。
61
120
  */
62
121
  function error(message: string) {
63
- uni.showToast({ title: message, icon: "fail", duration: 2000 });
122
+ uni.showToast({ title: message, icon: "error", duration: 2000 });
64
123
  }
65
124
 
66
125
  /**
@@ -105,20 +164,14 @@ export function useMsg(): HlwMsg {
105
164
  });
106
165
  }
107
166
 
108
- /**
109
- * modal 是 confirm 的语义别名。
110
- */
111
- function modal(opts: ModalOptions): Promise<boolean> {
112
- return confirm(opts);
113
- }
114
-
115
167
  /**
116
168
  * 通过标题文本模拟简单进度条展示。
117
169
  */
118
170
  function setLoadingBar(progress: number) {
119
171
  const clamped = Math.max(0, Math.min(100, progress));
172
+ const filled = Math.round(clamped / 2);
120
173
  uni.setNavigationBarTitle({
121
- title: `${"■".repeat(Math.round(clamped / 2))}${"□".repeat(50 - Math.round(clamped / 2))} ${clamped}%`,
174
+ title: `${"■".repeat(filled)}${"□".repeat(50 - filled)} ${clamped}%`,
122
175
  });
123
176
  }
124
177
 
@@ -130,7 +183,8 @@ export function useMsg(): HlwMsg {
130
183
  showLoading,
131
184
  hideLoading,
132
185
  confirm,
133
- modal,
186
+ modal: confirm,
134
187
  setLoadingBar,
135
188
  };
136
189
  }
190
+
@@ -1,6 +1,9 @@
1
1
  /**
2
- * useNavigate - uni-app 跳转工具
2
+ * useNavigate - uni-app 路由跳转工具
3
+ * 封装并统一原生的页面跳转、重定向、Switch Tab、返回、以及打开外部小程序或 WebView 等方法。
3
4
  */
5
+
6
+ /** 页面跳转类型,支持微信小程序的各类路由动作与 WebView/小程序跳转 */
4
7
  export type NavigateType =
5
8
  | "navigateTo"
6
9
  | "redirectTo"
@@ -11,17 +14,29 @@ export type NavigateType =
11
14
  | "webview"
12
15
  | (string & {});
13
16
 
17
+ /**
18
+ * 路由跳转的额外配置选项。
19
+ */
14
20
  export interface NavigateOptions {
21
+ /** 发生失败时是否静默不抛出/显示 Toast 提示,默认 false */
15
22
  silent?: boolean;
23
+ /** 页面跳转失败时的回调 */
16
24
  onFail?: (message: string) => void;
25
+ /** 返回上级页面的层数,仅在 type="navigateBack" 时生效,默认 1 */
17
26
  delta?: number;
27
+ /** 打开外部小程序时的页面路径,仅在 type="miniprogram" 时生效 */
18
28
  path?: string;
29
+ /** 打开外部小程序的环境版本 (开发/体验/正式),仅在 type="miniprogram" 时生效 */
19
30
  envVersion?: "develop" | "trial" | "release";
31
+ /** 传递给目标小程序的额外数据 */
20
32
  extraData?: Record<string, unknown>;
21
33
  }
22
34
 
23
35
  type UniFail = { errMsg?: string };
24
36
 
37
+ /**
38
+ * 集中处理跳转失败时的提示与回调。
39
+ */
25
40
  function fail(message: string, options: NavigateOptions = {}) {
26
41
  if (!options.silent) {
27
42
  uni.showToast({ title: message, icon: "none" });
@@ -29,12 +44,22 @@ function fail(message: string, options: NavigateOptions = {}) {
29
44
  options.onFail?.(message);
30
45
  }
31
46
 
47
+ /**
48
+ * 创建符合 uni-app 失败规范的回调处理函数。
49
+ */
32
50
  function failHandler(target: string, options: NavigateOptions = {}) {
33
51
  return (error?: UniFail) => {
34
52
  fail(error?.errMsg || `无法跳转:${target}`, options);
35
53
  };
36
54
  }
37
55
 
56
+ /**
57
+ * 核心的底层页面路由分发方法。
58
+ *
59
+ * @param type 跳转动作类型
60
+ * @param url 跳转目标路径或小程序 AppId
61
+ * @param options 额外的控制参数
62
+ */
38
63
  function navigate(type: NavigateType = "navigateTo", url = "", options: NavigateOptions = {}) {
39
64
  if (type === "navigateBack") {
40
65
  uni.navigateBack({ delta: options.delta || 1, fail: failHandler("返回上一页", options) });
@@ -91,14 +116,33 @@ function navigate(type: NavigateType = "navigateTo", url = "", options: Navigate
91
116
  uni.navigateTo({ url, fail: onFail });
92
117
  }
93
118
 
119
+ /**
120
+ * 路由跳转工具 hooks。
121
+ *
122
+ * @example
123
+ * ```ts
124
+ * const router = useNavigate();
125
+ * router.to('/pages/index/index');
126
+ * router.back();
127
+ * router.miniProgram('app-id');
128
+ * ```
129
+ */
94
130
  export function useNavigate() {
95
131
  return {
132
+ /** 核心底层路由分发函数 */
96
133
  navigate,
134
+ /** 保留当前页面,跳转到应用内的某个页面 */
97
135
  to: (url: string, options?: NavigateOptions) => navigate("navigateTo", url, options),
136
+ /** 关闭当前页面,跳转到应用内的某个页面 */
98
137
  redirect: (url: string, options?: NavigateOptions) => navigate("redirectTo", url, options),
138
+ /** 跳转到 switchTab 页面,并关闭其他所有非 tabBar 页面 */
99
139
  tab: (url: string, options?: NavigateOptions) => navigate("switchTab", url, options),
140
+ /** 关闭所有页面,打开到应用内的某个页面 */
100
141
  reLaunch: (url: string, options?: NavigateOptions) => navigate("reLaunch", url, options),
142
+ /** 关闭当前页面,返回上一页面或多级页面 */
101
143
  back: (delta = 1, options: NavigateOptions = {}) => navigate("navigateBack", "", { ...options, delta }),
144
+ /** 打开另一个小程序 */
102
145
  miniProgram: (appId: string, options?: NavigateOptions) => navigate("miniprogram", appId, options),
103
146
  };
104
147
  }
148
+