a2bei4-utils 1.0.7 → 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 +165 -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 +164 -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 +165 -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/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":"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,CAAC;AACD;AACA;AACA;AACA;AACA;AACY,MAAC,gBAAgB,GAAG;AAChC;AACA;AACA;AACA;AACA;AACA,IAAI,iBAAiB,EAAE,CAAC,OAAO,KAAK;AACpC,QAAQ,IAAI,CAAC,OAAO,EAAE;AACtB,YAAY,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;AAC1C,YAAY,OAAO;AACnB,QAAQ,CAAC;AACT,QAAQ,IAAI,OAAO,CAAC,iBAAiB,EAAE;AACvC,YAAY,OAAO,OAAO,CAAC,iBAAiB,EAAE,CAAC;AAC/C,QAAQ,CAAC,MAAM,IAAI,OAAO,CAAC,oBAAoB,EAAE;AACjD,YAAY,OAAO,OAAO,CAAC,oBAAoB,EAAE,CAAC;AAClD,QAAQ,CAAC,MAAM,IAAI,OAAO,CAAC,uBAAuB,EAAE;AACpD,YAAY,OAAO,OAAO,CAAC,uBAAuB,EAAE,CAAC;AACrD,QAAQ,CAAC,MAAM,IAAI,OAAO,CAAC,mBAAmB,EAAE;AAChD,YAAY,OAAO,OAAO,CAAC,mBAAmB,EAAE,CAAC;AACjD,QAAQ,CAAC,MAAM;AACf,YAAY,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;AAC3C,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA;AACA;AACA;AACA,IAAI,cAAc,EAAE,MAAM;AAC1B,QAAQ,IAAI,QAAQ,CAAC,cAAc,EAAE;AACrC,YAAY,OAAO,QAAQ,CAAC,cAAc,EAAE,CAAC;AAC7C,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,mBAAmB,EAAE;AACjD,YAAY,OAAO,QAAQ,CAAC,mBAAmB,EAAE,CAAC;AAClD,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,oBAAoB,EAAE;AAClD,YAAY,OAAO,QAAQ,CAAC,oBAAoB,EAAE,CAAC;AACnD,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,gBAAgB,EAAE;AAC9C,YAAY,OAAO,QAAQ,CAAC,gBAAgB,EAAE,CAAC;AAC/C,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA;AACA;AACA;AACA,IAAI,oBAAoB,EAAE,MAAM;AAChC,QAAQ,OAAO,QAAQ,CAAC,iBAAiB,IAAI,QAAQ,CAAC,oBAAoB,IAAI,QAAQ,CAAC,uBAAuB,IAAI,QAAQ,CAAC,mBAAmB,IAAI,IAAI,CAAC;AACvJ,IAAI,CAAC;AACL;AACA;AACA;AACA;AACA;AACA,IAAI,YAAY,EAAE,MAAM;AACxB,QAAQ,OAAO,CAAC,EAAE,QAAQ,CAAC,iBAAiB,IAAI,QAAQ,CAAC,oBAAoB,IAAI,QAAQ,CAAC,uBAAuB,IAAI,QAAQ,CAAC,mBAAmB,CAAC,CAAC;AACnJ,IAAI,CAAC;AACL;AACA;AACA;AACA;AACA;AACA,IAAI,mBAAmB,EAAE,MAAM;AAC/B,QAAQ,OAAO,CAAC,EAAE,QAAQ,CAAC,iBAAiB,IAAI,QAAQ,CAAC,oBAAoB,IAAI,QAAQ,CAAC,uBAAuB,IAAI,QAAQ,CAAC,mBAAmB,CAAC,CAAC;AACnJ,IAAI,CAAC;AACL;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,gBAAgB,EAAE,CAAC,OAAO,KAAK;AACnC,QAAQ,IAAI,gBAAgB,CAAC,YAAY,EAAE,EAAE;AAC7C,YAAY,OAAO,gBAAgB,CAAC,cAAc,EAAE,CAAC;AACrD,QAAQ,CAAC,MAAM;AACf,YAAY,OAAO,gBAAgB,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;AAC/D,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,kBAAkB,EAAE,CAAC,QAAQ,KAAK;AACtC,QAAQ,MAAM,OAAO,GAAG,MAAM;AAC9B,YAAY,QAAQ,CAAC,gBAAgB,CAAC,YAAY,EAAE,CAAC,CAAC;AACtD,QAAQ,CAAC,CAAC;AACV,QAAQ,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC;AAC/D,QAAQ,QAAQ,CAAC,gBAAgB,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;AACrE,QAAQ,QAAQ,CAAC,gBAAgB,CAAC,qBAAqB,EAAE,OAAO,CAAC,CAAC;AAClE,QAAQ,QAAQ,CAAC,gBAAgB,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC;AACjE;AACA,QAAQ,OAAO,MAAM;AACrB,YAAY,QAAQ,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC;AACtE,YAAY,QAAQ,CAAC,mBAAmB,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;AAC5E,YAAY,QAAQ,CAAC,mBAAmB,CAAC,qBAAqB,EAAE,OAAO,CAAC,CAAC;AACzE,YAAY,QAAQ,CAAC,mBAAmB,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC;AACxE,QAAQ,CAAC,CAAC;AACV,IAAI,CAAC;AACL;;;;"}
|
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
|
package/dist/tree.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree.js","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.js","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/package.json
CHANGED
package/types/browser.d.ts
CHANGED
|
@@ -33,6 +33,15 @@ declare function getAllSearchParams(): Record<string, string>;
|
|
|
33
33
|
* @returns {string | undefined} 对应参数值;不存在时返回 `undefined`
|
|
34
34
|
*/
|
|
35
35
|
declare function getSearchParam(key: string): string | undefined;
|
|
36
|
+
declare namespace fullscreenHelper {
|
|
37
|
+
function requestFullscreen(element: Element): Promise<void> | undefined;
|
|
38
|
+
function exitFullscreen(): Promise<void> | undefined;
|
|
39
|
+
function getFullscreenElement(): Element | null;
|
|
40
|
+
function isFullscreen(): boolean;
|
|
41
|
+
function isFullscreenEnabled(): boolean;
|
|
42
|
+
function toggleFullscreen(element: Element): Promise<void> | undefined;
|
|
43
|
+
function onFullscreenChange(callback: Function): Function;
|
|
44
|
+
}
|
|
36
45
|
/**
|
|
37
46
|
* 视口尺寸对象。
|
|
38
47
|
*/
|
|
@@ -47,5 +56,5 @@ type ViewportDimensions = {
|
|
|
47
56
|
h: number;
|
|
48
57
|
};
|
|
49
58
|
|
|
50
|
-
export { getAllSearchParams, getSearchParam, getViewportSize };
|
|
59
|
+
export { fullscreenHelper, getAllSearchParams, getSearchParam, getViewportSize };
|
|
51
60
|
export type { ViewportDimensions };
|
package/types/index.d.ts
CHANGED
|
@@ -321,6 +321,15 @@ declare function getAllSearchParams(): Record<string, string>;
|
|
|
321
321
|
* @returns {string | undefined} 对应参数值;不存在时返回 `undefined`
|
|
322
322
|
*/
|
|
323
323
|
declare function getSearchParam(key: string): string | undefined;
|
|
324
|
+
declare namespace fullscreenHelper {
|
|
325
|
+
function requestFullscreen(element: Element): Promise<void> | undefined;
|
|
326
|
+
function exitFullscreen(): Promise<void> | undefined;
|
|
327
|
+
function getFullscreenElement(): Element | null;
|
|
328
|
+
function isFullscreen(): boolean;
|
|
329
|
+
function isFullscreenEnabled(): boolean;
|
|
330
|
+
function toggleFullscreen(element: Element): Promise<void> | undefined;
|
|
331
|
+
function onFullscreenChange(callback: Function): Function;
|
|
332
|
+
}
|
|
324
333
|
/**
|
|
325
334
|
* 视口尺寸对象。
|
|
326
335
|
*/
|
|
@@ -981,5 +990,27 @@ declare function extractFullyCheckedKeys(treeData: any[], selectedKeys: any[], i
|
|
|
981
990
|
checked: string[];
|
|
982
991
|
halfChecked: string[];
|
|
983
992
|
};
|
|
993
|
+
/**
|
|
994
|
+
* 在树形结构中查找目标节点的完整路径(从根节点到目标节点,含目标节点自身)。
|
|
995
|
+
*
|
|
996
|
+
* @template T extends Record<PropertyKey, any>
|
|
997
|
+
* @param {T[]} nodes - 树形结构森林(支持多根)
|
|
998
|
+
* @param {any} targetValue - 目标节点的 key 值
|
|
999
|
+
* @param {string} [key='id'] - 节点唯一标识字段
|
|
1000
|
+
* @param {string} [parentKey='pid'] - 父节点标识字段(指向父节点的 key 值)
|
|
1001
|
+
* @param {string} [childrenKey='children'] - 子节点数组字段
|
|
1002
|
+
* @returns {T[]} 从根到目标节点的路径数组;未找到返回空数组
|
|
1003
|
+
*
|
|
1004
|
+
* @example
|
|
1005
|
+
* const tree = [
|
|
1006
|
+
* { id: 1, pid: null, children: [
|
|
1007
|
+
* { id: 2, pid: 1, children: [
|
|
1008
|
+
* { id: 3, pid: 2 }
|
|
1009
|
+
* ]}
|
|
1010
|
+
* ]}
|
|
1011
|
+
* ];
|
|
1012
|
+
* findTreeNodePath(tree, 3); // [{id:1, ...}, {id:2, ...}, {id:3, ...}]
|
|
1013
|
+
*/
|
|
1014
|
+
declare function findTreeNodePath<T>(nodes: T[], targetValue: any, key?: string, parentKey?: string, childrenKey?: string): T[];
|
|
984
1015
|
|
|
985
|
-
export { AudioStreamResampler, IntervalTimer, MyEvent, MyEvent_CrossPagePlugin, MyId, WebSocketManager, assignExisting, debounce, deepCloneByJSON, downloadByBlob, downloadByData, downloadByUrl, downloadExcel, downloadJSON, extractFullyCheckedKeys, fetchOrDownloadByUrl, findObjAttrValueById, findTreeNodeById, flatCompleteTree2NestedTree, formatTimeForLocale, getAllSearchParams, getDataType, getFunctionArgNames, getGUID, getSearchParam, getTimePeriodName, getViewportSize, handleDbMenuItems, isBlob, isDate, isFunction, isNonEmptyString, isPlainObject, isPromise, millisecond2Duration, millisecond2DurationMaxDay, millisecond2DurationMaxHour, moveItem, nestedTree2IdMap, pcmToWavBlob, randomDateInRange, randomEnLetter, randomHan, randomHanOrEn, randomIntInRange, readBlobAsText, second2Duration, second2DurationMaxDay, second2DurationMaxHour, shuffle, throttle, toDate };
|
|
1016
|
+
export { AudioStreamResampler, IntervalTimer, MyEvent, MyEvent_CrossPagePlugin, MyId, WebSocketManager, assignExisting, debounce, deepCloneByJSON, downloadByBlob, downloadByData, downloadByUrl, downloadExcel, downloadJSON, extractFullyCheckedKeys, fetchOrDownloadByUrl, findObjAttrValueById, findTreeNodeById, findTreeNodePath, flatCompleteTree2NestedTree, formatTimeForLocale, fullscreenHelper, getAllSearchParams, getDataType, getFunctionArgNames, getGUID, getSearchParam, getTimePeriodName, getViewportSize, handleDbMenuItems, isBlob, isDate, isFunction, isNonEmptyString, isPlainObject, isPromise, millisecond2Duration, millisecond2DurationMaxDay, millisecond2DurationMaxHour, moveItem, nestedTree2IdMap, pcmToWavBlob, randomDateInRange, randomEnLetter, randomHan, randomHanOrEn, randomIntInRange, readBlobAsText, second2Duration, second2DurationMaxDay, second2DurationMaxHour, shuffle, throttle, toDate };
|