@hlw-uni/mp-vue 2.1.54 → 2.1.55

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.
@@ -0,0 +1,16 @@
1
+ /**
2
+ * 小程序广告工具。
3
+ */
4
+ export interface AdRes {
5
+ ok: boolean;
6
+ isEnded?: boolean;
7
+ err?: unknown;
8
+ }
9
+ type AdDone = (res: AdRes) => void;
10
+ export declare function useHlwAd(): {
11
+ setAdPopup: (adId: string, done?: ((ok: boolean) => void) | undefined) => boolean;
12
+ showAdPopup: (delay?: number) => Promise<boolean>;
13
+ setAdReward: (adId: string, done?: AdDone) => Promise<AdRes>;
14
+ showAdReward: () => Promise<AdRes>;
15
+ };
16
+ export {};
@@ -6,6 +6,7 @@ export { useMsg, type HlwMsg, type ToastOptions, type ModalOptions, type ToastIc
6
6
  export { useDevice, clearDeviceCache, type DeviceInfo, type DeviceQueryInfo, } from './device';
7
7
  export { useRefs } from './refs';
8
8
  export { useShare, type ShareConfig, } from './share';
9
+ export { useHlwAd, type AdRes } from './ad';
9
10
  export { useUtils, type DownloadOpt, type DownloadRes } from './utils';
10
11
  export { useNavigate, type NavigateType, type NavigateOptions } from './navigator';
11
12
  export type { FontScale, FontPreset } from './theme';
package/dist/index.js CHANGED
@@ -34,6 +34,7 @@ var __publicField = (obj, key, value) => {
34
34
  buildFormData(ctx) {
35
35
  const c = ctx.credentials ?? {};
36
36
  return {
37
+ key: c["key"] ?? ctx.fileName,
37
38
  policy: c["policy"] ?? "",
38
39
  signature: c["signature"] ?? "",
39
40
  OSSAccessKeyId: c["accessKeyId"] ?? "",
@@ -630,8 +631,8 @@ var __publicField = (obj, key, value) => {
630
631
  }
631
632
  function showShareMenu() {
632
633
  var _a;
633
- const api = typeof uni !== "undefined" ? uni : void 0;
634
- (_a = api == null ? void 0 : api.showShareMenu) == null ? void 0 : _a.call(api, {
634
+ const api2 = typeof uni !== "undefined" ? uni : void 0;
635
+ (_a = api2 == null ? void 0 : api2.showShareMenu) == null ? void 0 : _a.call(api2, {
635
636
  withShareTicket: true,
636
637
  menus: ["shareAppMessage", "shareTimeline"],
637
638
  fail: () => void 0
@@ -670,6 +671,137 @@ var __publicField = (obj, key, value) => {
670
671
  showShareMenu
671
672
  };
672
673
  }
674
+ let popupAd = null;
675
+ let popupDone;
676
+ let popupClose = null;
677
+ let popupError = null;
678
+ let rewardAd = null;
679
+ let rewardDone;
680
+ let rewardPromise = null;
681
+ let rewardResolve = null;
682
+ let rewardClose = null;
683
+ let rewardError = null;
684
+ function api() {
685
+ return typeof wx === "undefined" ? null : wx;
686
+ }
687
+ function finish(res) {
688
+ rewardDone == null ? void 0 : rewardDone(res);
689
+ rewardResolve == null ? void 0 : rewardResolve(res);
690
+ rewardResolve = null;
691
+ rewardPromise = null;
692
+ }
693
+ function clearReward() {
694
+ var _a, _b;
695
+ if (!rewardAd)
696
+ return;
697
+ if (rewardClose)
698
+ (_a = rewardAd.offClose) == null ? void 0 : _a.call(rewardAd, rewardClose);
699
+ if (rewardError)
700
+ (_b = rewardAd.offError) == null ? void 0 : _b.call(rewardAd, rewardError);
701
+ rewardClose = null;
702
+ rewardError = null;
703
+ }
704
+ function useHlwAd() {
705
+ function clearPopup() {
706
+ var _a, _b;
707
+ if (!popupAd)
708
+ return;
709
+ if (popupClose)
710
+ (_a = popupAd.offClose) == null ? void 0 : _a.call(popupAd, popupClose);
711
+ if (popupError)
712
+ (_b = popupAd.offError) == null ? void 0 : _b.call(popupAd, popupError);
713
+ popupClose = null;
714
+ popupError = null;
715
+ }
716
+ function setAdPopup(adId, done) {
717
+ var _a, _b, _c;
718
+ popupDone = done;
719
+ const wxApi = api();
720
+ if (!adId || !(wxApi == null ? void 0 : wxApi.createInterstitialAd))
721
+ return false;
722
+ clearPopup();
723
+ popupAd = wxApi.createInterstitialAd({ adUnitId: adId });
724
+ (_a = popupAd.onLoad) == null ? void 0 : _a.call(popupAd, () => {
725
+ });
726
+ popupError = (err) => {
727
+ console.error("插屏广告加载失败", err);
728
+ popupDone == null ? void 0 : popupDone(false);
729
+ };
730
+ popupClose = () => {
731
+ popupDone == null ? void 0 : popupDone(true);
732
+ };
733
+ (_b = popupAd.onError) == null ? void 0 : _b.call(popupAd, popupError);
734
+ (_c = popupAd.onClose) == null ? void 0 : _c.call(popupAd, popupClose);
735
+ return true;
736
+ }
737
+ function showAdPopup(delay = 3e3) {
738
+ return new Promise((resolve) => {
739
+ if (!popupAd) {
740
+ resolve(false);
741
+ return;
742
+ }
743
+ const done = popupDone;
744
+ popupDone = (ok) => {
745
+ done == null ? void 0 : done(ok);
746
+ resolve(ok);
747
+ };
748
+ setTimeout(() => {
749
+ popupAd.show().catch((err) => {
750
+ console.error("插屏广告显示失败", err);
751
+ popupDone == null ? void 0 : popupDone(false);
752
+ });
753
+ }, Math.max(0, delay));
754
+ });
755
+ }
756
+ function setAdReward(adId, done) {
757
+ var _a, _b, _c;
758
+ rewardDone = done;
759
+ rewardPromise = new Promise((resolve) => {
760
+ rewardResolve = resolve;
761
+ });
762
+ const wxApi = api();
763
+ if (!adId || !(wxApi == null ? void 0 : wxApi.createRewardedVideoAd)) {
764
+ finish({ ok: false });
765
+ return rewardPromise;
766
+ }
767
+ clearReward();
768
+ rewardAd = wxApi.createRewardedVideoAd({ adUnitId: adId });
769
+ (_a = rewardAd.onLoad) == null ? void 0 : _a.call(rewardAd, () => {
770
+ });
771
+ rewardClose = (res) => {
772
+ finish({ ok: !!(res == null ? void 0 : res.isEnded), isEnded: !!(res == null ? void 0 : res.isEnded) });
773
+ };
774
+ rewardError = (err) => {
775
+ console.error("激励视频广告加载失败", err);
776
+ finish({ ok: false, err });
777
+ };
778
+ (_b = rewardAd.onClose) == null ? void 0 : _b.call(rewardAd, rewardClose);
779
+ (_c = rewardAd.onError) == null ? void 0 : _c.call(rewardAd, rewardError);
780
+ return rewardPromise;
781
+ }
782
+ function showAdReward() {
783
+ if (!rewardAd) {
784
+ return Promise.resolve({ ok: false });
785
+ }
786
+ const current = rewardPromise || new Promise((resolve) => {
787
+ rewardResolve = resolve;
788
+ });
789
+ rewardPromise = current;
790
+ rewardAd.show().catch(() => {
791
+ rewardAd.load().then(() => rewardAd.show()).catch((err) => {
792
+ console.error("激励视频广告显示失败", err);
793
+ finish({ ok: false, err });
794
+ });
795
+ });
796
+ return current;
797
+ }
798
+ return {
799
+ setAdPopup,
800
+ showAdPopup,
801
+ setAdReward,
802
+ showAdReward
803
+ };
804
+ }
673
805
  function fail(message, options = {}) {
674
806
  var _a;
675
807
  if (!options.silent) {
@@ -1200,6 +1332,7 @@ var __publicField = (obj, key, value) => {
1200
1332
  exports2.resolveAppearance = resolveAppearance;
1201
1333
  exports2.useApp = useApp;
1202
1334
  exports2.useDevice = useDevice;
1335
+ exports2.useHlwAd = useHlwAd;
1203
1336
  exports2.useMsg = useMsg;
1204
1337
  exports2.useNavigate = useNavigate;
1205
1338
  exports2.useRefs = useRefs;
package/dist/index.mjs CHANGED
@@ -33,6 +33,7 @@ const ossAdapter = {
33
33
  buildFormData(ctx) {
34
34
  const c = ctx.credentials ?? {};
35
35
  return {
36
+ key: c["key"] ?? ctx.fileName,
36
37
  policy: c["policy"] ?? "",
37
38
  signature: c["signature"] ?? "",
38
39
  OSSAccessKeyId: c["accessKeyId"] ?? "",
@@ -629,8 +630,8 @@ function buildPayload(base, extra) {
629
630
  }
630
631
  function showShareMenu() {
631
632
  var _a;
632
- const api = typeof uni !== "undefined" ? uni : void 0;
633
- (_a = api == null ? void 0 : api.showShareMenu) == null ? void 0 : _a.call(api, {
633
+ const api2 = typeof uni !== "undefined" ? uni : void 0;
634
+ (_a = api2 == null ? void 0 : api2.showShareMenu) == null ? void 0 : _a.call(api2, {
634
635
  withShareTicket: true,
635
636
  menus: ["shareAppMessage", "shareTimeline"],
636
637
  fail: () => void 0
@@ -669,6 +670,137 @@ function useShare(config = {}) {
669
670
  showShareMenu
670
671
  };
671
672
  }
673
+ let popupAd = null;
674
+ let popupDone;
675
+ let popupClose = null;
676
+ let popupError = null;
677
+ let rewardAd = null;
678
+ let rewardDone;
679
+ let rewardPromise = null;
680
+ let rewardResolve = null;
681
+ let rewardClose = null;
682
+ let rewardError = null;
683
+ function api() {
684
+ return typeof wx === "undefined" ? null : wx;
685
+ }
686
+ function finish(res) {
687
+ rewardDone == null ? void 0 : rewardDone(res);
688
+ rewardResolve == null ? void 0 : rewardResolve(res);
689
+ rewardResolve = null;
690
+ rewardPromise = null;
691
+ }
692
+ function clearReward() {
693
+ var _a, _b;
694
+ if (!rewardAd)
695
+ return;
696
+ if (rewardClose)
697
+ (_a = rewardAd.offClose) == null ? void 0 : _a.call(rewardAd, rewardClose);
698
+ if (rewardError)
699
+ (_b = rewardAd.offError) == null ? void 0 : _b.call(rewardAd, rewardError);
700
+ rewardClose = null;
701
+ rewardError = null;
702
+ }
703
+ function useHlwAd() {
704
+ function clearPopup() {
705
+ var _a, _b;
706
+ if (!popupAd)
707
+ return;
708
+ if (popupClose)
709
+ (_a = popupAd.offClose) == null ? void 0 : _a.call(popupAd, popupClose);
710
+ if (popupError)
711
+ (_b = popupAd.offError) == null ? void 0 : _b.call(popupAd, popupError);
712
+ popupClose = null;
713
+ popupError = null;
714
+ }
715
+ function setAdPopup(adId, done) {
716
+ var _a, _b, _c;
717
+ popupDone = done;
718
+ const wxApi = api();
719
+ if (!adId || !(wxApi == null ? void 0 : wxApi.createInterstitialAd))
720
+ return false;
721
+ clearPopup();
722
+ popupAd = wxApi.createInterstitialAd({ adUnitId: adId });
723
+ (_a = popupAd.onLoad) == null ? void 0 : _a.call(popupAd, () => {
724
+ });
725
+ popupError = (err) => {
726
+ console.error("插屏广告加载失败", err);
727
+ popupDone == null ? void 0 : popupDone(false);
728
+ };
729
+ popupClose = () => {
730
+ popupDone == null ? void 0 : popupDone(true);
731
+ };
732
+ (_b = popupAd.onError) == null ? void 0 : _b.call(popupAd, popupError);
733
+ (_c = popupAd.onClose) == null ? void 0 : _c.call(popupAd, popupClose);
734
+ return true;
735
+ }
736
+ function showAdPopup(delay = 3e3) {
737
+ return new Promise((resolve) => {
738
+ if (!popupAd) {
739
+ resolve(false);
740
+ return;
741
+ }
742
+ const done = popupDone;
743
+ popupDone = (ok) => {
744
+ done == null ? void 0 : done(ok);
745
+ resolve(ok);
746
+ };
747
+ setTimeout(() => {
748
+ popupAd.show().catch((err) => {
749
+ console.error("插屏广告显示失败", err);
750
+ popupDone == null ? void 0 : popupDone(false);
751
+ });
752
+ }, Math.max(0, delay));
753
+ });
754
+ }
755
+ function setAdReward(adId, done) {
756
+ var _a, _b, _c;
757
+ rewardDone = done;
758
+ rewardPromise = new Promise((resolve) => {
759
+ rewardResolve = resolve;
760
+ });
761
+ const wxApi = api();
762
+ if (!adId || !(wxApi == null ? void 0 : wxApi.createRewardedVideoAd)) {
763
+ finish({ ok: false });
764
+ return rewardPromise;
765
+ }
766
+ clearReward();
767
+ rewardAd = wxApi.createRewardedVideoAd({ adUnitId: adId });
768
+ (_a = rewardAd.onLoad) == null ? void 0 : _a.call(rewardAd, () => {
769
+ });
770
+ rewardClose = (res) => {
771
+ finish({ ok: !!(res == null ? void 0 : res.isEnded), isEnded: !!(res == null ? void 0 : res.isEnded) });
772
+ };
773
+ rewardError = (err) => {
774
+ console.error("激励视频广告加载失败", err);
775
+ finish({ ok: false, err });
776
+ };
777
+ (_b = rewardAd.onClose) == null ? void 0 : _b.call(rewardAd, rewardClose);
778
+ (_c = rewardAd.onError) == null ? void 0 : _c.call(rewardAd, rewardError);
779
+ return rewardPromise;
780
+ }
781
+ function showAdReward() {
782
+ if (!rewardAd) {
783
+ return Promise.resolve({ ok: false });
784
+ }
785
+ const current = rewardPromise || new Promise((resolve) => {
786
+ rewardResolve = resolve;
787
+ });
788
+ rewardPromise = current;
789
+ rewardAd.show().catch(() => {
790
+ rewardAd.load().then(() => rewardAd.show()).catch((err) => {
791
+ console.error("激励视频广告显示失败", err);
792
+ finish({ ok: false, err });
793
+ });
794
+ });
795
+ return current;
796
+ }
797
+ return {
798
+ setAdPopup,
799
+ showAdPopup,
800
+ setAdReward,
801
+ showAdReward
802
+ };
803
+ }
672
804
  function fail(message, options = {}) {
673
805
  var _a;
674
806
  if (!options.silent) {
@@ -1200,6 +1332,7 @@ export {
1200
1332
  resolveAppearance,
1201
1333
  useApp,
1202
1334
  useDevice,
1335
+ useHlwAd,
1203
1336
  useMsg,
1204
1337
  useNavigate,
1205
1338
  useRefs,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hlw-uni/mp-vue",
3
- "version": "2.1.54",
3
+ "version": "2.1.55",
4
4
  "description": "hlw-uni 小程序运行时 — Vue 组件 + composables + theme + http + 工具集(合并自原 mp-core)",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -81,12 +81,13 @@ function onError(event: any) {
81
81
  background: var(--surface-card, #ffffff);
82
82
  }
83
83
 
84
- /* 格子广告:默认右下悬浮;微信硬性规则要求 wrapper 透明无圆角,customStyle 可覆盖 */
84
+ /* 格子广告:默认右侧居中悬浮;微信硬性规则要求 wrapper 透明无圆角,customStyle 可覆盖 */
85
85
  .hlw-ad--grid {
86
86
  position: fixed;
87
- right: 20rpx;
88
- bottom: 200rpx;
87
+ top: 50%;
88
+ right: 0;
89
89
  z-index: 99;
90
+ transform: translateY(-50%);
90
91
  border-radius: 0;
91
92
  overflow: visible;
92
93
  background: transparent;
@@ -0,0 +1,58 @@
1
+ # ad 调用文档
2
+
3
+ `useHlwAd` 封装微信小程序插屏广告和激励视频广告。仅在存在 `wx` 且对应广告 API 可用时生效。
4
+
5
+ ## 引入
6
+
7
+ ```ts
8
+ import { useHlwAd } from "@hlw-uni/mp-vue";
9
+ ```
10
+
11
+ ## 插屏广告
12
+
13
+ ```ts
14
+ const ad = useHlwAd();
15
+
16
+ ad.setAdPopup("adunit-popup-id", (ok) => {
17
+ console.log("插屏广告关闭", ok);
18
+ });
19
+
20
+ await ad.showAdPopup(1000);
21
+ ```
22
+
23
+ ## 激励视频
24
+
25
+ ```ts
26
+ const ad = useHlwAd();
27
+
28
+ ad.setAdReward("adunit-reward-id", (res) => {
29
+ if (res.ok) {
30
+ // 用户完整看完激励视频
31
+ }
32
+ });
33
+
34
+ const result = await ad.showAdReward();
35
+
36
+ if (result.ok) {
37
+ // 发放奖励
38
+ }
39
+ ```
40
+
41
+ ## API
42
+
43
+ | 方法 | 说明 |
44
+ | --- | --- |
45
+ | `setAdPopup(adId, done?)` | 创建插屏广告实例 |
46
+ | `showAdPopup(delay?)` | 延迟展示插屏广告,默认 3000ms |
47
+ | `setAdReward(adId, done?)` | 创建激励视频实例 |
48
+ | `showAdReward()` | 展示激励视频,失败时会尝试 load 后再 show |
49
+
50
+ ## 类型
51
+
52
+ ```ts
53
+ interface AdRes {
54
+ ok: boolean;
55
+ isEnded?: boolean;
56
+ err?: unknown;
57
+ }
58
+ ```
@@ -0,0 +1,153 @@
1
+ /**
2
+ * 小程序广告工具。
3
+ */
4
+
5
+ declare const wx: any;
6
+
7
+ export interface AdRes {
8
+ ok: boolean;
9
+ isEnded?: boolean;
10
+ err?: unknown;
11
+ }
12
+
13
+ type AdDone = (res: AdRes) => void;
14
+
15
+ let popupAd: any = null;
16
+ let popupDone: ((ok: boolean) => void) | undefined;
17
+ let popupClose: (() => void) | null = null;
18
+ let popupError: ((err: unknown) => void) | null = null;
19
+
20
+ let rewardAd: any = null;
21
+ let rewardDone: AdDone | undefined;
22
+ let rewardPromise: Promise<AdRes> | null = null;
23
+ 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
+
27
+ function api() {
28
+ return typeof wx === "undefined" ? null : wx;
29
+ }
30
+
31
+ function finish(res: AdRes) {
32
+ rewardDone?.(res);
33
+ rewardResolve?.(res);
34
+ rewardResolve = null;
35
+ rewardPromise = null;
36
+ }
37
+
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
+
46
+ 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
+
55
+ function setAdPopup(adId: string, done?: (ok: boolean) => void): boolean {
56
+ 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);
72
+ return true;
73
+ }
74
+
75
+ function showAdPopup(delay = 3000): Promise<boolean> {
76
+ return new Promise((resolve) => {
77
+ if (!popupAd) {
78
+ resolve(false);
79
+ return;
80
+ }
81
+
82
+ const done = popupDone;
83
+ popupDone = (ok: boolean) => {
84
+ done?.(ok);
85
+ resolve(ok);
86
+ };
87
+
88
+ setTimeout(() => {
89
+ popupAd.show().catch((err: unknown) => {
90
+ console.error("插屏广告显示失败", err);
91
+ popupDone?.(false);
92
+ });
93
+ }, Math.max(0, delay));
94
+ });
95
+ }
96
+
97
+
98
+ function setAdReward(adId: string, done?: AdDone): Promise<AdRes> {
99
+ rewardDone = done;
100
+ rewardPromise = new Promise((resolve) => {
101
+ rewardResolve = resolve;
102
+ });
103
+
104
+ const wxApi = api();
105
+ if (!adId || !wxApi?.createRewardedVideoAd) {
106
+ finish({ ok: false });
107
+ return rewardPromise;
108
+ }
109
+
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);
122
+ return rewardPromise;
123
+ }
124
+
125
+ function showAdReward(): Promise<AdRes> {
126
+ if (!rewardAd) {
127
+ return Promise.resolve({ ok: false });
128
+ }
129
+
130
+ const current = rewardPromise || new Promise<AdRes>((resolve) => {
131
+ rewardResolve = resolve;
132
+ });
133
+ rewardPromise = current;
134
+
135
+ rewardAd.show().catch(() => {
136
+ rewardAd.load()
137
+ .then(() => rewardAd.show())
138
+ .catch((err: unknown) => {
139
+ console.error("激励视频广告显示失败", err);
140
+ finish({ ok: false, err });
141
+ });
142
+ });
143
+
144
+ return current;
145
+ }
146
+
147
+ return {
148
+ setAdPopup,
149
+ showAdPopup,
150
+ setAdReward,
151
+ showAdReward,
152
+ };
153
+ }
@@ -0,0 +1,50 @@
1
+ # device 调用文档
2
+
3
+ `useDevice` 采集并缓存设备、窗口、宿主和小程序信息,同时提供常用设备字段组成的 query 字符串。
4
+
5
+ ## 引入
6
+
7
+ ```ts
8
+ import { useDevice, clearDeviceCache } from "@hlw-uni/mp-vue";
9
+ ```
10
+
11
+ ## 基础用法
12
+
13
+ ```ts
14
+ const { info, query } = useDevice();
15
+
16
+ console.log(info.appid);
17
+ console.log(info.device_model);
18
+ console.log(query);
19
+ ```
20
+
21
+ `useDevice` 内部会优先读取 `uni.getDeviceInfo`、`uni.getWindowInfo`、`uni.getAppBaseInfo`,旧环境会回退到 `uni.getSystemInfoSync`。
22
+
23
+ ## 清除缓存
24
+
25
+ ```ts
26
+ clearDeviceCache();
27
+ ```
28
+
29
+ 切换账号、切换宿主环境或需要重新采集设备信息时可以手动清理缓存。
30
+
31
+ ## 返回值
32
+
33
+ | 字段 | 说明 |
34
+ | --- | --- |
35
+ | `info` | 完整 `DeviceInfo` |
36
+ | `query` | 常用设备字段组成的 URL query 字符串 |
37
+
38
+ ## 常用字段
39
+
40
+ | 字段 | 说明 |
41
+ | --- | --- |
42
+ | `appid` | 小程序 appId |
43
+ | `device_brand` | 设备品牌 |
44
+ | `device_model` | 设备型号 |
45
+ | `device_id` | 设备 ID |
46
+ | `platform` | 平台类型 |
47
+ | `system` | 系统版本 |
48
+ | `sdk_version` | 基础库版本 |
49
+ | `screen_width` | 屏幕宽度 |
50
+ | `screen_height` | 屏幕高度 |
@@ -14,6 +14,7 @@ export {
14
14
  useShare,
15
15
  type ShareConfig,
16
16
  } from "./share";
17
+ export { useHlwAd, type AdRes } from "./ad";
17
18
  export { useUtils, type DownloadOpt, type DownloadRes } from "./utils";
18
19
  export { useNavigate, type NavigateType, type NavigateOptions } from "./navigator";
19
20
 
@@ -0,0 +1,79 @@
1
+ # msg 调用文档
2
+
3
+ `useMsg` 统一封装 toast、loading、modal 和简单进度展示。
4
+
5
+ ## 引入
6
+
7
+ ```ts
8
+ import { useMsg } from "@hlw-uni/mp-vue";
9
+ ```
10
+
11
+ ## 基础用法
12
+
13
+ ```ts
14
+ const msg = useMsg();
15
+
16
+ msg.toast("保存中");
17
+ msg.success("保存成功");
18
+ msg.error("保存失败");
19
+
20
+ msg.showLoading("加载中...");
21
+ msg.hideLoading();
22
+ ```
23
+
24
+ ## 确认弹窗
25
+
26
+ ```ts
27
+ const ok = await msg.confirm({
28
+ title: "删除确认",
29
+ content: "确定删除这条记录吗?",
30
+ confirmText: "删除",
31
+ });
32
+
33
+ if (ok) {
34
+ // 用户点击确认
35
+ }
36
+ ```
37
+
38
+ `modal` 是 `confirm` 的语义别名。
39
+
40
+ ## API
41
+
42
+ | 方法 | 说明 |
43
+ | --- | --- |
44
+ | `toast(opts | string)` | 普通提示 |
45
+ | `success(message)` | 成功提示 |
46
+ | `error(message)` | 失败提示 |
47
+ | `fail(message)` | `error` 的别名 |
48
+ | `showLoading(message?)` | 显示全局 loading |
49
+ | `hideLoading()` | 关闭全局 loading |
50
+ | `confirm(opts)` | 确认弹窗,返回 `Promise<boolean>` |
51
+ | `modal(opts)` | `confirm` 的别名 |
52
+ | `setLoadingBar(progress)` | 用导航标题模拟进度 |
53
+
54
+ ## ToastOptions
55
+
56
+ ```ts
57
+ interface ToastOptions {
58
+ message: string;
59
+ icon?: "success" | "fail" | "exception" | "none";
60
+ image?: string;
61
+ duration?: number;
62
+ mask?: boolean;
63
+ position?: "top" | "center" | "bottom";
64
+ }
65
+ ```
66
+
67
+ ## ModalOptions
68
+
69
+ ```ts
70
+ interface ModalOptions {
71
+ title?: string;
72
+ content: string;
73
+ confirmText?: string;
74
+ cancelText?: string;
75
+ confirmColor?: string;
76
+ cancelColor?: string;
77
+ showCancel?: boolean;
78
+ }
79
+ ```
@@ -0,0 +1,71 @@
1
+ # navigator 调用文档
2
+
3
+ `useNavigate` 统一封装 uni-app 页面跳转、tab 跳转、返回和打开其他小程序。
4
+
5
+ ## 引入
6
+
7
+ ```ts
8
+ import { useNavigate } from "@hlw-uni/mp-vue";
9
+ ```
10
+
11
+ ## 基础用法
12
+
13
+ ```ts
14
+ const nav = useNavigate();
15
+
16
+ nav.to("/pages/detail/index?id=1");
17
+ nav.redirect("/pages/login/index");
18
+ nav.tab("/pages/index/index");
19
+ nav.reLaunch("/pages/index/index");
20
+ nav.back();
21
+ ```
22
+
23
+ ## 打开其他小程序
24
+
25
+ ```ts
26
+ nav.miniProgram("wx1234567890", {
27
+ path: "pages/index/index?id=1",
28
+ envVersion: "release",
29
+ extraData: {
30
+ from: "hlw",
31
+ },
32
+ });
33
+ ```
34
+
35
+ ## 通用跳转
36
+
37
+ ```ts
38
+ nav.navigate("navigateTo", "/pages/detail/index?id=1", {
39
+ silent: true,
40
+ onFail: (message) => {
41
+ console.log(message);
42
+ },
43
+ });
44
+ ```
45
+
46
+ ## API
47
+
48
+ | 方法 | 说明 |
49
+ | --- | --- |
50
+ | `navigate(type, url, options?)` | 通用跳转入口 |
51
+ | `to(url, options?)` | `uni.navigateTo` |
52
+ | `redirect(url, options?)` | `uni.redirectTo` |
53
+ | `tab(url, options?)` | `uni.switchTab` |
54
+ | `reLaunch(url, options?)` | `uni.reLaunch` |
55
+ | `back(delta?, options?)` | `uni.navigateBack` |
56
+ | `miniProgram(appId, options?)` | `uni.navigateToMiniProgram` |
57
+
58
+ ## NavigateOptions
59
+
60
+ ```ts
61
+ interface NavigateOptions {
62
+ silent?: boolean;
63
+ onFail?: (message: string) => void;
64
+ delta?: number;
65
+ path?: string;
66
+ envVersion?: "develop" | "trial" | "release";
67
+ extraData?: Record<string, unknown>;
68
+ }
69
+ ```
70
+
71
+ `webview` 类型当前只提示 `H5:{url}`,具体 web-view 承载页由业务项目实现。
@@ -0,0 +1,40 @@
1
+ # refs 调用文档
2
+
3
+ `useRefs` 用于 `v-for` 场景批量收集组件或元素引用。
4
+
5
+ ## 引入
6
+
7
+ ```ts
8
+ import { useRefs } from "@hlw-uni/mp-vue";
9
+ ```
10
+
11
+ ## 基础用法
12
+
13
+ ```vue
14
+ <template>
15
+ <hlw-popup
16
+ v-for="item in list"
17
+ :key="item.id"
18
+ :ref="setRefs(item.id)"
19
+ />
20
+ </template>
21
+
22
+ <script setup lang="ts">
23
+ import { useRefs } from "@hlw-uni/mp-vue";
24
+
25
+ const { refs, setRefs } = useRefs();
26
+
27
+ function open(id: string) {
28
+ refs.value[id]?.open?.();
29
+ }
30
+ </script>
31
+ ```
32
+
33
+ ## 返回值
34
+
35
+ | 字段 | 说明 |
36
+ | --- | --- |
37
+ | `refs` | `Record<string, any>` 的响应式引用集合 |
38
+ | `setRefs(key)` | 返回可绑定到模板 `ref` 的回调函数 |
39
+
40
+ 组件更新前和卸载时,内部会自动清空引用集合,避免旧引用残留。
@@ -0,0 +1,124 @@
1
+ # request 调用文档
2
+
3
+ `request` 模块封装 `uni.request`、请求拦截器、响应拦截器、错误拦截器、上传和服务类组织方式。
4
+
5
+ ## 引入
6
+
7
+ ```ts
8
+ import {
9
+ useRequest,
10
+ useUpload,
11
+ BaseService,
12
+ ServiceNamespace,
13
+ ServicePrefix,
14
+ } from "@hlw-uni/mp-vue";
15
+ ```
16
+
17
+ ## useRequest
18
+
19
+ ```ts
20
+ const request = useRequest();
21
+
22
+ request.setBaseURL("https://api.example.com");
23
+
24
+ const offRequest = request.onRequest((config) => {
25
+ config.headers = {
26
+ ...config.headers,
27
+ "x-token": uni.getStorageSync("token"),
28
+ };
29
+ return config;
30
+ });
31
+
32
+ const res = await request.get<{ name: string }>("/user/profile");
33
+
34
+ offRequest();
35
+ ```
36
+
37
+ ## API
38
+
39
+ | 方法 | 说明 |
40
+ | --- | --- |
41
+ | `request(config)` | 发起完整配置请求 |
42
+ | `get(url, data?)` | GET 请求 |
43
+ | `post(url, data?)` | POST 请求 |
44
+ | `put(url, data?)` | PUT 请求 |
45
+ | `del(url, data?)` | DELETE 请求 |
46
+ | `setBaseURL(url)` | 设置全局基础地址 |
47
+ | `onRequest(fn)` | 注册请求拦截器,返回取消函数 |
48
+ | `onResponse(fn)` | 注册响应拦截器,返回取消函数 |
49
+ | `onError(fn)` | 注册错误拦截器,返回取消函数 |
50
+ | `upload(config)` | 上传文件 |
51
+ | `resolveServiceUrl(namespace, url, servicePrefix?)` | 生成服务类请求地址 |
52
+
53
+ ## 响应格式
54
+
55
+ ```ts
56
+ interface ApiResponse<T = unknown> {
57
+ code: number;
58
+ data: T;
59
+ info: string;
60
+ }
61
+ ```
62
+
63
+ ## useUpload
64
+
65
+ ```ts
66
+ const { uploading, upload } = useUpload();
67
+
68
+ const result = await upload({
69
+ type: "local",
70
+ server: "https://api.example.com/upload",
71
+ url: "https://api.example.com/upload",
72
+ filePath: tempFilePath,
73
+ header: {
74
+ "x-token": uni.getStorageSync("token"),
75
+ },
76
+ });
77
+
78
+ console.log(uploading.value, result.data);
79
+ ```
80
+
81
+ 上传类型:
82
+
83
+ | 类型 | 说明 |
84
+ | --- | --- |
85
+ | `local` | 直接上传到业务接口 |
86
+ | `cos` | 腾讯云 COS 表单上传 |
87
+ | `oss` | 阿里云 OSS 表单上传 |
88
+ | `qiniu` | 七牛云表单上传 |
89
+ | `alist` | Alist 上传 |
90
+
91
+ ## BaseService
92
+
93
+ ```ts
94
+ @ServicePrefix("api")
95
+ @ServiceNamespace("user")
96
+ class UserService extends BaseService {
97
+ profile() {
98
+ return this.get<{ nickname: string }>("/profile");
99
+ }
100
+
101
+ update(data: { nickname: string }) {
102
+ return this.post("/update", data);
103
+ }
104
+ }
105
+
106
+ const userService = new UserService();
107
+ const profile = await userService.profile();
108
+ ```
109
+
110
+ 上面的 `profile()` 会请求 `/api/user/profile`。如果传入绝对地址,例如 `https://example.com/a`,则不会拼接前缀。
111
+
112
+ ## UploadConfig
113
+
114
+ ```ts
115
+ interface UploadConfig {
116
+ server: string;
117
+ filePath: string;
118
+ fileName?: string;
119
+ type: string;
120
+ credentials?: Record<string, string>;
121
+ header?: Record<string, string>;
122
+ url?: string;
123
+ }
124
+ ```
@@ -11,6 +11,7 @@ export const ossAdapter: UploadAdapter = {
11
11
  buildFormData(ctx) {
12
12
  const c = ctx.credentials ?? {};
13
13
  return {
14
+ key: c["key"] ?? ctx.fileName,
14
15
  policy: c["policy"] ?? "",
15
16
  signature: c["signature"] ?? "",
16
17
  OSSAccessKeyId: c["accessKeyId"] ?? "",
@@ -0,0 +1,53 @@
1
+ # share 调用文档
2
+
3
+ `useShare` 注册微信小程序分享给好友和分享到朋友圈,并尝试打开分享菜单。
4
+
5
+ ## 引入
6
+
7
+ ```ts
8
+ import { useShare } from "@hlw-uni/mp-vue";
9
+ ```
10
+
11
+ ## 基础用法
12
+
13
+ ```ts
14
+ useShare({
15
+ title: "好用的小程序",
16
+ path: "/pages/index/index?from=share",
17
+ imageUrl: "https://example.com/share.png",
18
+ });
19
+ ```
20
+
21
+ ## 动态分享内容
22
+
23
+ ```ts
24
+ const share = useShare(() => ({
25
+ title: detail.value.title,
26
+ path: `/pages/detail/index?id=${detail.value.id}`,
27
+ imageUrl: detail.value.cover,
28
+ }));
29
+
30
+ share.onShareAppMessage({
31
+ title: "覆盖好友分享标题",
32
+ });
33
+ ```
34
+
35
+ ## API
36
+
37
+ | 方法 | 说明 |
38
+ | --- | --- |
39
+ | `onShareAppMessage(config?)` | 注册好友分享 |
40
+ | `onShareTimeline(config?)` | 注册朋友圈分享 |
41
+ | `showShareMenu()` | 主动显示分享菜单 |
42
+
43
+ 同一个 `useShare` 实例中,好友分享和朋友圈分享各只注册一次。
44
+
45
+ ## ShareConfig
46
+
47
+ ```ts
48
+ interface ShareConfig {
49
+ title?: string;
50
+ path?: string;
51
+ imageUrl?: string;
52
+ }
53
+ ```
@@ -0,0 +1,131 @@
1
+ # theme 调用文档
2
+
3
+ `theme` 模块提供字体档位、主题色、外观模式、排版 token 和 `page-meta` 样式注入能力。
4
+
5
+ ## 引入
6
+
7
+ ```ts
8
+ import {
9
+ useThemePageStyle,
10
+ getCurrentFontScale,
11
+ getCurrentFontVars,
12
+ getCurrentThemeColor,
13
+ getCurrentThemeVars,
14
+ getCurrentAppearance,
15
+ getCurrentAppearanceMode,
16
+ getCurrentAppearanceVars,
17
+ getCurrentTypographyVars,
18
+ } from "@hlw-uni/mp-vue";
19
+ ```
20
+
21
+ ## useThemePageStyle
22
+
23
+ 页面需要把主题 CSS 变量注入到小程序 page 根时使用。
24
+
25
+ ```vue
26
+ <template>
27
+ <page-meta :page-style="themePageStyle" />
28
+ <hlw-page>
29
+ 页面内容
30
+ </hlw-page>
31
+ </template>
32
+
33
+ <script setup lang="ts">
34
+ import { useThemePageStyle } from "@hlw-uni/mp-vue";
35
+
36
+ const { themePageStyle } = useThemePageStyle();
37
+ </script>
38
+ ```
39
+
40
+ 如果项目启用了 `@hlw-uni/mp-vite-plugin` 的 `themePageMeta`,页面可由插件自动注入 `<page-meta>` 和 `useThemePageStyle`。
41
+
42
+ ## 字体档位
43
+
44
+ ```ts
45
+ const scale = getCurrentFontScale();
46
+ const vars = getCurrentFontVars();
47
+
48
+ console.log(scale, vars["--font-base"]);
49
+ ```
50
+
51
+ 支持的 `FontScale`:
52
+
53
+ | 值 | 说明 |
54
+ | --- | --- |
55
+ | `small` | 较小 |
56
+ | `compact` | 略小 |
57
+ | `normal` | 标准 |
58
+ | `medium` | 适中 |
59
+ | `large` | 较大 |
60
+ | `xlarge` | 超大 |
61
+ | `xxlarge` | 特大 |
62
+
63
+ ## 主题色
64
+
65
+ ```ts
66
+ const color = getCurrentThemeColor();
67
+ const vars = getCurrentThemeVars();
68
+
69
+ console.log(color, vars["--primary-color"]);
70
+ ```
71
+
72
+ 常用导出:
73
+
74
+ | 导出 | 说明 |
75
+ | --- | --- |
76
+ | `THEME_COLOR_KEY` | 主题色 storage key |
77
+ | `THEME_SEMANTIC_COLORS` | 语义色 |
78
+ | `DEFAULT_THEMES` | 内置主题色列表 |
79
+ | `getCurrentThemeColor()` | 读取当前主题色 |
80
+ | `getCurrentThemeVars()` | 生成主题色 CSS 变量 |
81
+
82
+ ## 外观模式
83
+
84
+ ```ts
85
+ const appearance = getCurrentAppearance();
86
+ const mode = getCurrentAppearanceMode();
87
+ const vars = getCurrentAppearanceVars();
88
+
89
+ console.log(appearance, mode, vars["--bg-page"]);
90
+ ```
91
+
92
+ `Appearance` 支持:
93
+
94
+ | 值 | 说明 |
95
+ | --- | --- |
96
+ | `light` | 浅色模式 |
97
+ | `dark` | 深色模式 |
98
+ | `auto` | 跟随系统 |
99
+
100
+ ## 排版 token
101
+
102
+ ```ts
103
+ const vars = getCurrentTypographyVars();
104
+
105
+ console.log(vars["--text-title-size"]);
106
+ ```
107
+
108
+ 内置语义角色:
109
+
110
+ | 角色 | 用途 |
111
+ | --- | --- |
112
+ | `title-lg` | 页面大标题 |
113
+ | `title` | 卡片或分区主标题 |
114
+ | `subtitle` | 次级标题 |
115
+ | `body` | 正文 |
116
+ | `desc` | 描述文字 |
117
+ | `caption` | 角标、时间戳等小字 |
118
+
119
+ ## 切换主题
120
+
121
+ 主题状态由 `useThemeStore` 管理,store 会写入 storage,`useThemePageStyle` 会响应 `scale` 和 `primaryColor` 变化。
122
+
123
+ ```ts
124
+ import { useThemeStore } from "@hlw-uni/mp-vue";
125
+
126
+ const theme = useThemeStore();
127
+
128
+ theme.setScale("large");
129
+ theme.setTheme("#3b82f6");
130
+ theme.setAppearance("auto");
131
+ ```
@@ -0,0 +1,81 @@
1
+ # utils 调用文档
2
+
3
+ `useUtils` 提供剪贴板、下载、保存相册、query 拼接和基础类型转换工具。
4
+
5
+ ## 引入
6
+
7
+ ```ts
8
+ import { useUtils } from "@hlw-uni/mp-vue";
9
+ ```
10
+
11
+ ## 基础用法
12
+
13
+ ```ts
14
+ const utils = useUtils();
15
+
16
+ await utils.copy("要复制的文本");
17
+ const text = await utils.paste();
18
+
19
+ const qs = utils.toQuery({ id: 1, keyword: "测试" });
20
+ const url = utils.withQuery("/pages/search/index", qs);
21
+
22
+ const age = utils.toNumber("18", 0);
23
+ const enabled = utils.toBoolean("1", false);
24
+ ```
25
+
26
+ ## 下载和保存
27
+
28
+ ```ts
29
+ const res = await utils.download({
30
+ url: "https://example.com/a.png",
31
+ progress: (value, done, total) => {
32
+ console.log(value, done, total);
33
+ },
34
+ });
35
+
36
+ if (res.ok && res.path) {
37
+ await utils.saveImage(res.path);
38
+ }
39
+
40
+ await utils.saveImageUrl("https://example.com/a.png");
41
+ await utils.saveVideoUrl("https://example.com/a.mp4");
42
+ ```
43
+
44
+ ## API
45
+
46
+ | 方法 | 说明 |
47
+ | --- | --- |
48
+ | `withQuery(url, qs)` | 为 URL 追加 query |
49
+ | `toQuery(data)` | 对象转 URL query |
50
+ | `signText(url)` | 生成签名原文,query 会排序 |
51
+ | `toNumber(value, defaultValue)` | 安全转数字 |
52
+ | `toBoolean(value, defaultValue)` | 安全转布尔 |
53
+ | `copy(text, tip?)` | 复制文本 |
54
+ | `paste()` | 读取剪贴板 |
55
+ | `saveImage(path)` | 保存本地图片到相册 |
56
+ | `saveVideo(path)` | 保存本地视频到相册 |
57
+ | `download(options)` | 下载文件 |
58
+ | `saveImageUrl(url, progress?)` | 下载远程图片并保存 |
59
+ | `saveVideoUrl(url, progress?)` | 下载远程视频并保存 |
60
+
61
+ ## DownloadOpt
62
+
63
+ ```ts
64
+ interface DownloadOpt {
65
+ url: string;
66
+ path?: string;
67
+ header?: Record<string, string>;
68
+ progress?: (value: number, done: number, total: number) => void;
69
+ }
70
+ ```
71
+
72
+ ## DownloadRes
73
+
74
+ ```ts
75
+ interface DownloadRes {
76
+ ok: boolean;
77
+ path?: string;
78
+ code?: number;
79
+ msg?: string;
80
+ }
81
+ ```