ph-utils 0.6.2 → 0.8.0
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/lib/dom.d.ts +9 -0
- package/lib/dom.js +43 -18
- package/lib/file.js +20 -19
- package/lib/logger.d.ts +62 -0
- package/lib/logger.js +123 -0
- package/package.json +1 -1
package/lib/dom.d.ts
CHANGED
@@ -90,3 +90,12 @@ export declare function queryHideNodeSize(hideNode: string | HTMLElement, parent
|
|
90
90
|
width: number;
|
91
91
|
height: number;
|
92
92
|
};
|
93
|
+
/**
|
94
|
+
* 判断元素是否在父元素的可视区域内。
|
95
|
+
*
|
96
|
+
* @param el 要检查的元素
|
97
|
+
* @param parent 元素的父元素,默认为document.body
|
98
|
+
* @param direction 检查的方向,默认为"horizontal"
|
99
|
+
* @returns 如果元素在父元素的可视区域内,则返回true;否则返回false。
|
100
|
+
*/
|
101
|
+
export declare function isVisible(el: HTMLElement, parent?: HTMLElement, direction?: string): boolean;
|
package/lib/dom.js
CHANGED
@@ -3,13 +3,13 @@
|
|
3
3
|
* 现今不推荐在使用这种方式,现在开发前端的时候,推荐使用一些成熟的框架例如:React、Preact、Vue、Angular、Svelte、Ember、Knockout等
|
4
4
|
* 在使用这些框架的时候额外的一些不可避免的 dom 操作时才使用这个工具;如果确实需要使用原生开发推荐使用 jquery 或者想要更精简的话可以使用 https://github.com/finom/bala 封装
|
5
5
|
*/
|
6
|
-
const vendorPrefix = [
|
6
|
+
const vendorPrefix = ["", "-webkit", "-moz-"];
|
7
7
|
/**
|
8
8
|
* 根据选择器获取节点
|
9
9
|
* @param {string} selector 选择器
|
10
10
|
*/
|
11
11
|
export function elem(selector, dom) {
|
12
|
-
if (typeof selector ===
|
12
|
+
if (typeof selector === "string") {
|
13
13
|
return (dom || document).querySelectorAll(selector);
|
14
14
|
}
|
15
15
|
else {
|
@@ -48,7 +48,7 @@ export function hasClass(elem, clazz) {
|
|
48
48
|
*/
|
49
49
|
export function transition(element, value) {
|
50
50
|
vendorPrefix.forEach((prefix) => {
|
51
|
-
let t = prefix ===
|
51
|
+
let t = prefix === "" ? "transition" : prefix + "Transition";
|
52
52
|
element.style[t] = value;
|
53
53
|
});
|
54
54
|
}
|
@@ -59,7 +59,7 @@ export function transition(element, value) {
|
|
59
59
|
*/
|
60
60
|
export function transform(element, value) {
|
61
61
|
vendorPrefix.forEach((prefix) => {
|
62
|
-
let t = prefix ===
|
62
|
+
let t = prefix === "" ? "transform" : prefix + "Transform";
|
63
63
|
element.style[t] = value;
|
64
64
|
});
|
65
65
|
}
|
@@ -72,24 +72,24 @@ export function transform(element, value) {
|
|
72
72
|
*/
|
73
73
|
export function on(element, listener, fn, once = false) {
|
74
74
|
let eventExtra = { eventStop: false };
|
75
|
-
if (typeof once ===
|
75
|
+
if (typeof once === "boolean") {
|
76
76
|
eventExtra.once = once;
|
77
77
|
}
|
78
78
|
else {
|
79
79
|
eventExtra = once;
|
80
80
|
}
|
81
81
|
if (eventExtra.eventFlag != null) {
|
82
|
-
element.setAttribute(eventExtra.eventFlag,
|
82
|
+
element.setAttribute(eventExtra.eventFlag, "__stop__");
|
83
83
|
element.addEventListener(listener, (e) => {
|
84
84
|
let target = e.target;
|
85
|
-
let flag =
|
85
|
+
let flag = "";
|
86
86
|
do {
|
87
|
-
flag = target.getAttribute(eventExtra.eventFlag) ||
|
88
|
-
if (flag ===
|
87
|
+
flag = target.getAttribute(eventExtra.eventFlag) || "";
|
88
|
+
if (flag === "") {
|
89
89
|
target = target.parentNode;
|
90
90
|
}
|
91
|
-
} while (flag ===
|
92
|
-
if (flag !==
|
91
|
+
} while (flag === "");
|
92
|
+
if (flag !== "__stop__" || eventExtra.eventStop) {
|
93
93
|
fn(e, target, flag);
|
94
94
|
}
|
95
95
|
}, eventExtra);
|
@@ -150,10 +150,10 @@ export function iterate(elems, fn) {
|
|
150
150
|
*/
|
151
151
|
export function attr(elem, key, value) {
|
152
152
|
if (value != null) {
|
153
|
-
elem.setAttribute(
|
153
|
+
elem.setAttribute("data-" + key, value);
|
154
154
|
}
|
155
155
|
else {
|
156
|
-
return elem.getAttribute(
|
156
|
+
return elem.getAttribute("data-" + key);
|
157
157
|
}
|
158
158
|
}
|
159
159
|
/**
|
@@ -172,11 +172,11 @@ export function parent(el) {
|
|
172
172
|
*/
|
173
173
|
export function queryHideNodeSize(hideNode, parent = document.body) {
|
174
174
|
// 计算折叠菜单的高度
|
175
|
-
let $tmp = document.createElement(
|
176
|
-
$tmp.style.cssText =
|
177
|
-
let $tmpInner = document.createElement(
|
178
|
-
$tmpInner.style.cssText =
|
179
|
-
if (typeof hideNode ===
|
175
|
+
let $tmp = document.createElement("div");
|
176
|
+
$tmp.style.cssText = "position:fixed;left:-1000px;top:-1000px;opacity:0;";
|
177
|
+
let $tmpInner = document.createElement("div");
|
178
|
+
$tmpInner.style.cssText = "position:relative;";
|
179
|
+
if (typeof hideNode === "string") {
|
180
180
|
$tmpInner.innerHTML = hideNode;
|
181
181
|
}
|
182
182
|
else {
|
@@ -188,3 +188,28 @@ export function queryHideNodeSize(hideNode, parent = document.body) {
|
|
188
188
|
parent.removeChild($tmp);
|
189
189
|
return { width: rect.width, height: rect.height };
|
190
190
|
}
|
191
|
+
/**
|
192
|
+
* 判断元素是否在父元素的可视区域内。
|
193
|
+
*
|
194
|
+
* @param el 要检查的元素
|
195
|
+
* @param parent 元素的父元素,默认为document.body
|
196
|
+
* @param direction 检查的方向,默认为"horizontal"
|
197
|
+
* @returns 如果元素在父元素的可视区域内,则返回true;否则返回false。
|
198
|
+
*/
|
199
|
+
export function isVisible(el, parent = document.body, direction = "horizontal") {
|
200
|
+
// 获取父元素的边界信息
|
201
|
+
const containerRect = parent.getBoundingClientRect();
|
202
|
+
// 获取元素的边界信息
|
203
|
+
const elementRect = el.getBoundingClientRect();
|
204
|
+
// 根据检查方向,确定元素的起始和结束位置
|
205
|
+
// 元素的上、下边界
|
206
|
+
let elStart = direction === "horizontal" ? elementRect.left : elementRect.top;
|
207
|
+
let elEnd = direction === "horizontal" ? elementRect.right : elementRect.bottom;
|
208
|
+
// 根据检查方向,确定父元素的起始和结束位置
|
209
|
+
// 容器的可视区域的上、下边界
|
210
|
+
let containerStart = direction === "horizontal" ? containerRect.left : containerRect.top;
|
211
|
+
let containerEnd = direction === "horizontal" ? containerRect.right : containerRect.bottom;
|
212
|
+
// 判断元素是否在父元素的可视区域内
|
213
|
+
// 判断元素是否完全在容器的可视区域内
|
214
|
+
return elStart >= containerStart && elEnd <= containerEnd;
|
215
|
+
}
|
package/lib/file.js
CHANGED
@@ -12,19 +12,20 @@ import fs from "node:fs/promises";
|
|
12
12
|
* @returns 文件内容
|
13
13
|
*/
|
14
14
|
export async function read(filepath, defaultValue) {
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
let content;
|
16
|
+
try {
|
17
|
+
content = await fs.readFile(filepath, "utf8");
|
18
|
+
if (defaultValue != null && typeof defaultValue === "object") {
|
19
|
+
return JSON.parse(content);
|
20
|
+
}
|
21
|
+
return content;
|
20
22
|
}
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
23
|
+
catch (error) {
|
24
|
+
if (defaultValue === undefined) {
|
25
|
+
throw error;
|
26
|
+
}
|
27
|
+
return defaultValue;
|
25
28
|
}
|
26
|
-
return defaultValue;
|
27
|
-
}
|
28
29
|
}
|
29
30
|
/**
|
30
31
|
* 写入 JSON 格式的数据到文件
|
@@ -35,12 +36,12 @@ export async function read(filepath, defaultValue) {
|
|
35
36
|
* @property opts.format 是否在写入 json 数据时,将 JSON 数据格式化2个空格写入, 默认为 true
|
36
37
|
*/
|
37
38
|
export async function write(file, data, opts) {
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
39
|
+
let writeData = data.toString();
|
40
|
+
opts = { json: true, format: true, ...opts };
|
41
|
+
if (opts.json === true && typeof data === "object") {
|
42
|
+
writeData = JSON.stringify(data, null, opts.format === true ? 2 : 0);
|
43
|
+
}
|
44
|
+
return await fs.writeFile(path.resolve(file), writeData);
|
44
45
|
}
|
45
46
|
/**
|
46
47
|
* 根据文件的 stat 获取文件的 etag
|
@@ -48,6 +49,6 @@ export async function write(file, data, opts) {
|
|
48
49
|
* @returns file stat etag
|
49
50
|
*/
|
50
51
|
export async function statTag(filePath) {
|
51
|
-
|
52
|
-
|
52
|
+
let stat = await fs.stat(filePath);
|
53
|
+
return `${stat.size.toString(16)}-${stat.mtimeMs.toString(16)}`;
|
53
54
|
}
|
package/lib/logger.d.ts
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
type LoggerLevel = "debug" | "info" | "warn" | "error" | "fatal";
|
2
|
+
/** 日志消息类型 */
|
3
|
+
type MessageIntf = number | string | boolean | object | any[] | Error;
|
4
|
+
/** 日志消息选项 */
|
5
|
+
type MessageOption = {
|
6
|
+
/** 日志名称 */
|
7
|
+
name?: string;
|
8
|
+
/** 日志级别 */
|
9
|
+
level?: LoggerLevel;
|
10
|
+
/** 日志消息 */
|
11
|
+
message: MessageIntf;
|
12
|
+
/** 当前消息是否美化输出 */
|
13
|
+
pretty?: boolean;
|
14
|
+
/** 如果消息是 JSON 格式, 转换为字符串时, 是否格式化 JSON */
|
15
|
+
jsonSpace?: number;
|
16
|
+
};
|
17
|
+
type LoggerOption = {
|
18
|
+
/** 记录的日志名称, 通常用于表明哪个页面 */
|
19
|
+
name?: string;
|
20
|
+
/** 记录日志级别, 通常上线时 error 或者禁用日志, 默认: debug */
|
21
|
+
level?: LoggerLevel;
|
22
|
+
/** 是否需要美化输出, 默认: true */
|
23
|
+
pretty?: boolean;
|
24
|
+
};
|
25
|
+
/**
|
26
|
+
* 日志记录器
|
27
|
+
*/
|
28
|
+
export declare class Logger {
|
29
|
+
/** 日志级别 */
|
30
|
+
levels: string[];
|
31
|
+
colors: {
|
32
|
+
debug: string;
|
33
|
+
info: string;
|
34
|
+
warn: string;
|
35
|
+
error: string;
|
36
|
+
};
|
37
|
+
option: LoggerOption & {
|
38
|
+
levelNum: number;
|
39
|
+
};
|
40
|
+
/** 构造日志记录器 */
|
41
|
+
constructor(option?: LoggerOption);
|
42
|
+
setOption(option: LoggerOption): void;
|
43
|
+
log(message: MessageIntf | MessageOption): void;
|
44
|
+
info(message: MessageIntf | MessageOption): void;
|
45
|
+
debug(message: MessageIntf | MessageOption): void;
|
46
|
+
warn(message: MessageIntf | MessageOption): void;
|
47
|
+
error(message: MessageIntf | MessageOption): void;
|
48
|
+
fatal(message: MessageIntf | MessageOption): void;
|
49
|
+
getLevel(): string;
|
50
|
+
getName(): string | undefined;
|
51
|
+
getOption(): LoggerOption & {
|
52
|
+
levelNum: number;
|
53
|
+
};
|
54
|
+
private generateLog;
|
55
|
+
/** 格式化显示 */
|
56
|
+
private formatShow;
|
57
|
+
}
|
58
|
+
/** 默认日志记录器 */
|
59
|
+
export declare const logger: Logger;
|
60
|
+
/** 获取新的日志记录器, 属性采用之前的 */
|
61
|
+
export declare const getLogger: (option?: LoggerOption) => Logger;
|
62
|
+
export {};
|
package/lib/logger.js
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
import { format } from "./date";
|
2
|
+
/**
|
3
|
+
* 日志记录器
|
4
|
+
*/
|
5
|
+
export class Logger {
|
6
|
+
/** 日志级别 */
|
7
|
+
levels = ["debug", "info", "warn", "error", "fatal"];
|
8
|
+
colors = {
|
9
|
+
debug: "#909399",
|
10
|
+
info: "#1677ff",
|
11
|
+
warn: "#fadb14",
|
12
|
+
error: "#eb2f96",
|
13
|
+
};
|
14
|
+
option;
|
15
|
+
/** 构造日志记录器 */
|
16
|
+
constructor(option) {
|
17
|
+
this.setOption(option || {});
|
18
|
+
}
|
19
|
+
setOption(option) {
|
20
|
+
let opts = { level: "debug", levelNum: 0, pretty: true, ...option };
|
21
|
+
opts.levelNum = this.levels.indexOf(opts.level);
|
22
|
+
this.option = opts;
|
23
|
+
}
|
24
|
+
log(message) {
|
25
|
+
let msgInfo = {
|
26
|
+
name: this.option.name,
|
27
|
+
level: "info",
|
28
|
+
time: format(null, "yyyy-mm-dd HH:MM:ss.S"),
|
29
|
+
pretty: this.option.pretty,
|
30
|
+
jsonSpace: 0,
|
31
|
+
};
|
32
|
+
let msgContent = message;
|
33
|
+
if (typeof message === "object") {
|
34
|
+
if (message instanceof Error) {
|
35
|
+
msgInfo.level = "error";
|
36
|
+
msgContent = msgContent.stack;
|
37
|
+
}
|
38
|
+
else if (message.message != null) {
|
39
|
+
msgContent = message.message;
|
40
|
+
msgInfo = { ...msgInfo, ...message };
|
41
|
+
}
|
42
|
+
}
|
43
|
+
if (typeof msgContent === "object") {
|
44
|
+
try {
|
45
|
+
msgInfo.message = JSON.stringify(msgContent, null, msgInfo.jsonSpace);
|
46
|
+
}
|
47
|
+
catch (error) {
|
48
|
+
msgInfo.message = msgContent.toString();
|
49
|
+
}
|
50
|
+
}
|
51
|
+
else {
|
52
|
+
msgInfo.message = msgContent;
|
53
|
+
}
|
54
|
+
if (msgInfo.pretty == null) {
|
55
|
+
msgInfo.pretty = this.option.pretty;
|
56
|
+
}
|
57
|
+
let levelIndex = this.levels.indexOf(msgInfo.level);
|
58
|
+
if (levelIndex >= this.option.levelNum) {
|
59
|
+
this.formatShow(msgInfo);
|
60
|
+
}
|
61
|
+
}
|
62
|
+
info(message) {
|
63
|
+
this.log(this.generateLog(message, "info"));
|
64
|
+
}
|
65
|
+
debug(message) {
|
66
|
+
this.log(this.generateLog(message, "debug"));
|
67
|
+
}
|
68
|
+
warn(message) {
|
69
|
+
this.log(this.generateLog(message, "warn"));
|
70
|
+
}
|
71
|
+
error(message) {
|
72
|
+
this.log(this.generateLog(message, "error"));
|
73
|
+
}
|
74
|
+
fatal(message) {
|
75
|
+
this.log(this.generateLog(message, "fatal"));
|
76
|
+
}
|
77
|
+
getLevel() {
|
78
|
+
return this.levels[this.option.levelNum];
|
79
|
+
}
|
80
|
+
getName() {
|
81
|
+
return this.option.name;
|
82
|
+
}
|
83
|
+
getOption() {
|
84
|
+
return this.option;
|
85
|
+
}
|
86
|
+
generateLog(message, level = "info") {
|
87
|
+
let msgInfo = {
|
88
|
+
message: message,
|
89
|
+
};
|
90
|
+
if (typeof message === "object") {
|
91
|
+
if (message.message != null) {
|
92
|
+
msgInfo = message;
|
93
|
+
}
|
94
|
+
}
|
95
|
+
msgInfo["level"] = level;
|
96
|
+
return msgInfo;
|
97
|
+
}
|
98
|
+
/** 格式化显示 */
|
99
|
+
formatShow(msg) {
|
100
|
+
if (msg.level === "fatal") {
|
101
|
+
msg.level = "error";
|
102
|
+
}
|
103
|
+
const res = [`[${msg.time}]`];
|
104
|
+
if (msg.name != null) {
|
105
|
+
res.push(`[${msg.name}]`);
|
106
|
+
}
|
107
|
+
res.push(`- ${msg.message}`);
|
108
|
+
if (!msg.pretty) {
|
109
|
+
res.splice(1, 0, `${msg.level.toUpperCase()}`);
|
110
|
+
console[msg.level](res.join(" "));
|
111
|
+
}
|
112
|
+
else {
|
113
|
+
const color = this.colors[msg.level];
|
114
|
+
console.log(`%c ${`${msg.level.toUpperCase()}`} %c ${res.join(" ")} %c`, `background:${color};border:1px solid ${color}; padding: 1px; border-radius: 2px 0 0 2px; color: #fff;`, `border:1px solid ${color}; padding: 1px; border-radius: 0 2px 2px 0; color: ${color};`, "background:transparent");
|
115
|
+
}
|
116
|
+
}
|
117
|
+
}
|
118
|
+
/** 默认日志记录器 */
|
119
|
+
export const logger = new Logger({ name: "APP" });
|
120
|
+
/** 获取新的日志记录器, 属性采用之前的 */
|
121
|
+
export const getLogger = (option) => {
|
122
|
+
return new Logger({ ...logger.getOption(), ...option });
|
123
|
+
};
|