vite-uni-dev-tool 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +120 -0
- package/dev/components/Button/index.vue +34 -0
- package/dev/components/Checkbox/index.vue +40 -0
- package/dev/components/CloseButton/index.vue +25 -0
- package/dev/components/Connection/index.vue +98 -0
- package/dev/components/ConsoleList/ConsoleItem.vue +89 -0
- package/dev/components/ConsoleList/index.vue +98 -0
- package/dev/components/DevTool/index.vue +165 -0
- package/dev/components/DevToolButton/index.vue +213 -0
- package/dev/components/DevToolWindow/index.vue +847 -0
- package/dev/components/DeviceInfo/index.vue +32 -0
- package/dev/components/Empty/empty.png +0 -0
- package/dev/components/Empty/index.vue +28 -0
- package/dev/components/FilterInput/index.vue +86 -0
- package/dev/components/JsonPretty/components/Brackets/index.vue +23 -0
- package/dev/components/JsonPretty/components/Carets/index.vue +63 -0
- package/dev/components/JsonPretty/components/CheckController/index.vue +108 -0
- package/dev/components/JsonPretty/components/TreeNode/index.vue +348 -0
- package/dev/components/JsonPretty/hooks/useClipboard.ts +21 -0
- package/dev/components/JsonPretty/hooks/useError.ts +21 -0
- package/dev/components/JsonPretty/index.vue +463 -0
- package/dev/components/JsonPretty/type.ts +123 -0
- package/dev/components/JsonPretty/utils/index.ts +172 -0
- package/dev/components/NetworkList/NetworkDetail.vue +197 -0
- package/dev/components/NetworkList/NetworkItem.vue +106 -0
- package/dev/components/NetworkList/index.vue +108 -0
- package/dev/components/PiniaList/index.vue +64 -0
- package/dev/components/RouteList/index.vue +98 -0
- package/dev/components/SettingList/index.vue +235 -0
- package/dev/components/StorageList/index.vue +170 -0
- package/dev/components/SystemInfo/index.vue +34 -0
- package/dev/components/Tabs/index.vue +110 -0
- package/dev/components/Tag/index.vue +89 -0
- package/dev/components/UploadList/UploadDetail.vue +208 -0
- package/dev/components/UploadList/UploadItem.vue +111 -0
- package/dev/components/UploadList/index.vue +94 -0
- package/dev/components/VuexList/index.vue +54 -0
- package/dev/components/WebSocket/WebSocketItem.vue +98 -0
- package/dev/components/WebSocket/WebSocketList.vue +176 -0
- package/dev/components/WebSocket/index.vue +99 -0
- package/dev/components/WindowInfo/index.vue +33 -0
- package/dev/const.ts +95 -0
- package/dev/core.ts +103 -0
- package/dev/devConsole/index.ts +334 -0
- package/dev/devEvent/index.ts +665 -0
- package/dev/devIntercept/index.ts +629 -0
- package/dev/devStore/index.ts +581 -0
- package/dev/index.d.ts +6 -0
- package/dev/index.d.ts.map +1 -0
- package/dev/index.js +1 -0
- package/dev/plugins/uniDevTool/uniDevTool.d.ts +66 -0
- package/dev/plugins/uniDevTool/uniDevTool.d.ts.map +1 -0
- package/dev/plugins/uniDevTool/uniDevTool.js +13 -0
- package/dev/plugins/uniGlobalComponents/uniGlobalComponents.d.ts +28 -0
- package/dev/plugins/uniGlobalComponents/uniGlobalComponents.d.ts.map +1 -0
- package/dev/plugins/uniGlobalComponents/uniGlobalComponents.js +5 -0
- package/dev/shims-uni.d.ts +43 -0
- package/dev/type.ts +188 -0
- package/dev/utils/date.ts +75 -0
- package/dev/utils/file.ts +121 -0
- package/dev/utils/function.ts +192 -0
- package/dev/utils/index.ts +25 -0
- package/dev/utils/ip.ts +79 -0
- package/dev/utils/language.ts +19 -0
- package/dev/utils/object.ts +235 -0
- package/dev/utils/page.ts +13 -0
- package/dev/utils/string.ts +23 -0
- package/dev/utils/utils.ts +198 -0
- package/package.json +34 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";const o=/<template[^>]*>([\s\S]*?)<\/template>/;function m({pages:s,components:a}){return{name:"uni-global-components",enforce:"pre",transform(t,n){if(n.endsWith(".vue")){const l=t.includes("<template>");if(s.pages.some(e=>n.includes(e.path))&&l){const e=t.match(o);if(e&&e[1]){const p=`${e[1].trim()}
|
|
2
|
+
${a.join(`
|
|
3
|
+
`)}`;return{code:t.replace(o,`<template>
|
|
4
|
+
${p}
|
|
5
|
+
</template>`),map:null}}}}return{code:t,map:null}}}}module.exports=m;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/// <reference types='@dcloudio/types' />
|
|
2
|
+
import 'vue';
|
|
3
|
+
|
|
4
|
+
declare module 'vue' {
|
|
5
|
+
type Hooks = App.AppInstance & Page.PageInstance;
|
|
6
|
+
interface ComponentCustomOptions extends Hooks {}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
declare global {
|
|
11
|
+
interface Uni {
|
|
12
|
+
/**
|
|
13
|
+
* 小程序下拥有的环境变量
|
|
14
|
+
* 目前微信小程序下支持
|
|
15
|
+
*/
|
|
16
|
+
env: {
|
|
17
|
+
USER_DATA_PATH: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
__dev__console: {
|
|
22
|
+
log: Function;
|
|
23
|
+
error: Function;
|
|
24
|
+
warn: Function;
|
|
25
|
+
info: Function;
|
|
26
|
+
time: Function;
|
|
27
|
+
timeEnd: Function;
|
|
28
|
+
clear: Function;
|
|
29
|
+
count: Function;
|
|
30
|
+
countReset: Function;
|
|
31
|
+
assert: Function;
|
|
32
|
+
debug: Function;
|
|
33
|
+
dir: Function;
|
|
34
|
+
dirxml: Function;
|
|
35
|
+
group: Function;
|
|
36
|
+
groupCollapsed: Function;
|
|
37
|
+
groupEnd: Function;
|
|
38
|
+
table: Function;
|
|
39
|
+
timeStamp: Function;
|
|
40
|
+
trace: Function;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
package/dev/type.ts
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { DevEvent } from './devEvent';
|
|
2
|
+
export declare namespace DevTool {
|
|
3
|
+
type Page = {
|
|
4
|
+
index?: number;
|
|
5
|
+
path: string;
|
|
6
|
+
sort?: number;
|
|
7
|
+
name?: string;
|
|
8
|
+
isNav?: boolean;
|
|
9
|
+
style: {
|
|
10
|
+
navigationBarTitleText?: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type Message = {
|
|
15
|
+
type: 'success' | 'error';
|
|
16
|
+
data: string;
|
|
17
|
+
time: number;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
type WS = {
|
|
21
|
+
url: string;
|
|
22
|
+
/**
|
|
23
|
+
* -1: error
|
|
24
|
+
* 0:connecting
|
|
25
|
+
* 1:open
|
|
26
|
+
* 2:closing
|
|
27
|
+
* 3:closed
|
|
28
|
+
*/
|
|
29
|
+
readyState?: string;
|
|
30
|
+
headers?: { key: string; value: string }[];
|
|
31
|
+
method?: string;
|
|
32
|
+
protocols?: string[];
|
|
33
|
+
message: Message[];
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
type Nav = {
|
|
37
|
+
pagePath: string;
|
|
38
|
+
text: string;
|
|
39
|
+
};
|
|
40
|
+
type PagesJSON = {
|
|
41
|
+
pages: Page[];
|
|
42
|
+
tabBar: {
|
|
43
|
+
list: Nav[];
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
type DevToolOptions = {
|
|
48
|
+
/** 是否拦截Promise.reject 最好不要拦截 默认禁用 */
|
|
49
|
+
enableInterceptPromiseReject?: boolean;
|
|
50
|
+
/** 打开窗口时隐藏按钮 */
|
|
51
|
+
openWindowHideButton?: boolean;
|
|
52
|
+
/** 最大的console条数 */
|
|
53
|
+
consoleMaxSize?: number;
|
|
54
|
+
/** 最大的网络请求条数 */
|
|
55
|
+
networkMaxSize?: number;
|
|
56
|
+
/** 最大的上传文件条数 */
|
|
57
|
+
uploadMaxSize?: number;
|
|
58
|
+
/** 最大的套接字消息条数 */
|
|
59
|
+
wsDataMaxSize?: number;
|
|
60
|
+
/** 最大占用缓存空间 */
|
|
61
|
+
cacheMaxSize?: number;
|
|
62
|
+
/** 所有路由信息 */
|
|
63
|
+
pagesJson?: PagesJSON;
|
|
64
|
+
} & ButtonOptions;
|
|
65
|
+
|
|
66
|
+
type ButtonOptions = Partial<{
|
|
67
|
+
/** 按钮大小 */
|
|
68
|
+
buttonSize: number;
|
|
69
|
+
/** 按钮文本 */
|
|
70
|
+
buttonText: string;
|
|
71
|
+
/** 按钮文本颜色 */
|
|
72
|
+
buttonColor: string;
|
|
73
|
+
/** 按钮字体大小 */
|
|
74
|
+
buttonFontSize: string;
|
|
75
|
+
/** 按钮背景颜色 */
|
|
76
|
+
buttonBackgroundColor: string;
|
|
77
|
+
/** 初始化时是否显示调试按钮,默认显示 */
|
|
78
|
+
initShowDevTool: boolean;
|
|
79
|
+
}>;
|
|
80
|
+
|
|
81
|
+
type NetworkItem = {
|
|
82
|
+
index: number;
|
|
83
|
+
url: string;
|
|
84
|
+
name: string;
|
|
85
|
+
method: string;
|
|
86
|
+
status: number | string;
|
|
87
|
+
time: string;
|
|
88
|
+
startTime: number;
|
|
89
|
+
endTime: number;
|
|
90
|
+
size: string;
|
|
91
|
+
headers: {
|
|
92
|
+
requestHeader: { key: string; value: any }[];
|
|
93
|
+
responseHeader: { key: string; value: any }[];
|
|
94
|
+
};
|
|
95
|
+
response: string;
|
|
96
|
+
payload: any;
|
|
97
|
+
};
|
|
98
|
+
type StorageItem = {
|
|
99
|
+
key: string;
|
|
100
|
+
_oldKey: string;
|
|
101
|
+
value: string;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/** 调试工具目前支持处理的console类型 */
|
|
105
|
+
type ConsoleType =
|
|
106
|
+
| 'log'
|
|
107
|
+
| 'info'
|
|
108
|
+
| 'warn'
|
|
109
|
+
| 'error'
|
|
110
|
+
| 'timeEnd'
|
|
111
|
+
| 'time'
|
|
112
|
+
| 'clear'
|
|
113
|
+
| 'count';
|
|
114
|
+
|
|
115
|
+
/** 不支持处理的console类型 */
|
|
116
|
+
type OriginalConsoleType =
|
|
117
|
+
| 'assert'
|
|
118
|
+
| 'count'
|
|
119
|
+
| 'countReset'
|
|
120
|
+
| 'debug'
|
|
121
|
+
| 'dir'
|
|
122
|
+
| 'dirxml'
|
|
123
|
+
| 'group'
|
|
124
|
+
| 'groupCollapsed'
|
|
125
|
+
| 'groupEnd'
|
|
126
|
+
| 'table'
|
|
127
|
+
| 'trace'
|
|
128
|
+
| 'profile'
|
|
129
|
+
| 'profileEnd'
|
|
130
|
+
| 'timeStamp';
|
|
131
|
+
|
|
132
|
+
type ConsoleItem = {
|
|
133
|
+
type: string;
|
|
134
|
+
args: any[];
|
|
135
|
+
position: string;
|
|
136
|
+
time: string;
|
|
137
|
+
stack?: string;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
type UploadItem = {
|
|
141
|
+
index: number;
|
|
142
|
+
url?: string;
|
|
143
|
+
filePath?: string;
|
|
144
|
+
formData?: Record<string, any>;
|
|
145
|
+
method?: string;
|
|
146
|
+
headers?: {
|
|
147
|
+
requestHeader?: { key: string; value: unknown }[];
|
|
148
|
+
responseHeader?: { key: string; value: unknown }[];
|
|
149
|
+
};
|
|
150
|
+
response?: Record<string, any>;
|
|
151
|
+
files?: any[];
|
|
152
|
+
fileType?: string;
|
|
153
|
+
name?: string;
|
|
154
|
+
status: number | string;
|
|
155
|
+
timeout?: number;
|
|
156
|
+
startTime?: number;
|
|
157
|
+
endTime?: number;
|
|
158
|
+
/** 上传进度 */
|
|
159
|
+
progress?: number;
|
|
160
|
+
/** 已上传长度 */
|
|
161
|
+
totalBytesSent?: number;
|
|
162
|
+
/** 预计上传总长度 */
|
|
163
|
+
totalBytesExpectedToSend?: number;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
type WindowData = {
|
|
167
|
+
devToolVisible?: boolean;
|
|
168
|
+
consoleList?: ConsoleItem[];
|
|
169
|
+
networkList?: NetworkItem[];
|
|
170
|
+
storageList?: StorageItem[];
|
|
171
|
+
routeList?: Page[];
|
|
172
|
+
vuexList?: Record<string, any>;
|
|
173
|
+
piniaList?: Record<string, any>;
|
|
174
|
+
systemInfo?: Record<string, any>;
|
|
175
|
+
deviceInfo?: Record<string, any>;
|
|
176
|
+
windowInfo?: Record<string, any>;
|
|
177
|
+
netWorkStatus?: Record<string, any>;
|
|
178
|
+
wsList?: WS[];
|
|
179
|
+
size?: number;
|
|
180
|
+
sizeFormat?: string;
|
|
181
|
+
uploadList?: UploadItem[];
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
type DevInterceptOptions = {
|
|
185
|
+
event: DevEvent;
|
|
186
|
+
enableInterceptPromiseReject?: boolean;
|
|
187
|
+
};
|
|
188
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export function getCurrentDate() {
|
|
2
|
+
const date = new Date();
|
|
3
|
+
const year = date.getFullYear();
|
|
4
|
+
const month = date.getMonth() + 1;
|
|
5
|
+
const day = date.getDate();
|
|
6
|
+
const hour = date.getHours();
|
|
7
|
+
const minute = date.getMinutes();
|
|
8
|
+
const second = date.getSeconds();
|
|
9
|
+
return `${year}-${month.toString().padStart(2, '0')}-${day
|
|
10
|
+
.toString()
|
|
11
|
+
.padStart(2, '0')} ${hour.toString().padStart(2, '0')}:${minute
|
|
12
|
+
.toString()
|
|
13
|
+
.padStart(2, '0')}:${second?.toString().padStart(2, '0')}`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 格式化时间
|
|
18
|
+
*
|
|
19
|
+
* @export
|
|
20
|
+
* @param {(Date | string | number)} date
|
|
21
|
+
* @param {string} format
|
|
22
|
+
* @return {*} {string}
|
|
23
|
+
*/
|
|
24
|
+
export function formatDate(
|
|
25
|
+
date: Date | string | number,
|
|
26
|
+
format: string,
|
|
27
|
+
): string {
|
|
28
|
+
let dateObj: Date;
|
|
29
|
+
|
|
30
|
+
if (date instanceof Date) {
|
|
31
|
+
dateObj = date;
|
|
32
|
+
} else {
|
|
33
|
+
dateObj = new Date(date);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (isNaN(dateObj.getTime())) {
|
|
37
|
+
throw new Error('Invalid date');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const formatMap: Record<string, string | number> = {
|
|
41
|
+
YYYY: dateObj.getFullYear(),
|
|
42
|
+
MM: String(dateObj.getMonth() + 1).padStart(2, '0'),
|
|
43
|
+
M: dateObj.getMonth() + 1,
|
|
44
|
+
DD: String(dateObj.getDate()).padStart(2, '0'),
|
|
45
|
+
D: dateObj.getDate(),
|
|
46
|
+
HH: String(dateObj.getHours()).padStart(2, '0'),
|
|
47
|
+
H: dateObj.getHours(),
|
|
48
|
+
hh: String(dateObj.getHours() % 12 || 12).padStart(2, '0'),
|
|
49
|
+
h: dateObj.getHours() % 12 || 12,
|
|
50
|
+
mm: String(dateObj.getMinutes()).padStart(2, '0'),
|
|
51
|
+
m: dateObj.getMinutes(),
|
|
52
|
+
ss: String(dateObj.getSeconds()).padStart(2, '0'),
|
|
53
|
+
s: dateObj.getSeconds(),
|
|
54
|
+
SS: String(dateObj.getMilliseconds()).padStart(3, '0'),
|
|
55
|
+
S: dateObj.getMilliseconds(),
|
|
56
|
+
A: dateObj.getHours() >= 12 ? 'PM' : 'AM',
|
|
57
|
+
a: dateObj.getHours() >= 12 ? 'pm' : 'am',
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
return format.replace(
|
|
61
|
+
/YYYY|MM|DD|HH|hh|mm|ss|SS|A|a|M|D|H|h|m|s|S/g,
|
|
62
|
+
(match) => formatMap[match].toString(),
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 休眠
|
|
68
|
+
*
|
|
69
|
+
* @export
|
|
70
|
+
* @param {number} ms
|
|
71
|
+
* @return {*}
|
|
72
|
+
*/
|
|
73
|
+
export function sleep(ms: number) {
|
|
74
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
75
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 获取文件路径
|
|
3
|
+
*
|
|
4
|
+
* @export
|
|
5
|
+
* @return {*}
|
|
6
|
+
*/
|
|
7
|
+
export function getFilePath() {
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
if (plus) {
|
|
10
|
+
plus.io.resolveLocalFileSystemURL('_downloads', function (dirEntry) {
|
|
11
|
+
resolve(dirEntry.fullPath);
|
|
12
|
+
});
|
|
13
|
+
} else {
|
|
14
|
+
reject();
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 写入文件
|
|
21
|
+
*
|
|
22
|
+
* @param {string} filePath
|
|
23
|
+
* @param {string} content
|
|
24
|
+
*/
|
|
25
|
+
function writeContentToFile(filePath: string, content: string) {
|
|
26
|
+
plus.io.requestFileSystem(
|
|
27
|
+
plus.io.PUBLIC_DOCUMENTS,
|
|
28
|
+
function (fs) {
|
|
29
|
+
fs.root?.getFile(
|
|
30
|
+
filePath,
|
|
31
|
+
{ create: true },
|
|
32
|
+
function (fileEntry) {
|
|
33
|
+
fileEntry.createWriter(function (writer) {
|
|
34
|
+
writer.onwriteend = function () {
|
|
35
|
+
console.log('[DevTool] 写入文件成功' + filePath);
|
|
36
|
+
uni.showToast({
|
|
37
|
+
icon: 'none',
|
|
38
|
+
title: '写入文件成功' + filePath,
|
|
39
|
+
duration: 10 * 1000,
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
writer.onerror = function (e) {
|
|
43
|
+
console.log('[DevTool] 写入文件失败' + JSON.stringify(e));
|
|
44
|
+
uni.showToast({
|
|
45
|
+
icon: 'none',
|
|
46
|
+
title: '写入文件失败',
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
writer.write(content);
|
|
50
|
+
});
|
|
51
|
+
},
|
|
52
|
+
function (e) {
|
|
53
|
+
uni.showToast({
|
|
54
|
+
icon: 'none',
|
|
55
|
+
title: '获取文件失败',
|
|
56
|
+
});
|
|
57
|
+
console.log('[DevTool] 获取文件失败' + JSON.stringify(e));
|
|
58
|
+
},
|
|
59
|
+
);
|
|
60
|
+
},
|
|
61
|
+
function (e) {
|
|
62
|
+
uni.showToast({
|
|
63
|
+
icon: 'none',
|
|
64
|
+
title: '获取文件系统失败',
|
|
65
|
+
});
|
|
66
|
+
console.log('[DevTool] 获取文件系统失败' + JSON.stringify(e));
|
|
67
|
+
},
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export async function saveTxtFileApp(data: string, fileName: string) {
|
|
72
|
+
try {
|
|
73
|
+
const filePath = (await getFilePath()) + `${Date.now()}_${fileName}.txt`;
|
|
74
|
+
writeContentToFile(filePath, data);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.log('[DevTool] ' + JSON.stringify(error));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export async function saveTextFileH5(data: string, fileName: string) {
|
|
81
|
+
// 创建 Blob 对象
|
|
82
|
+
const blob = new Blob([data], { type: 'text/plain' });
|
|
83
|
+
|
|
84
|
+
// 生成临时 URL
|
|
85
|
+
const url = URL.createObjectURL(blob);
|
|
86
|
+
|
|
87
|
+
// 创建下载链接
|
|
88
|
+
const link = document.createElement('a');
|
|
89
|
+
link.href = url;
|
|
90
|
+
link.download = fileName;
|
|
91
|
+
|
|
92
|
+
// 触发点击下载
|
|
93
|
+
link.click();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export async function saveTextFileMicro(data: string, fileName: string) {
|
|
97
|
+
const fs = uni.getFileSystemManager();
|
|
98
|
+
const fileNameDate = `${fileName}_${Date.now()}.txt`;
|
|
99
|
+
const filePath = `${uni?.env?.USER_DATA_PATH ?? 'Download'}/${fileNameDate}`;
|
|
100
|
+
fs.writeFile({
|
|
101
|
+
data,
|
|
102
|
+
filePath,
|
|
103
|
+
success: (res) => {
|
|
104
|
+
console.log('[DevTool] 写入文件成功' + filePath);
|
|
105
|
+
console.log(
|
|
106
|
+
`[DevTool] 文件位置:内部存储/Android/data/comm.tencent.mm/MicroMsg/wxanewfiles/手动查找最新文件夹/${fileNameDate}`,
|
|
107
|
+
);
|
|
108
|
+
uni.showToast({
|
|
109
|
+
title: '写入文件成功' + filePath,
|
|
110
|
+
icon: 'none',
|
|
111
|
+
});
|
|
112
|
+
},
|
|
113
|
+
fail: (error) => {
|
|
114
|
+
console.log('[DevTool] 写入文件失败' + JSON.stringify(error));
|
|
115
|
+
uni.showToast({
|
|
116
|
+
title: '写入文件失败' + JSON.stringify(error),
|
|
117
|
+
icon: 'none',
|
|
118
|
+
});
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
type ThrottleOptions = {
|
|
2
|
+
leading?: boolean;
|
|
3
|
+
trailing?: boolean;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 创建一个节流函数,在指定时间间隔内只执行一次原函数
|
|
8
|
+
* @param func 需要节流的函数
|
|
9
|
+
* @param wait 等待时间(毫秒)
|
|
10
|
+
* @param options 配置选项
|
|
11
|
+
* @param options.leading 是否在开始时立即执行
|
|
12
|
+
* @param options.trailing 是否在延迟结束后执行最后一次调用
|
|
13
|
+
* @returns 节流后的函数
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export function throttle<T extends (...args: any[]) => any>(
|
|
17
|
+
func: T,
|
|
18
|
+
wait: number,
|
|
19
|
+
options: ThrottleOptions = {},
|
|
20
|
+
): (...args: Parameters<T>) => ReturnType<T> | undefined {
|
|
21
|
+
let timeout: NodeJS.Timeout | null = null;
|
|
22
|
+
let lastArgs: Parameters<T> | null = null;
|
|
23
|
+
let lastThis: any = null;
|
|
24
|
+
let result: ReturnType<T> | undefined;
|
|
25
|
+
let lastCallTime: number | null = null;
|
|
26
|
+
|
|
27
|
+
const { leading = true, trailing = true } = options;
|
|
28
|
+
|
|
29
|
+
const invokeFunc = (time: number) => {
|
|
30
|
+
const args = lastArgs;
|
|
31
|
+
const thisArg = lastThis;
|
|
32
|
+
lastArgs = lastThis = null;
|
|
33
|
+
lastCallTime = time;
|
|
34
|
+
result = func.apply(thisArg, args!);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const leadingEdge = (time: number) => {
|
|
39
|
+
lastCallTime = time;
|
|
40
|
+
timeout = null;
|
|
41
|
+
return leading ? invokeFunc(time) : undefined;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const trailingEdge = (time: number) => {
|
|
45
|
+
timeout = null;
|
|
46
|
+
if (lastArgs && trailing) {
|
|
47
|
+
return invokeFunc(time);
|
|
48
|
+
}
|
|
49
|
+
lastArgs = lastThis = null;
|
|
50
|
+
return result;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const remainingWait = (time: number) => {
|
|
54
|
+
if (lastCallTime === null) return wait;
|
|
55
|
+
const timeSinceLastCall = time - lastCallTime;
|
|
56
|
+
return wait - timeSinceLastCall;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const shouldInvoke = (time: number) => {
|
|
60
|
+
if (lastCallTime === null) return true;
|
|
61
|
+
const timeSinceLastCall = time - lastCallTime;
|
|
62
|
+
return timeSinceLastCall >= wait || timeSinceLastCall < 0;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const timerExpired = () => {
|
|
66
|
+
const time = Date.now();
|
|
67
|
+
if (shouldInvoke(time)) {
|
|
68
|
+
return trailingEdge(time);
|
|
69
|
+
}
|
|
70
|
+
timeout = setTimeout(timerExpired, remainingWait(time));
|
|
71
|
+
return undefined;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const throttled = function (this: any, ...args: Parameters<T>) {
|
|
75
|
+
const time = Date.now();
|
|
76
|
+
const isInvoking = shouldInvoke(time);
|
|
77
|
+
|
|
78
|
+
lastArgs = args;
|
|
79
|
+
lastThis = this;
|
|
80
|
+
|
|
81
|
+
if (isInvoking) {
|
|
82
|
+
if (timeout === null) {
|
|
83
|
+
return leadingEdge(time);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (timeout === null) {
|
|
88
|
+
timeout = setTimeout(timerExpired, wait);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return result;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
throttled.cancel = () => {
|
|
95
|
+
if (timeout !== null) {
|
|
96
|
+
clearTimeout(timeout);
|
|
97
|
+
}
|
|
98
|
+
lastCallTime = null;
|
|
99
|
+
timeout = lastArgs = lastThis = null;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
return throttled;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
type DebouncedFunction<T extends (...args: any[]) => any> = ((
|
|
106
|
+
...args: Parameters<T>
|
|
107
|
+
) => ReturnType<T> | undefined) & {
|
|
108
|
+
cancel: () => void;
|
|
109
|
+
flush: () => ReturnType<T> | undefined;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 创建一个防抖函数,该函数在最后一次调用后等待指定时间才执行。
|
|
114
|
+
* @param func 需要防抖的函数
|
|
115
|
+
* @param wait 等待时间(毫秒)
|
|
116
|
+
* @param immediate 是否在第一次调用时立即执行
|
|
117
|
+
* @returns 防抖后的函数
|
|
118
|
+
*/
|
|
119
|
+
export function debounce<T extends (...args: any[]) => any>(
|
|
120
|
+
func: T,
|
|
121
|
+
wait: number,
|
|
122
|
+
immediate: boolean = false,
|
|
123
|
+
): DebouncedFunction<T> {
|
|
124
|
+
let timeout: ReturnType<typeof setTimeout> | null = null;
|
|
125
|
+
let lastArgs: Parameters<T> | null = null;
|
|
126
|
+
let lastThis: ThisParameterType<T> | null = null;
|
|
127
|
+
let result: ReturnType<T> | undefined;
|
|
128
|
+
let lastCallTime: number | null = null;
|
|
129
|
+
|
|
130
|
+
const later = (): void => {
|
|
131
|
+
const last = lastCallTime !== null ? Date.now() - lastCallTime : 0;
|
|
132
|
+
|
|
133
|
+
if (last < wait && last >= 0) {
|
|
134
|
+
timeout = setTimeout(later, wait - last);
|
|
135
|
+
} else {
|
|
136
|
+
timeout = null;
|
|
137
|
+
if (!immediate) {
|
|
138
|
+
if (lastArgs !== null && lastThis !== null) {
|
|
139
|
+
result = func.apply(lastThis, lastArgs);
|
|
140
|
+
lastArgs = lastThis = null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const debounced = function (
|
|
147
|
+
this: ThisParameterType<T>,
|
|
148
|
+
...args: Parameters<T>
|
|
149
|
+
): ReturnType<T> | undefined {
|
|
150
|
+
lastArgs = args;
|
|
151
|
+
lastThis = this;
|
|
152
|
+
lastCallTime = Date.now();
|
|
153
|
+
|
|
154
|
+
const callNow = immediate && timeout === null;
|
|
155
|
+
|
|
156
|
+
if (!timeout) {
|
|
157
|
+
timeout = setTimeout(later, wait);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (callNow) {
|
|
161
|
+
result = func.apply(this, args);
|
|
162
|
+
lastArgs = lastThis = null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return result;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
debounced.cancel = (): void => {
|
|
169
|
+
if (timeout !== null) {
|
|
170
|
+
clearTimeout(timeout);
|
|
171
|
+
timeout = null;
|
|
172
|
+
lastArgs = lastThis = null;
|
|
173
|
+
lastCallTime = null;
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
debounced.flush = (): ReturnType<T> | undefined => {
|
|
178
|
+
if (timeout !== null) {
|
|
179
|
+
clearTimeout(timeout);
|
|
180
|
+
timeout = null;
|
|
181
|
+
if (!immediate) {
|
|
182
|
+
if (lastArgs !== null && lastThis !== null) {
|
|
183
|
+
result = func.apply(lastThis, lastArgs);
|
|
184
|
+
lastArgs = lastThis = null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return result;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
return debounced;
|
|
192
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export { isNil, isBoolean, isNumber, isObject, isArray } from './language';
|
|
2
|
+
export {
|
|
3
|
+
setValueByPath,
|
|
4
|
+
getValueByPath,
|
|
5
|
+
calculateObjectSize,
|
|
6
|
+
formatStorageSize,
|
|
7
|
+
serializeCircular,
|
|
8
|
+
} from './object';
|
|
9
|
+
|
|
10
|
+
export { throttle, debounce } from './function';
|
|
11
|
+
|
|
12
|
+
export {
|
|
13
|
+
getFilePath,
|
|
14
|
+
saveTextFileH5,
|
|
15
|
+
saveTextFileMicro,
|
|
16
|
+
saveTxtFileApp,
|
|
17
|
+
} from './file';
|
|
18
|
+
|
|
19
|
+
export { getCurrentPagePath } from './page';
|
|
20
|
+
|
|
21
|
+
export { getCurrentDate, formatDate, sleep } from './date';
|
|
22
|
+
|
|
23
|
+
export { hightLight } from './string';
|
|
24
|
+
|
|
25
|
+
export { getWifiIp, getDeviceMac, getLanIp, getMicroAppIp } from './ip';
|