a2bei4-utils 1.0.6 → 1.0.8
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/dist/a2bei4.utils.cjs.js +168 -1
- package/dist/a2bei4.utils.cjs.js.map +1 -1
- package/dist/a2bei4.utils.cjs.min.js +1 -1
- package/dist/a2bei4.utils.cjs.min.js.map +1 -1
- package/dist/a2bei4.utils.esm.js +167 -2
- package/dist/a2bei4.utils.esm.js.map +1 -1
- package/dist/a2bei4.utils.esm.min.js +1 -1
- package/dist/a2bei4.utils.esm.min.js.map +1 -1
- package/dist/a2bei4.utils.umd.js +168 -1
- package/dist/a2bei4.utils.umd.js.map +1 -1
- package/dist/a2bei4.utils.umd.min.js +1 -1
- package/dist/a2bei4.utils.umd.min.js.map +1 -1
- package/dist/browser.cjs +106 -1
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.js +106 -2
- package/dist/browser.js.map +1 -1
- package/dist/download.cjs +3 -0
- package/dist/download.cjs.map +1 -1
- package/dist/download.js +3 -0
- package/dist/download.js.map +1 -1
- package/dist/tree.cjs +59 -0
- package/dist/tree.cjs.map +1 -1
- package/dist/tree.js +59 -1
- package/dist/tree.js.map +1 -1
- package/package.json +1 -1
- package/types/browser.d.ts +10 -1
- package/types/index.d.ts +32 -1
- package/types/tree.d.ts +23 -1
package/dist/browser.cjs
CHANGED
|
@@ -52,8 +52,113 @@ function getAllSearchParams() {
|
|
|
52
52
|
function getSearchParam(key) {
|
|
53
53
|
const params = getAllSearchParams();
|
|
54
54
|
return params[key];
|
|
55
|
-
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 全屏操作辅助工具对象
|
|
59
|
+
* @namespace fullscreenHelper
|
|
60
|
+
*/
|
|
61
|
+
const fullscreenHelper = {
|
|
62
|
+
/**
|
|
63
|
+
* 请求进入全屏模式
|
|
64
|
+
* @param {Element} element - 要全屏显示的元素
|
|
65
|
+
* @returns {Promise<void> | undefined} 全屏请求 Promise(如支持)
|
|
66
|
+
*/
|
|
67
|
+
requestFullscreen: (element) => {
|
|
68
|
+
if (!element) {
|
|
69
|
+
console.warn("未提供有效的 DOM 元素");
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (element.requestFullscreen) {
|
|
73
|
+
return element.requestFullscreen();
|
|
74
|
+
} else if (element.mozRequestFullScreen) {
|
|
75
|
+
return element.mozRequestFullScreen();
|
|
76
|
+
} else if (element.webkitRequestFullscreen) {
|
|
77
|
+
return element.webkitRequestFullscreen();
|
|
78
|
+
} else if (element.msRequestFullscreen) {
|
|
79
|
+
return element.msRequestFullscreen();
|
|
80
|
+
} else {
|
|
81
|
+
console.warn("当前浏览器不支持全屏 API");
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 退出全屏模式
|
|
87
|
+
* @returns {Promise<void> | undefined} 退出全屏请求 Promise(如支持)
|
|
88
|
+
*/
|
|
89
|
+
exitFullscreen: () => {
|
|
90
|
+
if (document.exitFullscreen) {
|
|
91
|
+
return document.exitFullscreen();
|
|
92
|
+
} else if (document.mozCancelFullScreen) {
|
|
93
|
+
return document.mozCancelFullScreen();
|
|
94
|
+
} else if (document.webkitExitFullscreen) {
|
|
95
|
+
return document.webkitExitFullscreen();
|
|
96
|
+
} else if (document.msExitFullscreen) {
|
|
97
|
+
return document.msExitFullscreen();
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* 获取当前全屏元素
|
|
103
|
+
* @returns {Element | null} 当前处于全屏模式的元素,无则返回 null
|
|
104
|
+
*/
|
|
105
|
+
getFullscreenElement: () => {
|
|
106
|
+
return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement || null;
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 检测当前是否处于全屏模式
|
|
111
|
+
* @returns {boolean} 是否全屏中
|
|
112
|
+
*/
|
|
113
|
+
isFullscreen: () => {
|
|
114
|
+
return !!(document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement);
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* 检测浏览器是否支持全屏 API
|
|
119
|
+
* @returns {boolean} 是否支持全屏
|
|
120
|
+
*/
|
|
121
|
+
isFullscreenEnabled: () => {
|
|
122
|
+
return !!(document.fullscreenEnabled || document.mozFullScreenEnabled || document.webkitFullscreenEnabled || document.msFullscreenEnabled);
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* 切换指定元素的全屏状态
|
|
127
|
+
* @param {Element} element - 要切换全屏的元素
|
|
128
|
+
* @returns {Promise<void> | undefined} 全屏操作 Promise
|
|
129
|
+
*/
|
|
130
|
+
toggleFullscreen: (element) => {
|
|
131
|
+
if (fullscreenHelper.isFullscreen()) {
|
|
132
|
+
return fullscreenHelper.exitFullscreen();
|
|
133
|
+
} else {
|
|
134
|
+
return fullscreenHelper.requestFullscreen(element);
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* 监听全屏变化事件
|
|
140
|
+
* @param {Function} callback - 全屏状态变化时的回调函数,参数为 isFullscreen: boolean
|
|
141
|
+
* @returns {Function} 取消监听的函数
|
|
142
|
+
*/
|
|
143
|
+
onFullscreenChange: (callback) => {
|
|
144
|
+
const handler = () => {
|
|
145
|
+
callback(fullscreenHelper.isFullscreen());
|
|
146
|
+
};
|
|
147
|
+
document.addEventListener("fullscreenchange", handler);
|
|
148
|
+
document.addEventListener("webkitfullscreenchange", handler);
|
|
149
|
+
document.addEventListener("mozfullscreenchange", handler);
|
|
150
|
+
document.addEventListener("msfullscreenchange", handler);
|
|
151
|
+
|
|
152
|
+
return () => {
|
|
153
|
+
document.removeEventListener("fullscreenchange", handler);
|
|
154
|
+
document.removeEventListener("webkitfullscreenchange", handler);
|
|
155
|
+
document.removeEventListener("mozfullscreenchange", handler);
|
|
156
|
+
document.removeEventListener("msfullscreenchange", handler);
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
};
|
|
56
160
|
|
|
161
|
+
exports.fullscreenHelper = fullscreenHelper;
|
|
57
162
|
exports.getAllSearchParams = getAllSearchParams;
|
|
58
163
|
exports.getSearchParam = getSearchParam;
|
|
59
164
|
exports.getViewportSize = getViewportSize;
|
package/dist/browser.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.cjs","sources":["../src/source/browser.js"],"sourcesContent":["/**\r\n * 视口尺寸对象。\r\n * @typedef {Object} ViewportDimensions\r\n * @property {number} w 视口宽度,单位像素。\r\n * @property {number} h 视口高度,单位像素。\r\n */\r\n\r\n/**\r\n * 获取当前视口(viewport)的宽高。\r\n *\r\n * 兼容策略:\r\n * 1. 优先使用 `window.innerWidth/innerHeight`(现代浏览器)。\r\n * 2. 降级到 `document.documentElement.clientWidth/clientHeight`(IE9+ 及怪异模式)。\r\n * 3. 最后降级到 `document.body.clientWidth/clientHeight`(IE6-8 怪异模式)。\r\n *\r\n * @returns {ViewportDimensions} 包含 `w`(宽度)和 `h`(高度)的对象,单位为像素。\r\n *\r\n * @example\r\n * const { w, h } = getViewportSize();\r\n * console.log(`视口尺寸:${w} × ${h}`);\r\n */\r\nexport function getViewportSize() {\r\n const d = document,\r\n root = d.documentElement,\r\n body = d.body;\r\n\r\n return {\r\n w: window.innerWidth || root.clientWidth || body.clientWidth,\r\n h: window.innerHeight || root.clientHeight || body.clientHeight\r\n };\r\n}\r\n\r\n/**\r\n * 将当前页面 URL 的 query 部分解析成键值对对象。\r\n *\r\n * @returns {Record<string, string>} 所有查询参数组成的平凡对象\r\n * (同名 key 仅保留最后一项)\r\n */\r\nexport function getAllSearchParams() {\r\n const urlSearchParams = new URLSearchParams(location.search);\r\n return Object.fromEntries(urlSearchParams.entries());\r\n}\r\n\r\n/**\r\n * 根据 key 获取当前页面 URL 中的单个查询参数。\r\n *\r\n * @param {string} key - 要提取的参数名\r\n * @returns {string | undefined} 对应参数值;不存在时返回 `undefined`\r\n */\r\nexport function getSearchParam(key) {\r\n const params = getAllSearchParams();\r\n return params[key];\r\n}\r\n"],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,eAAe,GAAG;AAClC,IAAI,MAAM,CAAC,GAAG,QAAQ;AACtB,QAAQ,IAAI,GAAG,CAAC,CAAC,eAAe;AAChC,QAAQ,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC;AACtB;AACA,IAAI,OAAO;AACX,QAAQ,CAAC,EAAE,MAAM,CAAC,UAAU,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,WAAW;AACpE,QAAQ,CAAC,EAAE,MAAM,CAAC,WAAW,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY;AACvE,KAAK,CAAC;AACN,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,kBAAkB,GAAG;AACrC,IAAI,MAAM,eAAe,GAAG,IAAI,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AACjE,IAAI,OAAO,MAAM,CAAC,WAAW,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC,CAAC;AACzD,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,cAAc,CAAC,GAAG,EAAE;AACpC,IAAI,MAAM,MAAM,GAAG,kBAAkB,EAAE,CAAC;AACxC,IAAI,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;AACvB
|
|
1
|
+
{"version":3,"file":"browser.cjs","sources":["../src/source/browser.js"],"sourcesContent":["/**\r\n * 视口尺寸对象。\r\n * @typedef {Object} ViewportDimensions\r\n * @property {number} w 视口宽度,单位像素。\r\n * @property {number} h 视口高度,单位像素。\r\n */\r\n\r\n/**\r\n * 获取当前视口(viewport)的宽高。\r\n *\r\n * 兼容策略:\r\n * 1. 优先使用 `window.innerWidth/innerHeight`(现代浏览器)。\r\n * 2. 降级到 `document.documentElement.clientWidth/clientHeight`(IE9+ 及怪异模式)。\r\n * 3. 最后降级到 `document.body.clientWidth/clientHeight`(IE6-8 怪异模式)。\r\n *\r\n * @returns {ViewportDimensions} 包含 `w`(宽度)和 `h`(高度)的对象,单位为像素。\r\n *\r\n * @example\r\n * const { w, h } = getViewportSize();\r\n * console.log(`视口尺寸:${w} × ${h}`);\r\n */\r\nexport function getViewportSize() {\r\n const d = document,\r\n root = d.documentElement,\r\n body = d.body;\r\n\r\n return {\r\n w: window.innerWidth || root.clientWidth || body.clientWidth,\r\n h: window.innerHeight || root.clientHeight || body.clientHeight\r\n };\r\n}\r\n\r\n/**\r\n * 将当前页面 URL 的 query 部分解析成键值对对象。\r\n *\r\n * @returns {Record<string, string>} 所有查询参数组成的平凡对象\r\n * (同名 key 仅保留最后一项)\r\n */\r\nexport function getAllSearchParams() {\r\n const urlSearchParams = new URLSearchParams(location.search);\r\n return Object.fromEntries(urlSearchParams.entries());\r\n}\r\n\r\n/**\r\n * 根据 key 获取当前页面 URL 中的单个查询参数。\r\n *\r\n * @param {string} key - 要提取的参数名\r\n * @returns {string | undefined} 对应参数值;不存在时返回 `undefined`\r\n */\r\nexport function getSearchParam(key) {\r\n const params = getAllSearchParams();\r\n return params[key];\r\n}\r\n\r\n/**\r\n * 全屏操作辅助工具对象\r\n * @namespace fullscreenHelper\r\n */\r\nexport const fullscreenHelper = {\r\n /**\r\n * 请求进入全屏模式\r\n * @param {Element} element - 要全屏显示的元素\r\n * @returns {Promise<void> | undefined} 全屏请求 Promise(如支持)\r\n */\r\n requestFullscreen: (element) => {\r\n if (!element) {\r\n console.warn(\"未提供有效的 DOM 元素\");\r\n return;\r\n }\r\n if (element.requestFullscreen) {\r\n return element.requestFullscreen();\r\n } else if (element.mozRequestFullScreen) {\r\n return element.mozRequestFullScreen();\r\n } else if (element.webkitRequestFullscreen) {\r\n return element.webkitRequestFullscreen();\r\n } else if (element.msRequestFullscreen) {\r\n return element.msRequestFullscreen();\r\n } else {\r\n console.warn(\"当前浏览器不支持全屏 API\");\r\n }\r\n },\r\n\r\n /**\r\n * 退出全屏模式\r\n * @returns {Promise<void> | undefined} 退出全屏请求 Promise(如支持)\r\n */\r\n exitFullscreen: () => {\r\n if (document.exitFullscreen) {\r\n return document.exitFullscreen();\r\n } else if (document.mozCancelFullScreen) {\r\n return document.mozCancelFullScreen();\r\n } else if (document.webkitExitFullscreen) {\r\n return document.webkitExitFullscreen();\r\n } else if (document.msExitFullscreen) {\r\n return document.msExitFullscreen();\r\n }\r\n },\r\n\r\n /**\r\n * 获取当前全屏元素\r\n * @returns {Element | null} 当前处于全屏模式的元素,无则返回 null\r\n */\r\n getFullscreenElement: () => {\r\n return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement || null;\r\n },\r\n\r\n /**\r\n * 检测当前是否处于全屏模式\r\n * @returns {boolean} 是否全屏中\r\n */\r\n isFullscreen: () => {\r\n return !!(document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement);\r\n },\r\n\r\n /**\r\n * 检测浏览器是否支持全屏 API\r\n * @returns {boolean} 是否支持全屏\r\n */\r\n isFullscreenEnabled: () => {\r\n return !!(document.fullscreenEnabled || document.mozFullScreenEnabled || document.webkitFullscreenEnabled || document.msFullscreenEnabled);\r\n },\r\n\r\n /**\r\n * 切换指定元素的全屏状态\r\n * @param {Element} element - 要切换全屏的元素\r\n * @returns {Promise<void> | undefined} 全屏操作 Promise\r\n */\r\n toggleFullscreen: (element) => {\r\n if (fullscreenHelper.isFullscreen()) {\r\n return fullscreenHelper.exitFullscreen();\r\n } else {\r\n return fullscreenHelper.requestFullscreen(element);\r\n }\r\n },\r\n\r\n /**\r\n * 监听全屏变化事件\r\n * @param {Function} callback - 全屏状态变化时的回调函数,参数为 isFullscreen: boolean\r\n * @returns {Function} 取消监听的函数\r\n */\r\n onFullscreenChange: (callback) => {\r\n const handler = () => {\r\n callback(fullscreenHelper.isFullscreen());\r\n };\r\n document.addEventListener(\"fullscreenchange\", handler);\r\n document.addEventListener(\"webkitfullscreenchange\", handler);\r\n document.addEventListener(\"mozfullscreenchange\", handler);\r\n document.addEventListener(\"msfullscreenchange\", handler);\r\n\r\n return () => {\r\n document.removeEventListener(\"fullscreenchange\", handler);\r\n document.removeEventListener(\"webkitfullscreenchange\", handler);\r\n document.removeEventListener(\"mozfullscreenchange\", handler);\r\n document.removeEventListener(\"msfullscreenchange\", handler);\r\n };\r\n }\r\n};\r\n"],"names":[],"mappings":"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"}
|
package/dist/browser.js
CHANGED
|
@@ -50,7 +50,111 @@ function getAllSearchParams() {
|
|
|
50
50
|
function getSearchParam(key) {
|
|
51
51
|
const params = getAllSearchParams();
|
|
52
52
|
return params[key];
|
|
53
|
-
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 全屏操作辅助工具对象
|
|
57
|
+
* @namespace fullscreenHelper
|
|
58
|
+
*/
|
|
59
|
+
const fullscreenHelper = {
|
|
60
|
+
/**
|
|
61
|
+
* 请求进入全屏模式
|
|
62
|
+
* @param {Element} element - 要全屏显示的元素
|
|
63
|
+
* @returns {Promise<void> | undefined} 全屏请求 Promise(如支持)
|
|
64
|
+
*/
|
|
65
|
+
requestFullscreen: (element) => {
|
|
66
|
+
if (!element) {
|
|
67
|
+
console.warn("未提供有效的 DOM 元素");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (element.requestFullscreen) {
|
|
71
|
+
return element.requestFullscreen();
|
|
72
|
+
} else if (element.mozRequestFullScreen) {
|
|
73
|
+
return element.mozRequestFullScreen();
|
|
74
|
+
} else if (element.webkitRequestFullscreen) {
|
|
75
|
+
return element.webkitRequestFullscreen();
|
|
76
|
+
} else if (element.msRequestFullscreen) {
|
|
77
|
+
return element.msRequestFullscreen();
|
|
78
|
+
} else {
|
|
79
|
+
console.warn("当前浏览器不支持全屏 API");
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 退出全屏模式
|
|
85
|
+
* @returns {Promise<void> | undefined} 退出全屏请求 Promise(如支持)
|
|
86
|
+
*/
|
|
87
|
+
exitFullscreen: () => {
|
|
88
|
+
if (document.exitFullscreen) {
|
|
89
|
+
return document.exitFullscreen();
|
|
90
|
+
} else if (document.mozCancelFullScreen) {
|
|
91
|
+
return document.mozCancelFullScreen();
|
|
92
|
+
} else if (document.webkitExitFullscreen) {
|
|
93
|
+
return document.webkitExitFullscreen();
|
|
94
|
+
} else if (document.msExitFullscreen) {
|
|
95
|
+
return document.msExitFullscreen();
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* 获取当前全屏元素
|
|
101
|
+
* @returns {Element | null} 当前处于全屏模式的元素,无则返回 null
|
|
102
|
+
*/
|
|
103
|
+
getFullscreenElement: () => {
|
|
104
|
+
return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement || null;
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 检测当前是否处于全屏模式
|
|
109
|
+
* @returns {boolean} 是否全屏中
|
|
110
|
+
*/
|
|
111
|
+
isFullscreen: () => {
|
|
112
|
+
return !!(document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement);
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* 检测浏览器是否支持全屏 API
|
|
117
|
+
* @returns {boolean} 是否支持全屏
|
|
118
|
+
*/
|
|
119
|
+
isFullscreenEnabled: () => {
|
|
120
|
+
return !!(document.fullscreenEnabled || document.mozFullScreenEnabled || document.webkitFullscreenEnabled || document.msFullscreenEnabled);
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* 切换指定元素的全屏状态
|
|
125
|
+
* @param {Element} element - 要切换全屏的元素
|
|
126
|
+
* @returns {Promise<void> | undefined} 全屏操作 Promise
|
|
127
|
+
*/
|
|
128
|
+
toggleFullscreen: (element) => {
|
|
129
|
+
if (fullscreenHelper.isFullscreen()) {
|
|
130
|
+
return fullscreenHelper.exitFullscreen();
|
|
131
|
+
} else {
|
|
132
|
+
return fullscreenHelper.requestFullscreen(element);
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* 监听全屏变化事件
|
|
138
|
+
* @param {Function} callback - 全屏状态变化时的回调函数,参数为 isFullscreen: boolean
|
|
139
|
+
* @returns {Function} 取消监听的函数
|
|
140
|
+
*/
|
|
141
|
+
onFullscreenChange: (callback) => {
|
|
142
|
+
const handler = () => {
|
|
143
|
+
callback(fullscreenHelper.isFullscreen());
|
|
144
|
+
};
|
|
145
|
+
document.addEventListener("fullscreenchange", handler);
|
|
146
|
+
document.addEventListener("webkitfullscreenchange", handler);
|
|
147
|
+
document.addEventListener("mozfullscreenchange", handler);
|
|
148
|
+
document.addEventListener("msfullscreenchange", handler);
|
|
149
|
+
|
|
150
|
+
return () => {
|
|
151
|
+
document.removeEventListener("fullscreenchange", handler);
|
|
152
|
+
document.removeEventListener("webkitfullscreenchange", handler);
|
|
153
|
+
document.removeEventListener("mozfullscreenchange", handler);
|
|
154
|
+
document.removeEventListener("msfullscreenchange", handler);
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
};
|
|
54
158
|
|
|
55
|
-
export { getAllSearchParams, getSearchParam, getViewportSize };
|
|
159
|
+
export { fullscreenHelper, getAllSearchParams, getSearchParam, getViewportSize };
|
|
56
160
|
//# sourceMappingURL=browser.js.map
|
package/dist/browser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.js","sources":["../src/source/browser.js"],"sourcesContent":["/**\r\n * 视口尺寸对象。\r\n * @typedef {Object} ViewportDimensions\r\n * @property {number} w 视口宽度,单位像素。\r\n * @property {number} h 视口高度,单位像素。\r\n */\r\n\r\n/**\r\n * 获取当前视口(viewport)的宽高。\r\n *\r\n * 兼容策略:\r\n * 1. 优先使用 `window.innerWidth/innerHeight`(现代浏览器)。\r\n * 2. 降级到 `document.documentElement.clientWidth/clientHeight`(IE9+ 及怪异模式)。\r\n * 3. 最后降级到 `document.body.clientWidth/clientHeight`(IE6-8 怪异模式)。\r\n *\r\n * @returns {ViewportDimensions} 包含 `w`(宽度)和 `h`(高度)的对象,单位为像素。\r\n *\r\n * @example\r\n * const { w, h } = getViewportSize();\r\n * console.log(`视口尺寸:${w} × ${h}`);\r\n */\r\nexport function getViewportSize() {\r\n const d = document,\r\n root = d.documentElement,\r\n body = d.body;\r\n\r\n return {\r\n w: window.innerWidth || root.clientWidth || body.clientWidth,\r\n h: window.innerHeight || root.clientHeight || body.clientHeight\r\n };\r\n}\r\n\r\n/**\r\n * 将当前页面 URL 的 query 部分解析成键值对对象。\r\n *\r\n * @returns {Record<string, string>} 所有查询参数组成的平凡对象\r\n * (同名 key 仅保留最后一项)\r\n */\r\nexport function getAllSearchParams() {\r\n const urlSearchParams = new URLSearchParams(location.search);\r\n return Object.fromEntries(urlSearchParams.entries());\r\n}\r\n\r\n/**\r\n * 根据 key 获取当前页面 URL 中的单个查询参数。\r\n *\r\n * @param {string} key - 要提取的参数名\r\n * @returns {string | undefined} 对应参数值;不存在时返回 `undefined`\r\n */\r\nexport function getSearchParam(key) {\r\n const params = getAllSearchParams();\r\n return params[key];\r\n}\r\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,eAAe,GAAG;AAClC,IAAI,MAAM,CAAC,GAAG,QAAQ;AACtB,QAAQ,IAAI,GAAG,CAAC,CAAC,eAAe;AAChC,QAAQ,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC;AACtB;AACA,IAAI,OAAO;AACX,QAAQ,CAAC,EAAE,MAAM,CAAC,UAAU,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,WAAW;AACpE,QAAQ,CAAC,EAAE,MAAM,CAAC,WAAW,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY;AACvE,KAAK,CAAC;AACN,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,kBAAkB,GAAG;AACrC,IAAI,MAAM,eAAe,GAAG,IAAI,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AACjE,IAAI,OAAO,MAAM,CAAC,WAAW,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC,CAAC;AACzD,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,cAAc,CAAC,GAAG,EAAE;AACpC,IAAI,MAAM,MAAM,GAAG,kBAAkB,EAAE,CAAC;AACxC,IAAI,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;AACvB;;;;"}
|
|
1
|
+
{"version":3,"file":"browser.js","sources":["../src/source/browser.js"],"sourcesContent":["/**\r\n * 视口尺寸对象。\r\n * @typedef {Object} ViewportDimensions\r\n * @property {number} w 视口宽度,单位像素。\r\n * @property {number} h 视口高度,单位像素。\r\n */\r\n\r\n/**\r\n * 获取当前视口(viewport)的宽高。\r\n *\r\n * 兼容策略:\r\n * 1. 优先使用 `window.innerWidth/innerHeight`(现代浏览器)。\r\n * 2. 降级到 `document.documentElement.clientWidth/clientHeight`(IE9+ 及怪异模式)。\r\n * 3. 最后降级到 `document.body.clientWidth/clientHeight`(IE6-8 怪异模式)。\r\n *\r\n * @returns {ViewportDimensions} 包含 `w`(宽度)和 `h`(高度)的对象,单位为像素。\r\n *\r\n * @example\r\n * const { w, h } = getViewportSize();\r\n * console.log(`视口尺寸:${w} × ${h}`);\r\n */\r\nexport function getViewportSize() {\r\n const d = document,\r\n root = d.documentElement,\r\n body = d.body;\r\n\r\n return {\r\n w: window.innerWidth || root.clientWidth || body.clientWidth,\r\n h: window.innerHeight || root.clientHeight || body.clientHeight\r\n };\r\n}\r\n\r\n/**\r\n * 将当前页面 URL 的 query 部分解析成键值对对象。\r\n *\r\n * @returns {Record<string, string>} 所有查询参数组成的平凡对象\r\n * (同名 key 仅保留最后一项)\r\n */\r\nexport function getAllSearchParams() {\r\n const urlSearchParams = new URLSearchParams(location.search);\r\n return Object.fromEntries(urlSearchParams.entries());\r\n}\r\n\r\n/**\r\n * 根据 key 获取当前页面 URL 中的单个查询参数。\r\n *\r\n * @param {string} key - 要提取的参数名\r\n * @returns {string | undefined} 对应参数值;不存在时返回 `undefined`\r\n */\r\nexport function getSearchParam(key) {\r\n const params = getAllSearchParams();\r\n return params[key];\r\n}\r\n\r\n/**\r\n * 全屏操作辅助工具对象\r\n * @namespace fullscreenHelper\r\n */\r\nexport const fullscreenHelper = {\r\n /**\r\n * 请求进入全屏模式\r\n * @param {Element} element - 要全屏显示的元素\r\n * @returns {Promise<void> | undefined} 全屏请求 Promise(如支持)\r\n */\r\n requestFullscreen: (element) => {\r\n if (!element) {\r\n console.warn(\"未提供有效的 DOM 元素\");\r\n return;\r\n }\r\n if (element.requestFullscreen) {\r\n return element.requestFullscreen();\r\n } else if (element.mozRequestFullScreen) {\r\n return element.mozRequestFullScreen();\r\n } else if (element.webkitRequestFullscreen) {\r\n return element.webkitRequestFullscreen();\r\n } else if (element.msRequestFullscreen) {\r\n return element.msRequestFullscreen();\r\n } else {\r\n console.warn(\"当前浏览器不支持全屏 API\");\r\n }\r\n },\r\n\r\n /**\r\n * 退出全屏模式\r\n * @returns {Promise<void> | undefined} 退出全屏请求 Promise(如支持)\r\n */\r\n exitFullscreen: () => {\r\n if (document.exitFullscreen) {\r\n return document.exitFullscreen();\r\n } else if (document.mozCancelFullScreen) {\r\n return document.mozCancelFullScreen();\r\n } else if (document.webkitExitFullscreen) {\r\n return document.webkitExitFullscreen();\r\n } else if (document.msExitFullscreen) {\r\n return document.msExitFullscreen();\r\n }\r\n },\r\n\r\n /**\r\n * 获取当前全屏元素\r\n * @returns {Element | null} 当前处于全屏模式的元素,无则返回 null\r\n */\r\n getFullscreenElement: () => {\r\n return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement || null;\r\n },\r\n\r\n /**\r\n * 检测当前是否处于全屏模式\r\n * @returns {boolean} 是否全屏中\r\n */\r\n isFullscreen: () => {\r\n return !!(document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement);\r\n },\r\n\r\n /**\r\n * 检测浏览器是否支持全屏 API\r\n * @returns {boolean} 是否支持全屏\r\n */\r\n isFullscreenEnabled: () => {\r\n return !!(document.fullscreenEnabled || document.mozFullScreenEnabled || document.webkitFullscreenEnabled || document.msFullscreenEnabled);\r\n },\r\n\r\n /**\r\n * 切换指定元素的全屏状态\r\n * @param {Element} element - 要切换全屏的元素\r\n * @returns {Promise<void> | undefined} 全屏操作 Promise\r\n */\r\n toggleFullscreen: (element) => {\r\n if (fullscreenHelper.isFullscreen()) {\r\n return fullscreenHelper.exitFullscreen();\r\n } else {\r\n return fullscreenHelper.requestFullscreen(element);\r\n }\r\n },\r\n\r\n /**\r\n * 监听全屏变化事件\r\n * @param {Function} callback - 全屏状态变化时的回调函数,参数为 isFullscreen: boolean\r\n * @returns {Function} 取消监听的函数\r\n */\r\n onFullscreenChange: (callback) => {\r\n const handler = () => {\r\n callback(fullscreenHelper.isFullscreen());\r\n };\r\n document.addEventListener(\"fullscreenchange\", handler);\r\n document.addEventListener(\"webkitfullscreenchange\", handler);\r\n document.addEventListener(\"mozfullscreenchange\", handler);\r\n document.addEventListener(\"msfullscreenchange\", handler);\r\n\r\n return () => {\r\n document.removeEventListener(\"fullscreenchange\", handler);\r\n document.removeEventListener(\"webkitfullscreenchange\", handler);\r\n document.removeEventListener(\"mozfullscreenchange\", handler);\r\n document.removeEventListener(\"msfullscreenchange\", handler);\r\n };\r\n }\r\n};\r\n"],"names":[],"mappings":"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"}
|
package/dist/download.cjs
CHANGED
|
@@ -79,6 +79,9 @@ async function fetchOrDownloadByUrl(url, fileName) {
|
|
|
79
79
|
const urlPathname = new URL(url).pathname;
|
|
80
80
|
// 获取路径的最后一部分作为文件名,并移除可能的查询参数
|
|
81
81
|
fileName = urlPathname.substring(urlPathname.lastIndexOf("/") + 1).split("?")[0];
|
|
82
|
+
if (fileName) {
|
|
83
|
+
fileName = decodeURIComponent(fileName);
|
|
84
|
+
}
|
|
82
85
|
} catch (e) {}
|
|
83
86
|
// 如果提取后文件名为空(例如 URL 以 '/' 结尾),也使用时间戳
|
|
84
87
|
if (!fileName) {
|
package/dist/download.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"download.cjs","sources":["../src/source/download.js"],"sourcesContent":["/**\r\n * 通过动态创建 `<a>` 标签触发浏览器下载。\r\n * 注意:此方法可能无法强制下载浏览器原生支持的文件(如图片、PDF),浏览器可能会选择直接打开。\r\n *\r\n * @param {string} url - 任意可下载地址(同源或允许跨域)\r\n * @param {string} [fileName] - 保存到本地的文件名;不传时使用时间戳\r\n */\r\nexport function downloadByUrl(url, fileName) {\r\n const a = document.createElement(\"a\");\r\n a.style.display = \"none\";\r\n a.rel = \"noopener\";\r\n a.href = url;\r\n a.download = fileName || Date.now();\r\n document.body.appendChild(a);\r\n a.click();\r\n document.body.removeChild(a);\r\n}\r\n\r\n/**\r\n * 把 Blob 转成临时 URL 并触发下载,下载完成后立即释放内存。\r\n *\r\n * @param {Blob} blob - 待下载的 Blob(含 File)\r\n * @param {string} [fileName] - 保存到本地的文件名\r\n */\r\nexport function downloadByBlob(blob, fileName) {\r\n const url = URL.createObjectURL(blob);\r\n downloadByUrl(url, fileName);\r\n setTimeout(() => URL.revokeObjectURL(url), 0);\r\n}\r\n\r\n/**\r\n * 将任意数据包装成 Blob 并下载。\r\n *\r\n * @param {string | ArrayBufferView | ArrayBuffer | Blob} data - 要写入文件的数据\r\n * @param {string} [fileName] - 保存到本地的文件名\r\n * @param {string} [mimeType] - MIME 类型;默认 `application/octet-stream`\r\n */\r\nexport function downloadByData(data, fileName, mimeType = \"application/octet-stream\") {\r\n downloadByBlob(new Blob([data], { type: mimeType }), fileName);\r\n}\r\n\r\n/**\r\n * 快捷下载 Excel 文件(MIME 已固定)。\r\n *\r\n * @param {string | ArrayBufferView | ArrayBuffer | Blob} data - Excel 二进制或字符串内容\r\n * @param {string} [fileName] - 保存到本地的文件名\r\n */\r\nexport function downloadExcel(data, fileName) {\r\n downloadByData(data, fileName, \"application/vnd.ms-excel\");\r\n}\r\n\r\n/**\r\n * 快捷下载 JSON 文件(MIME 已固定)。\r\n * 若传入非字符串数据,会自行 `JSON.stringify`。\r\n *\r\n * @param {any} data - 要序列化的 JSON 数据\r\n * @param {string} [fileName] - 保存到本地的文件名\r\n */\r\nexport function downloadJSON(data, fileName) {\r\n // downloadByData(typeof data === \"string\" ? data : JSON.stringify(data, null, 4), fileName, \"application/json\");\r\n downloadByData(data, fileName, \"application/json\");\r\n}\r\n\r\n/**\r\n * 通过 `fetch` 获取资源并强制下载,避免浏览器直接打开文件。\r\n * 此方法适用于下载图片、PDF 等浏览器默认会打开的文件类型。\r\n * 如果 `fetch` 失败(如 CORS 策略阻止),会回退到 `downloadByUrl` 方法作为备选方案。\r\n *\r\n * @param {string} url - 文件的 URL 地址\r\n * @param {string} [fileName] - 保存到本地的文件名。如果不提供,会尝试从 URL 中自动提取\r\n * @returns {Promise<void>} 返回一个 Promise,在下载开始或失败后 resolve\r\n */\r\nexport async function fetchOrDownloadByUrl(url, fileName) {\r\n // 如果未提供文件名,尝试从 URL 路径中提取\r\n if (!fileName) {\r\n try {\r\n const urlPathname = new URL(url).pathname;\r\n // 获取路径的最后一部分作为文件名,并移除可能的查询参数\r\n fileName = urlPathname.substring(urlPathname.lastIndexOf(\"/\") + 1).split(\"?\")[0];\r\n } catch (e) {}\r\n // 如果提取后文件名为空(例如 URL 以 '/' 结尾),也使用时间戳\r\n if (!fileName) {\r\n fileName = Date.now().toString();\r\n }\r\n }\r\n\r\n try {\r\n const response = await fetch(url, {\r\n method: \"GET\",\r\n mode: \"cors\",\r\n cache: \"no-cache\"\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`HTTP error! ${response.status}: ${response.statusText}`);\r\n }\r\n\r\n const blob = await response.blob();\r\n downloadByBlob(blob, fileName);\r\n } catch (error) {\r\n downloadByUrl(url, fileName);\r\n }\r\n}\r\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"download.cjs","sources":["../src/source/download.js"],"sourcesContent":["/**\r\n * 通过动态创建 `<a>` 标签触发浏览器下载。\r\n * 注意:此方法可能无法强制下载浏览器原生支持的文件(如图片、PDF),浏览器可能会选择直接打开。\r\n *\r\n * @param {string} url - 任意可下载地址(同源或允许跨域)\r\n * @param {string} [fileName] - 保存到本地的文件名;不传时使用时间戳\r\n */\r\nexport function downloadByUrl(url, fileName) {\r\n const a = document.createElement(\"a\");\r\n a.style.display = \"none\";\r\n a.rel = \"noopener\";\r\n a.href = url;\r\n a.download = fileName || Date.now();\r\n document.body.appendChild(a);\r\n a.click();\r\n document.body.removeChild(a);\r\n}\r\n\r\n/**\r\n * 把 Blob 转成临时 URL 并触发下载,下载完成后立即释放内存。\r\n *\r\n * @param {Blob} blob - 待下载的 Blob(含 File)\r\n * @param {string} [fileName] - 保存到本地的文件名\r\n */\r\nexport function downloadByBlob(blob, fileName) {\r\n const url = URL.createObjectURL(blob);\r\n downloadByUrl(url, fileName);\r\n setTimeout(() => URL.revokeObjectURL(url), 0);\r\n}\r\n\r\n/**\r\n * 将任意数据包装成 Blob 并下载。\r\n *\r\n * @param {string | ArrayBufferView | ArrayBuffer | Blob} data - 要写入文件的数据\r\n * @param {string} [fileName] - 保存到本地的文件名\r\n * @param {string} [mimeType] - MIME 类型;默认 `application/octet-stream`\r\n */\r\nexport function downloadByData(data, fileName, mimeType = \"application/octet-stream\") {\r\n downloadByBlob(new Blob([data], { type: mimeType }), fileName);\r\n}\r\n\r\n/**\r\n * 快捷下载 Excel 文件(MIME 已固定)。\r\n *\r\n * @param {string | ArrayBufferView | ArrayBuffer | Blob} data - Excel 二进制或字符串内容\r\n * @param {string} [fileName] - 保存到本地的文件名\r\n */\r\nexport function downloadExcel(data, fileName) {\r\n downloadByData(data, fileName, \"application/vnd.ms-excel\");\r\n}\r\n\r\n/**\r\n * 快捷下载 JSON 文件(MIME 已固定)。\r\n * 若传入非字符串数据,会自行 `JSON.stringify`。\r\n *\r\n * @param {any} data - 要序列化的 JSON 数据\r\n * @param {string} [fileName] - 保存到本地的文件名\r\n */\r\nexport function downloadJSON(data, fileName) {\r\n // downloadByData(typeof data === \"string\" ? data : JSON.stringify(data, null, 4), fileName, \"application/json\");\r\n downloadByData(data, fileName, \"application/json\");\r\n}\r\n\r\n/**\r\n * 通过 `fetch` 获取资源并强制下载,避免浏览器直接打开文件。\r\n * 此方法适用于下载图片、PDF 等浏览器默认会打开的文件类型。\r\n * 如果 `fetch` 失败(如 CORS 策略阻止),会回退到 `downloadByUrl` 方法作为备选方案。\r\n *\r\n * @param {string} url - 文件的 URL 地址\r\n * @param {string} [fileName] - 保存到本地的文件名。如果不提供,会尝试从 URL 中自动提取\r\n * @returns {Promise<void>} 返回一个 Promise,在下载开始或失败后 resolve\r\n */\r\nexport async function fetchOrDownloadByUrl(url, fileName) {\r\n // 如果未提供文件名,尝试从 URL 路径中提取\r\n if (!fileName) {\r\n try {\r\n const urlPathname = new URL(url).pathname;\r\n // 获取路径的最后一部分作为文件名,并移除可能的查询参数\r\n fileName = urlPathname.substring(urlPathname.lastIndexOf(\"/\") + 1).split(\"?\")[0];\r\n if (fileName) {\r\n fileName = decodeURIComponent(fileName);\r\n }\r\n } catch (e) {}\r\n // 如果提取后文件名为空(例如 URL 以 '/' 结尾),也使用时间戳\r\n if (!fileName) {\r\n fileName = Date.now().toString();\r\n }\r\n }\r\n\r\n try {\r\n const response = await fetch(url, {\r\n method: \"GET\",\r\n mode: \"cors\",\r\n cache: \"no-cache\"\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`HTTP error! ${response.status}: ${response.statusText}`);\r\n }\r\n\r\n const blob = await response.blob();\r\n downloadByBlob(blob, fileName);\r\n } catch (error) {\r\n downloadByUrl(url, fileName);\r\n }\r\n}\r\n"],"names":[],"mappings":"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"}
|
package/dist/download.js
CHANGED
|
@@ -77,6 +77,9 @@ async function fetchOrDownloadByUrl(url, fileName) {
|
|
|
77
77
|
const urlPathname = new URL(url).pathname;
|
|
78
78
|
// 获取路径的最后一部分作为文件名,并移除可能的查询参数
|
|
79
79
|
fileName = urlPathname.substring(urlPathname.lastIndexOf("/") + 1).split("?")[0];
|
|
80
|
+
if (fileName) {
|
|
81
|
+
fileName = decodeURIComponent(fileName);
|
|
82
|
+
}
|
|
80
83
|
} catch (e) {}
|
|
81
84
|
// 如果提取后文件名为空(例如 URL 以 '/' 结尾),也使用时间戳
|
|
82
85
|
if (!fileName) {
|
package/dist/download.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"download.js","sources":["../src/source/download.js"],"sourcesContent":["/**\r\n * 通过动态创建 `<a>` 标签触发浏览器下载。\r\n * 注意:此方法可能无法强制下载浏览器原生支持的文件(如图片、PDF),浏览器可能会选择直接打开。\r\n *\r\n * @param {string} url - 任意可下载地址(同源或允许跨域)\r\n * @param {string} [fileName] - 保存到本地的文件名;不传时使用时间戳\r\n */\r\nexport function downloadByUrl(url, fileName) {\r\n const a = document.createElement(\"a\");\r\n a.style.display = \"none\";\r\n a.rel = \"noopener\";\r\n a.href = url;\r\n a.download = fileName || Date.now();\r\n document.body.appendChild(a);\r\n a.click();\r\n document.body.removeChild(a);\r\n}\r\n\r\n/**\r\n * 把 Blob 转成临时 URL 并触发下载,下载完成后立即释放内存。\r\n *\r\n * @param {Blob} blob - 待下载的 Blob(含 File)\r\n * @param {string} [fileName] - 保存到本地的文件名\r\n */\r\nexport function downloadByBlob(blob, fileName) {\r\n const url = URL.createObjectURL(blob);\r\n downloadByUrl(url, fileName);\r\n setTimeout(() => URL.revokeObjectURL(url), 0);\r\n}\r\n\r\n/**\r\n * 将任意数据包装成 Blob 并下载。\r\n *\r\n * @param {string | ArrayBufferView | ArrayBuffer | Blob} data - 要写入文件的数据\r\n * @param {string} [fileName] - 保存到本地的文件名\r\n * @param {string} [mimeType] - MIME 类型;默认 `application/octet-stream`\r\n */\r\nexport function downloadByData(data, fileName, mimeType = \"application/octet-stream\") {\r\n downloadByBlob(new Blob([data], { type: mimeType }), fileName);\r\n}\r\n\r\n/**\r\n * 快捷下载 Excel 文件(MIME 已固定)。\r\n *\r\n * @param {string | ArrayBufferView | ArrayBuffer | Blob} data - Excel 二进制或字符串内容\r\n * @param {string} [fileName] - 保存到本地的文件名\r\n */\r\nexport function downloadExcel(data, fileName) {\r\n downloadByData(data, fileName, \"application/vnd.ms-excel\");\r\n}\r\n\r\n/**\r\n * 快捷下载 JSON 文件(MIME 已固定)。\r\n * 若传入非字符串数据,会自行 `JSON.stringify`。\r\n *\r\n * @param {any} data - 要序列化的 JSON 数据\r\n * @param {string} [fileName] - 保存到本地的文件名\r\n */\r\nexport function downloadJSON(data, fileName) {\r\n // downloadByData(typeof data === \"string\" ? data : JSON.stringify(data, null, 4), fileName, \"application/json\");\r\n downloadByData(data, fileName, \"application/json\");\r\n}\r\n\r\n/**\r\n * 通过 `fetch` 获取资源并强制下载,避免浏览器直接打开文件。\r\n * 此方法适用于下载图片、PDF 等浏览器默认会打开的文件类型。\r\n * 如果 `fetch` 失败(如 CORS 策略阻止),会回退到 `downloadByUrl` 方法作为备选方案。\r\n *\r\n * @param {string} url - 文件的 URL 地址\r\n * @param {string} [fileName] - 保存到本地的文件名。如果不提供,会尝试从 URL 中自动提取\r\n * @returns {Promise<void>} 返回一个 Promise,在下载开始或失败后 resolve\r\n */\r\nexport async function fetchOrDownloadByUrl(url, fileName) {\r\n // 如果未提供文件名,尝试从 URL 路径中提取\r\n if (!fileName) {\r\n try {\r\n const urlPathname = new URL(url).pathname;\r\n // 获取路径的最后一部分作为文件名,并移除可能的查询参数\r\n fileName = urlPathname.substring(urlPathname.lastIndexOf(\"/\") + 1).split(\"?\")[0];\r\n } catch (e) {}\r\n // 如果提取后文件名为空(例如 URL 以 '/' 结尾),也使用时间戳\r\n if (!fileName) {\r\n fileName = Date.now().toString();\r\n }\r\n }\r\n\r\n try {\r\n const response = await fetch(url, {\r\n method: \"GET\",\r\n mode: \"cors\",\r\n cache: \"no-cache\"\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`HTTP error! ${response.status}: ${response.statusText}`);\r\n }\r\n\r\n const blob = await response.blob();\r\n downloadByBlob(blob, fileName);\r\n } catch (error) {\r\n downloadByUrl(url, fileName);\r\n }\r\n}\r\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"download.js","sources":["../src/source/download.js"],"sourcesContent":["/**\r\n * 通过动态创建 `<a>` 标签触发浏览器下载。\r\n * 注意:此方法可能无法强制下载浏览器原生支持的文件(如图片、PDF),浏览器可能会选择直接打开。\r\n *\r\n * @param {string} url - 任意可下载地址(同源或允许跨域)\r\n * @param {string} [fileName] - 保存到本地的文件名;不传时使用时间戳\r\n */\r\nexport function downloadByUrl(url, fileName) {\r\n const a = document.createElement(\"a\");\r\n a.style.display = \"none\";\r\n a.rel = \"noopener\";\r\n a.href = url;\r\n a.download = fileName || Date.now();\r\n document.body.appendChild(a);\r\n a.click();\r\n document.body.removeChild(a);\r\n}\r\n\r\n/**\r\n * 把 Blob 转成临时 URL 并触发下载,下载完成后立即释放内存。\r\n *\r\n * @param {Blob} blob - 待下载的 Blob(含 File)\r\n * @param {string} [fileName] - 保存到本地的文件名\r\n */\r\nexport function downloadByBlob(blob, fileName) {\r\n const url = URL.createObjectURL(blob);\r\n downloadByUrl(url, fileName);\r\n setTimeout(() => URL.revokeObjectURL(url), 0);\r\n}\r\n\r\n/**\r\n * 将任意数据包装成 Blob 并下载。\r\n *\r\n * @param {string | ArrayBufferView | ArrayBuffer | Blob} data - 要写入文件的数据\r\n * @param {string} [fileName] - 保存到本地的文件名\r\n * @param {string} [mimeType] - MIME 类型;默认 `application/octet-stream`\r\n */\r\nexport function downloadByData(data, fileName, mimeType = \"application/octet-stream\") {\r\n downloadByBlob(new Blob([data], { type: mimeType }), fileName);\r\n}\r\n\r\n/**\r\n * 快捷下载 Excel 文件(MIME 已固定)。\r\n *\r\n * @param {string | ArrayBufferView | ArrayBuffer | Blob} data - Excel 二进制或字符串内容\r\n * @param {string} [fileName] - 保存到本地的文件名\r\n */\r\nexport function downloadExcel(data, fileName) {\r\n downloadByData(data, fileName, \"application/vnd.ms-excel\");\r\n}\r\n\r\n/**\r\n * 快捷下载 JSON 文件(MIME 已固定)。\r\n * 若传入非字符串数据,会自行 `JSON.stringify`。\r\n *\r\n * @param {any} data - 要序列化的 JSON 数据\r\n * @param {string} [fileName] - 保存到本地的文件名\r\n */\r\nexport function downloadJSON(data, fileName) {\r\n // downloadByData(typeof data === \"string\" ? data : JSON.stringify(data, null, 4), fileName, \"application/json\");\r\n downloadByData(data, fileName, \"application/json\");\r\n}\r\n\r\n/**\r\n * 通过 `fetch` 获取资源并强制下载,避免浏览器直接打开文件。\r\n * 此方法适用于下载图片、PDF 等浏览器默认会打开的文件类型。\r\n * 如果 `fetch` 失败(如 CORS 策略阻止),会回退到 `downloadByUrl` 方法作为备选方案。\r\n *\r\n * @param {string} url - 文件的 URL 地址\r\n * @param {string} [fileName] - 保存到本地的文件名。如果不提供,会尝试从 URL 中自动提取\r\n * @returns {Promise<void>} 返回一个 Promise,在下载开始或失败后 resolve\r\n */\r\nexport async function fetchOrDownloadByUrl(url, fileName) {\r\n // 如果未提供文件名,尝试从 URL 路径中提取\r\n if (!fileName) {\r\n try {\r\n const urlPathname = new URL(url).pathname;\r\n // 获取路径的最后一部分作为文件名,并移除可能的查询参数\r\n fileName = urlPathname.substring(urlPathname.lastIndexOf(\"/\") + 1).split(\"?\")[0];\r\n if (fileName) {\r\n fileName = decodeURIComponent(fileName);\r\n }\r\n } catch (e) {}\r\n // 如果提取后文件名为空(例如 URL 以 '/' 结尾),也使用时间戳\r\n if (!fileName) {\r\n fileName = Date.now().toString();\r\n }\r\n }\r\n\r\n try {\r\n const response = await fetch(url, {\r\n method: \"GET\",\r\n mode: \"cors\",\r\n cache: \"no-cache\"\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`HTTP error! ${response.status}: ${response.statusText}`);\r\n }\r\n\r\n const blob = await response.blob();\r\n downloadByBlob(blob, fileName);\r\n } catch (error) {\r\n downloadByUrl(url, fileName);\r\n }\r\n}\r\n"],"names":[],"mappings":"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"}
|
package/dist/tree.cjs
CHANGED
|
@@ -179,11 +179,70 @@ function extractFullyCheckedKeys(treeData, selectedKeys, idKey = "id", childrenK
|
|
|
179
179
|
checked: [...checked],
|
|
180
180
|
halfChecked: [...halfChecked]
|
|
181
181
|
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* 在树形结构中查找目标节点的完整路径(从根节点到目标节点,含目标节点自身)。
|
|
186
|
+
*
|
|
187
|
+
* @template T extends Record<PropertyKey, any>
|
|
188
|
+
* @param {T[]} nodes - 树形结构森林(支持多根)
|
|
189
|
+
* @param {any} targetValue - 目标节点的 key 值
|
|
190
|
+
* @param {string} [key='id'] - 节点唯一标识字段
|
|
191
|
+
* @param {string} [parentKey='pid'] - 父节点标识字段(指向父节点的 key 值)
|
|
192
|
+
* @param {string} [childrenKey='children'] - 子节点数组字段
|
|
193
|
+
* @returns {T[]} 从根到目标节点的路径数组;未找到返回空数组
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* const tree = [
|
|
197
|
+
* { id: 1, pid: null, children: [
|
|
198
|
+
* { id: 2, pid: 1, children: [
|
|
199
|
+
* { id: 3, pid: 2 }
|
|
200
|
+
* ]}
|
|
201
|
+
* ]}
|
|
202
|
+
* ];
|
|
203
|
+
* findTreeNodePath(tree, 3); // [{id:1, ...}, {id:2, ...}, {id:3, ...}]
|
|
204
|
+
*/
|
|
205
|
+
function findTreeNodePath(nodes, targetValue, key = "id", parentKey = "pid", childrenKey = "children") {
|
|
206
|
+
if (!Array.isArray(nodes) || nodes.length === 0 || targetValue == null) {
|
|
207
|
+
return [];
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// 1. 建立节点索引
|
|
211
|
+
const index = new Map();
|
|
212
|
+
const stack = [...nodes];
|
|
213
|
+
|
|
214
|
+
while (stack.length) {
|
|
215
|
+
const node = stack.pop();
|
|
216
|
+
if (!node || typeof node !== "object") continue;
|
|
217
|
+
|
|
218
|
+
index.set(node[key], node);
|
|
219
|
+
|
|
220
|
+
const children = node[childrenKey];
|
|
221
|
+
if (Array.isArray(children)) {
|
|
222
|
+
stack.push(...children);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// 2. 回溯路径(防循环引用)
|
|
227
|
+
const path = [];
|
|
228
|
+
const visited = new Set();
|
|
229
|
+
let cur = index.get(targetValue);
|
|
230
|
+
|
|
231
|
+
while (cur && !visited.has(cur[key])) {
|
|
232
|
+
visited.add(cur[key]);
|
|
233
|
+
path.push(cur);
|
|
234
|
+
|
|
235
|
+
const parentValue = cur[parentKey];
|
|
236
|
+
cur = parentValue != null ? index.get(parentValue) : undefined;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return path.reverse();
|
|
182
240
|
}
|
|
183
241
|
|
|
184
242
|
exports.extractFullyCheckedKeys = extractFullyCheckedKeys;
|
|
185
243
|
exports.findObjAttrValueById = findObjAttrValueById;
|
|
186
244
|
exports.findTreeNodeById = findTreeNodeById;
|
|
245
|
+
exports.findTreeNodePath = findTreeNodePath;
|
|
187
246
|
exports.flatCompleteTree2NestedTree = flatCompleteTree2NestedTree;
|
|
188
247
|
exports.nestedTree2IdMap = nestedTree2IdMap;
|
|
189
248
|
//# sourceMappingURL=tree.cjs.map
|
package/dist/tree.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree.cjs","sources":["../src/source/tree.js"],"sourcesContent":["/**\r\n * 把嵌套树拍平成 `{ [id]: node }` 映射,同时把原 `children` 置为 `null`。\r\n *\r\n * @template T extends Record<PropertyKey, any>\r\n * @param {T[]} data - 嵌套树森林\r\n * @param {string} [idKey='id'] - 主键字段\r\n * @param {string} [childrenKey='children'] - 子节点字段\r\n * @returns {Record<string, T & { [k in typeof childrenKey]: null }>} id→节点的映射表\r\n */\r\nexport function nestedTree2IdMap(data, idKey = \"id\", childrenKey = \"children\") {\r\n const retObj = {};\r\n function fn(nodes) {\r\n if (Array.isArray(nodes) && nodes.length > 0) {\r\n nodes.forEach((node) => {\r\n retObj[node[idKey]] = { ...node };\r\n retObj[node[idKey]][childrenKey] = null;\r\n\r\n fn(node[childrenKey]);\r\n });\r\n }\r\n }\r\n fn(data);\r\n return retObj;\r\n}\r\n\r\n/**\r\n * 把**已包含完整父子关系**的扁平节点列表还原成嵌套树(森林)。\r\n *\r\n * @template T extends Record<PropertyKey, any>\r\n * @param {T[]} nodes - 扁平节点列表(必须包含 id / parentId)\r\n * @param {number | string} [parentId=0] - 根节点标识值\r\n * @param {Object} [opts] - 字段映射配置\r\n * @param {string} [opts.idKey='id'] - 节点主键\r\n * @param {string} [opts.parentKey='parentId'] - 父节点外键\r\n * @param {string} [opts.childrenKey='children'] - 存放子节点的字段\r\n * @returns {(T & { [k in typeof childrenKey]: T[] })[]} 嵌套树森林\r\n */\r\nexport function flatCompleteTree2NestedTree(nodes, parentId = 0, { idKey = \"id\", parentKey = \"parentId\", childrenKey = \"children\" } = {}) {\r\n const map = new Map(); // id -> node\r\n const items = []; // 多根森林\r\n\r\n // 1. 初始化:保证每个节点都有 children,并存入 map\r\n for (const item of nodes) {\r\n const node = { ...item, [childrenKey]: [] };\r\n map.set(item[idKey], node);\r\n }\r\n\r\n // 2. 建立父子关系\r\n for (const item of nodes) {\r\n const node = map.get(item[idKey]);\r\n const parentIdVal = item[parentKey];\r\n\r\n if (parentIdVal === parentId) {\r\n // 根层\r\n items.push(node);\r\n } else {\r\n // 非根层:找到父节点,把自己挂上去\r\n const parent = map.get(parentIdVal);\r\n if (parent) parent[childrenKey].push(node);\r\n // 如果 parent 不存在,说明数据不完整,可自定义处理\r\n }\r\n }\r\n\r\n return items;\r\n}\r\n\r\n/**\r\n * 在嵌套树中按 `id` 递归查找节点\r\n *\r\n * @template T extends Record<PropertyKey, any>\r\n * @param {string | number} id - 要查找的 id\r\n * @param {T[]} arr - 嵌套树森林\r\n * @param {string} [idKey='id'] - 主键字段\r\n * @param {string} [childrenKey='children'] - 子节点字段\r\n * @returns {T | undefined} 找到的节点;未找到返回 `undefined`\r\n */\r\nexport function findTreeNodeById(id, arr, idKey = \"id\", childrenKey = \"children\") {\r\n if (Array.isArray(arr) && arr.length > 0) {\r\n for (let i = 0; i < arr.length; i++) {\r\n const item = arr[i];\r\n if (item[idKey]?.toString() === id?.toString()) {\r\n return item;\r\n } else if (Array.isArray(item[childrenKey]) && item[childrenKey].length > 0) {\r\n const result = findTreeNodeById(id, item[childrenKey], idKey, childrenKey);\r\n if (result) {\r\n return result;\r\n }\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * 在嵌套树中按 `id` 递归查找节点,并返回其指定属性值。\r\n *\r\n * @template T extends Record<PropertyKey, any>\r\n * @param {string | number} id - 要查找的 id\r\n * @param {T[]} arr - 嵌套树森林\r\n * @param {string} [resultKey='name'] - 需要返回的字段\r\n * @param {string} [idKey='id'] - 主键字段\r\n * @param {string} [childrenKey='children'] - 子节点字段\r\n * @returns {any} 找到的值;未找到返回 `undefined`\r\n */\r\nexport function findObjAttrValueById(id, arr, resultKey = \"name\", idKey = \"id\", childrenKey = \"children\") {\r\n return findTreeNodeById(id, arr, idKey, childrenKey)?.[resultKey];\r\n}\r\n\r\n/**\r\n * 从服务端返回的已选 id 数组里,提取出\r\n * 1. 叶子节点\r\n * 2. 所有子节点都被选中的父节点\r\n * 其余父节点一律丢弃(由前端 Tree 自动算半选)\r\n *\r\n * @param {Array} treeData 完整树\r\n * @param {Array} selectedKeys 后端给的选中 id 数组\r\n * @param {String} idKey 节点唯一字段\r\n * @param {String} childrenKey 子节点字段\r\n * @returns {{checked: string[], halfChecked: string[]}}\r\n */\r\nexport function extractFullyCheckedKeys(treeData, selectedKeys, idKey = \"id\", childrenKey = \"children\") {\r\n const selectedSet = new Set(selectedKeys);\r\n const checked = new Set();\r\n const halfChecked = new Set();\r\n\r\n /* 返回值含义\r\n 0 - 未选中\r\n 1 - 半选\r\n 2 - 全选\r\n */\r\n function dfs(node) {\r\n const nodeId = node[idKey];\r\n const children = node[childrenKey] || [];\r\n\r\n // 叶子\r\n if (!children.length) {\r\n if (selectedSet.has(nodeId)) {\r\n checked.add(nodeId);\r\n return 2;\r\n }\r\n return 0;\r\n }\r\n\r\n // 非叶子\r\n let allChecked = true;\r\n let someChecked = false;\r\n\r\n children.forEach((child) => {\r\n const childState = dfs(child);\r\n if (childState !== 2) allChecked = false;\r\n if (childState >= 1) someChecked = true;\r\n });\r\n\r\n // 当前节点本身在 selectedKeys 里,但子节点未全选 → 只能算半选\r\n if (selectedSet.has(nodeId)) {\r\n if (allChecked) {\r\n checked.add(nodeId);\r\n return 2;\r\n }\r\n halfChecked.add(nodeId);\r\n return 1;\r\n }\r\n\r\n // 当前节点不在 selectedKeys 里,看子节点\r\n if (allChecked) {\r\n checked.add(nodeId);\r\n return 2;\r\n }\r\n if (someChecked) {\r\n halfChecked.add(nodeId);\r\n return 1;\r\n }\r\n return 0;\r\n }\r\n\r\n treeData.forEach(dfs);\r\n return {\r\n checked: [...checked],\r\n halfChecked: [...halfChecked]\r\n };\r\n}\r\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tree.cjs","sources":["../src/source/tree.js"],"sourcesContent":["/**\r\n * 把嵌套树拍平成 `{ [id]: node }` 映射,同时把原 `children` 置为 `null`。\r\n *\r\n * @template T extends Record<PropertyKey, any>\r\n * @param {T[]} data - 嵌套树森林\r\n * @param {string} [idKey='id'] - 主键字段\r\n * @param {string} [childrenKey='children'] - 子节点字段\r\n * @returns {Record<string, T & { [k in typeof childrenKey]: null }>} id→节点的映射表\r\n */\r\nexport function nestedTree2IdMap(data, idKey = \"id\", childrenKey = \"children\") {\r\n const retObj = {};\r\n function fn(nodes) {\r\n if (Array.isArray(nodes) && nodes.length > 0) {\r\n nodes.forEach((node) => {\r\n retObj[node[idKey]] = { ...node };\r\n retObj[node[idKey]][childrenKey] = null;\r\n\r\n fn(node[childrenKey]);\r\n });\r\n }\r\n }\r\n fn(data);\r\n return retObj;\r\n}\r\n\r\n/**\r\n * 把**已包含完整父子关系**的扁平节点列表还原成嵌套树(森林)。\r\n *\r\n * @template T extends Record<PropertyKey, any>\r\n * @param {T[]} nodes - 扁平节点列表(必须包含 id / parentId)\r\n * @param {number | string} [parentId=0] - 根节点标识值\r\n * @param {Object} [opts] - 字段映射配置\r\n * @param {string} [opts.idKey='id'] - 节点主键\r\n * @param {string} [opts.parentKey='parentId'] - 父节点外键\r\n * @param {string} [opts.childrenKey='children'] - 存放子节点的字段\r\n * @returns {(T & { [k in typeof childrenKey]: T[] })[]} 嵌套树森林\r\n */\r\nexport function flatCompleteTree2NestedTree(nodes, parentId = 0, { idKey = \"id\", parentKey = \"parentId\", childrenKey = \"children\" } = {}) {\r\n const map = new Map(); // id -> node\r\n const items = []; // 多根森林\r\n\r\n // 1. 初始化:保证每个节点都有 children,并存入 map\r\n for (const item of nodes) {\r\n const node = { ...item, [childrenKey]: [] };\r\n map.set(item[idKey], node);\r\n }\r\n\r\n // 2. 建立父子关系\r\n for (const item of nodes) {\r\n const node = map.get(item[idKey]);\r\n const parentIdVal = item[parentKey];\r\n\r\n if (parentIdVal === parentId) {\r\n // 根层\r\n items.push(node);\r\n } else {\r\n // 非根层:找到父节点,把自己挂上去\r\n const parent = map.get(parentIdVal);\r\n if (parent) parent[childrenKey].push(node);\r\n // 如果 parent 不存在,说明数据不完整,可自定义处理\r\n }\r\n }\r\n\r\n return items;\r\n}\r\n\r\n/**\r\n * 在嵌套树中按 `id` 递归查找节点\r\n *\r\n * @template T extends Record<PropertyKey, any>\r\n * @param {string | number} id - 要查找的 id\r\n * @param {T[]} arr - 嵌套树森林\r\n * @param {string} [idKey='id'] - 主键字段\r\n * @param {string} [childrenKey='children'] - 子节点字段\r\n * @returns {T | undefined} 找到的节点;未找到返回 `undefined`\r\n */\r\nexport function findTreeNodeById(id, arr, idKey = \"id\", childrenKey = \"children\") {\r\n if (Array.isArray(arr) && arr.length > 0) {\r\n for (let i = 0; i < arr.length; i++) {\r\n const item = arr[i];\r\n if (item[idKey]?.toString() === id?.toString()) {\r\n return item;\r\n } else if (Array.isArray(item[childrenKey]) && item[childrenKey].length > 0) {\r\n const result = findTreeNodeById(id, item[childrenKey], idKey, childrenKey);\r\n if (result) {\r\n return result;\r\n }\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * 在嵌套树中按 `id` 递归查找节点,并返回其指定属性值。\r\n *\r\n * @template T extends Record<PropertyKey, any>\r\n * @param {string | number} id - 要查找的 id\r\n * @param {T[]} arr - 嵌套树森林\r\n * @param {string} [resultKey='name'] - 需要返回的字段\r\n * @param {string} [idKey='id'] - 主键字段\r\n * @param {string} [childrenKey='children'] - 子节点字段\r\n * @returns {any} 找到的值;未找到返回 `undefined`\r\n */\r\nexport function findObjAttrValueById(id, arr, resultKey = \"name\", idKey = \"id\", childrenKey = \"children\") {\r\n return findTreeNodeById(id, arr, idKey, childrenKey)?.[resultKey];\r\n}\r\n\r\n/**\r\n * 从服务端返回的已选 id 数组里,提取出\r\n * 1. 叶子节点\r\n * 2. 所有子节点都被选中的父节点\r\n * 其余父节点一律丢弃(由前端 Tree 自动算半选)\r\n *\r\n * @param {Array} treeData 完整树\r\n * @param {Array} selectedKeys 后端给的选中 id 数组\r\n * @param {String} idKey 节点唯一字段\r\n * @param {String} childrenKey 子节点字段\r\n * @returns {{checked: string[], halfChecked: string[]}}\r\n */\r\nexport function extractFullyCheckedKeys(treeData, selectedKeys, idKey = \"id\", childrenKey = \"children\") {\r\n const selectedSet = new Set(selectedKeys);\r\n const checked = new Set();\r\n const halfChecked = new Set();\r\n\r\n /* 返回值含义\r\n 0 - 未选中\r\n 1 - 半选\r\n 2 - 全选\r\n */\r\n function dfs(node) {\r\n const nodeId = node[idKey];\r\n const children = node[childrenKey] || [];\r\n\r\n // 叶子\r\n if (!children.length) {\r\n if (selectedSet.has(nodeId)) {\r\n checked.add(nodeId);\r\n return 2;\r\n }\r\n return 0;\r\n }\r\n\r\n // 非叶子\r\n let allChecked = true;\r\n let someChecked = false;\r\n\r\n children.forEach((child) => {\r\n const childState = dfs(child);\r\n if (childState !== 2) allChecked = false;\r\n if (childState >= 1) someChecked = true;\r\n });\r\n\r\n // 当前节点本身在 selectedKeys 里,但子节点未全选 → 只能算半选\r\n if (selectedSet.has(nodeId)) {\r\n if (allChecked) {\r\n checked.add(nodeId);\r\n return 2;\r\n }\r\n halfChecked.add(nodeId);\r\n return 1;\r\n }\r\n\r\n // 当前节点不在 selectedKeys 里,看子节点\r\n if (allChecked) {\r\n checked.add(nodeId);\r\n return 2;\r\n }\r\n if (someChecked) {\r\n halfChecked.add(nodeId);\r\n return 1;\r\n }\r\n return 0;\r\n }\r\n\r\n treeData.forEach(dfs);\r\n return {\r\n checked: [...checked],\r\n halfChecked: [...halfChecked]\r\n };\r\n}\r\n\r\n/**\r\n * 在树形结构中查找目标节点的完整路径(从根节点到目标节点,含目标节点自身)。\r\n *\r\n * @template T extends Record<PropertyKey, any>\r\n * @param {T[]} nodes - 树形结构森林(支持多根)\r\n * @param {any} targetValue - 目标节点的 key 值\r\n * @param {string} [key='id'] - 节点唯一标识字段\r\n * @param {string} [parentKey='pid'] - 父节点标识字段(指向父节点的 key 值)\r\n * @param {string} [childrenKey='children'] - 子节点数组字段\r\n * @returns {T[]} 从根到目标节点的路径数组;未找到返回空数组\r\n *\r\n * @example\r\n * const tree = [\r\n * { id: 1, pid: null, children: [\r\n * { id: 2, pid: 1, children: [\r\n * { id: 3, pid: 2 }\r\n * ]}\r\n * ]}\r\n * ];\r\n * findTreeNodePath(tree, 3); // [{id:1, ...}, {id:2, ...}, {id:3, ...}]\r\n */\r\nexport function findTreeNodePath(nodes, targetValue, key = \"id\", parentKey = \"pid\", childrenKey = \"children\") {\r\n if (!Array.isArray(nodes) || nodes.length === 0 || targetValue == null) {\r\n return [];\r\n }\r\n\r\n // 1. 建立节点索引\r\n const index = new Map();\r\n const stack = [...nodes];\r\n\r\n while (stack.length) {\r\n const node = stack.pop();\r\n if (!node || typeof node !== \"object\") continue;\r\n\r\n index.set(node[key], node);\r\n\r\n const children = node[childrenKey];\r\n if (Array.isArray(children)) {\r\n stack.push(...children);\r\n }\r\n }\r\n\r\n // 2. 回溯路径(防循环引用)\r\n const path = [];\r\n const visited = new Set();\r\n let cur = index.get(targetValue);\r\n\r\n while (cur && !visited.has(cur[key])) {\r\n visited.add(cur[key]);\r\n path.push(cur);\r\n\r\n const parentValue = cur[parentKey];\r\n cur = parentValue != null ? index.get(parentValue) : undefined;\r\n }\r\n\r\n return path.reverse();\r\n}\r\n"],"names":[],"mappings":"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"}
|
package/dist/tree.js
CHANGED
|
@@ -177,7 +177,65 @@ function extractFullyCheckedKeys(treeData, selectedKeys, idKey = "id", childrenK
|
|
|
177
177
|
checked: [...checked],
|
|
178
178
|
halfChecked: [...halfChecked]
|
|
179
179
|
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* 在树形结构中查找目标节点的完整路径(从根节点到目标节点,含目标节点自身)。
|
|
184
|
+
*
|
|
185
|
+
* @template T extends Record<PropertyKey, any>
|
|
186
|
+
* @param {T[]} nodes - 树形结构森林(支持多根)
|
|
187
|
+
* @param {any} targetValue - 目标节点的 key 值
|
|
188
|
+
* @param {string} [key='id'] - 节点唯一标识字段
|
|
189
|
+
* @param {string} [parentKey='pid'] - 父节点标识字段(指向父节点的 key 值)
|
|
190
|
+
* @param {string} [childrenKey='children'] - 子节点数组字段
|
|
191
|
+
* @returns {T[]} 从根到目标节点的路径数组;未找到返回空数组
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* const tree = [
|
|
195
|
+
* { id: 1, pid: null, children: [
|
|
196
|
+
* { id: 2, pid: 1, children: [
|
|
197
|
+
* { id: 3, pid: 2 }
|
|
198
|
+
* ]}
|
|
199
|
+
* ]}
|
|
200
|
+
* ];
|
|
201
|
+
* findTreeNodePath(tree, 3); // [{id:1, ...}, {id:2, ...}, {id:3, ...}]
|
|
202
|
+
*/
|
|
203
|
+
function findTreeNodePath(nodes, targetValue, key = "id", parentKey = "pid", childrenKey = "children") {
|
|
204
|
+
if (!Array.isArray(nodes) || nodes.length === 0 || targetValue == null) {
|
|
205
|
+
return [];
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// 1. 建立节点索引
|
|
209
|
+
const index = new Map();
|
|
210
|
+
const stack = [...nodes];
|
|
211
|
+
|
|
212
|
+
while (stack.length) {
|
|
213
|
+
const node = stack.pop();
|
|
214
|
+
if (!node || typeof node !== "object") continue;
|
|
215
|
+
|
|
216
|
+
index.set(node[key], node);
|
|
217
|
+
|
|
218
|
+
const children = node[childrenKey];
|
|
219
|
+
if (Array.isArray(children)) {
|
|
220
|
+
stack.push(...children);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// 2. 回溯路径(防循环引用)
|
|
225
|
+
const path = [];
|
|
226
|
+
const visited = new Set();
|
|
227
|
+
let cur = index.get(targetValue);
|
|
228
|
+
|
|
229
|
+
while (cur && !visited.has(cur[key])) {
|
|
230
|
+
visited.add(cur[key]);
|
|
231
|
+
path.push(cur);
|
|
232
|
+
|
|
233
|
+
const parentValue = cur[parentKey];
|
|
234
|
+
cur = parentValue != null ? index.get(parentValue) : undefined;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return path.reverse();
|
|
180
238
|
}
|
|
181
239
|
|
|
182
|
-
export { extractFullyCheckedKeys, findObjAttrValueById, findTreeNodeById, flatCompleteTree2NestedTree, nestedTree2IdMap };
|
|
240
|
+
export { extractFullyCheckedKeys, findObjAttrValueById, findTreeNodeById, findTreeNodePath, flatCompleteTree2NestedTree, nestedTree2IdMap };
|
|
183
241
|
//# sourceMappingURL=tree.js.map
|