@mt-kit/utils
Version:
1,615 lines (1,496 loc) • 117 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["microUtil"] = factory();
else
root["microUtil"] = factory();
})(self, function() {
return /******/ (function() { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ([
/* 0 */,
/* 1 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ animationFrameThrottle; }
/* harmony export */ });
/**
* 创建一个使用 requestAnimationFrame 的函数节流(throttle)版本
*
* 函数节流的目的是限制一个函数在特定时间内的调用次数,以避免过于频繁的执行,以确保性能优化或更平滑的动画效果时
*
* @param fn
* @returns
*
* 使用场景:
*
* 1、滚动事件处理
* window.addEventListener('scroll', animationFrameThrottle(handleScroll));
*
* 2、窗口大小改变
* window.addEventListener('resize', animationFrameThrottle(handleResize));
*
* 3、动画效果
* const animatedFunction = animationFrameThrottle(updateAnimation);
*/
function animationFrameThrottle(fn) {
let locked = false;
return function (...args) {
if (locked) {
return undefined;
}
locked = true;
// window.requestAnimationFrame 用于在下一次浏览器重绘之前调用指定的函数
window.requestAnimationFrame(() => {
fn.apply(this, args);
locked = false;
});
return undefined;
};
}
/***/ }),
/* 2 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ imageBase64ToBlob; }
/* harmony export */ });
/**
* 将 base64 编码的图像数据转换为 Blob 对象
* @param base64Buf base64Buf 是包含 base64 编码的图像数据的字符串
* @returns 返回一个 Blob 对象,该对象表示解码后的图像数据
*/
function imageBase64ToBlob(base64Buf) {
const arr = base64Buf.split(",");
const [typeItem] = arr;
const [, mime] = typeItem.match(/:(.*?);/) || [
"", ""
];
const bstr = window.atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.codePointAt(n) || 0;
}
return new Blob([
u8arr
], {
type: mime
});
}
/***/ }),
/* 3 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ imageUrlToBase64; }
/* harmony export */ });
/**
* 将图像 URL 转换为 base64 编码的字符串
* @param url 是要转换的图像的 URL
* @param mineType 是可选参数,用于指定生成的 base64 字符串的 MIME 类型,默认为 image/png
* @returns 返回一个 Promise 对象,resolve 后的值是生成的 base64 编码的字符串
*/
function imageUrlToBase64(url, mineType) {
return new Promise((resolve, reject) => {
let canvas = document.createElement("CANVAS");
const ctx = canvas === null || canvas === void 0 ? void 0 : canvas.getContext("2d");
const img = new Image();
img.crossOrigin = "";
img.addEventListener("load", () => {
if (!canvas || !ctx) {
return reject(new Error("Canvas or context is not available"));
}
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img, 0, 0);
const dataUrl = canvas.toDataURL(mineType || "image/png");
canvas = null;
resolve(dataUrl);
});
img.src = url;
});
}
/***/ }),
/* 4 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ downloadByUrl; }
/* harmony export */ });
/* harmony import */ var _open_window__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5);
/**
* 根据文件地址进行下载
*
* Url 文件的地址
*
* target 链接的打开方式,默认为 '_blank'
*
* fileName 保存的文件名,如果不提供会从 URL 中提取
*
* isCORS 是否是 CORS 跨域请求,默认为 false
*/
function downloadByUrl({ url, target = "_blank", fileName, isCORS = false }) {
const isChrome = window.navigator.userAgent.toLowerCase().includes("chrome");
const isSafari = window.navigator.userAgent.toLowerCase().includes("safari");
if ((/iP/).test(window.navigator.userAgent)) {
console.error("Your browser does not support download!");
return false;
}
if (isChrome || isSafari) {
const link = document.createElement("a");
// 处理 CORS 跨域问题
if (isCORS) {
// 强制添加 response-content-disposition=attachment 参数下载文件
link.href = url.includes("?") ? `${url}&response-content-disposition=attachment` : `${url}?response-content-disposition=attachment`;
}
else {
link.href = url;
}
link.target = target;
if (link.download !== undefined) {
link.download = fileName || url.slice(url.lastIndexOf("/") + 1);
}
if (document.createEvent) {
const e = document.createEvent("MouseEvents");
e.initEvent("click", true, true);
link.dispatchEvent(e);
return true;
}
}
if (!url.includes("?")) {
url += "?download";
}
(0,_open_window__WEBPACK_IMPORTED_MODULE_0__["default"])(url, {
target
});
return true;
}
/***/ }),
/* 5 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ openWindow; }
/* harmony export */ });
/**
* 用于在浏览器中打开窗口
* @param {string} url 要打开的目标 URL
* @param {IOptions} opt
*/
function openWindow(url, opt) {
const { target = "__blank", noopener = true, noreferrer = true } = opt || {};
const feature = [];
noopener && feature.push("noopener=yes");
noreferrer && feature.push("noreferrer=yes");
window.open(url, target, feature.join(","));
}
/***/ }),
/* 6 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ downloadDataFile; }
/* harmony export */ });
/**
* 根据文件数据进行下载
* @param {*} data Blob 对象的 BlobPart 参数
* @param {*} filename 保存的文件名
* @param {*} mime 文件的 MIME 类型
* @param {*} bom Blob 对象的 BlobPart 参数
*/
function downloadDataFile(data, filename, mime, bom) {
const blobData = bom === undefined ? [
data
] : [
bom, data
];
const blob = new Blob(blobData, {
type: mime || "application/octet-stream"
});
const blobURL = window.URL.createObjectURL(blob);
const tempLink = document.createElement("a");
tempLink.style.display = "none";
tempLink.href = blobURL;
tempLink.setAttribute("download", filename);
if (tempLink.download === undefined) {
tempLink.setAttribute("target", "_blank");
}
document.body.append(tempLink);
tempLink.click();
tempLink.remove();
window.URL.revokeObjectURL(blobURL);
}
/***/ }),
/* 7 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ downloadBase64File; }
/* harmony export */ });
/* harmony import */ var _download_data_file__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
/* harmony import */ var _image_base64_to_blob__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
/**
* 根据 Base64 编码的字符串进行下载
* @param buf Base64 编码的字符串
* @param filename 保存的文件名
* @param mime 文件的 MIME 类型
* @param bom Blob 对象的 BlobPart 参数
*/
function downloadBase64File(buf, filename, mime, bom) {
const base64Buf = (0,_image_base64_to_blob__WEBPACK_IMPORTED_MODULE_1__["default"])(buf);
(0,_download_data_file__WEBPACK_IMPORTED_MODULE_0__["default"])(base64Buf, filename, mime, bom);
}
/***/ }),
/* 8 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ downloadUrlFile; }
/* harmony export */ });
/* harmony import */ var _download_base64_file__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7);
/* harmony import */ var _image_url_to_base64__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
/**
* 根据在线图片的 URL 进行下载
* @param url 在线图片的 URL
* @param filename 保存的文件名
* @param mime 文件的 MIME 类型
* @param bom Blob 对象的 BlobPart 参数
*/
function downloadUrlFile(url, filename, mime, bom) {
(0,_image_url_to_base64__WEBPACK_IMPORTED_MODULE_1__["default"])(url).then(base64 => {
(0,_download_base64_file__WEBPACK_IMPORTED_MODULE_0__["default"])(base64, filename, mime, bom);
});
}
/***/ }),
/* 9 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ copyText; }
/* harmony export */ });
/**
* 文本复制
*
* `navigator.clipboard` 可能因浏览器设置或浏览器兼容而造成兼容问题
*
* @param {string} text 要复制的文字
* @param {Function} promptFn 复制成功后的回调
*/
function copyText(text, promptFn) {
if (navigator.clipboard) {
return navigator.clipboard.
writeText(text).
then(() => {
promptFn && promptFn();
}).
catch(error => {
console.error(error);
return error;
});
}
if (Reflect.has(document, "execCommand")) {
return new Promise((resolve, reject) => {
const textArea = document.createElement("textarea");
textArea.value = text;
// 优化隐藏逻辑
textArea.style.opacity = "0";
textArea.style.position = "fixed";
textArea.style.top = "0";
textArea.style.left = "-9999px";
textArea.setAttribute("readonly", "readonly");
document.body.append(textArea);
try {
textArea.focus(); // 兼容移动端聚焦问题
textArea.select();
const success = document.execCommand("copy");
if (!success) {
throw new Error("execCommand('copy') 执行失败");
}
promptFn === null || promptFn === void 0 ? void 0 : promptFn();
}
catch (error) {
console.error(error);
reject(error);
}
finally {
textArea.remove(); // 确保清理
}
});
}
return Promise.reject(new Error("\"navigator.clipboard\" 或 \"document.execCommand\" 中存在API错误, 拷贝失败!"));
}
/***/ }),
/* 10 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ queryStringToObject; }
/* harmony export */ });
/**
* window.location.search 的值转换为 Object
* @param queryString window.location.search
* @returns {Record<string, string>} Object
*/
function queryStringToObject(queryString) {
const params = new URLSearchParams(queryString);
const result = {};
params.forEach((value, key) => {
result[key] = value;
});
return result;
}
/***/ }),
/* 11 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/**
* 封装 Cookie 操作的工具类
*
* 端口、协议不同,不影响 Cookie
*
*
*/
const cookieHelper = {
/**
* 设置 Cookie
* @param {string} name - Cookie 的名称
* @param {string} value - Cookie 的值
* @param {CookieOptions} options - Cookie 的选项
*/
setCookie(name, value, options) {
let cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
if (options === null || options === void 0 ? void 0 : options.expires) {
const expirationDate = new Date(Date.now() + options.expires * 1000);
cookieString += `; expires=${expirationDate.toUTCString()}`;
}
if (options === null || options === void 0 ? void 0 : options.domain) {
cookieString += `; domain=${options.domain}`;
}
if (options === null || options === void 0 ? void 0 : options.path) {
cookieString += `; path=${options.path}`;
}
if (options === null || options === void 0 ? void 0 : options.secure) {
cookieString += "; secure";
}
if (options === null || options === void 0 ? void 0 : options.sameSite) {
cookieString += `; samesite=${options.sameSite}`;
}
// eslint-disable-next-line unicorn/no-document-cookie
document.cookie = cookieString;
},
/**
* 获取 Cookie 的值
* @param {string} name - Cookie 的名称
* @returns {string|null} Cookie 的值,如果不存在则返回 null
*/
getCookie(name) {
const cookies = document.cookie.split("; ");
for (const cookie of cookies) {
const [cookieName, cookieValue] = cookie.split("=");
if (decodeURIComponent(cookieName) === name) {
return decodeURIComponent(cookieValue);
}
}
return null;
},
/**
* 删除 Cookie
* @param {string} name - Cookie 的名称
* @param {CookieOptions} options - Cookie 的路径(一版不需要)
*/
deleteCookie(name, options) {
if (!this.getCookie(name)) {
return;
}
// 设置过期时间为过去的时间来删除 Cookie
const deleteOptions = {
domain: options === null || options === void 0 ? void 0 : options.domain,
expires: -1,
path: options === null || options === void 0 ? void 0 : options.path,
sameSite: options === null || options === void 0 ? void 0 : options.sameSite,
secure: options === null || options === void 0 ? void 0 : options.secure
};
this.setCookie(name, "", deleteOptions);
}
};
/* harmony default export */ __webpack_exports__["default"] = (cookieHelper);
/*
* // 使用示例
* const cookieOptions: CookieOptions = {
* expires: 3600,
* domain: 'example.com',
* path: '/',
* secure: true,
* sameSite: 'None'
* };
*
* CookieHelper.setCookie('username', 'John Doe', cookieOptions);
* const username = CookieHelper.getCookie('username');
* console.log(username);
*
* CookieHelper.deleteCookie('username', cookieOptions);
*/
/***/ }),
/* 12 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/**
* localStorage 的一些扩展
*/
const localStorageHelper = {
// private static readonly storageKeyPrefix = 'test';
/**
* 设置 localStorage
*/
set({ key, value, expire }) {
if (key === "" || key === null || key === undefined) {
throw new Error("key 不能为空");
}
if (value === "" || value === null || value === undefined) {
throw new Error("value 不能为空");
}
localStorage.setItem(key, JSON.stringify({
value,
expire: expire ? Date.now() + expire * 24 * 60 * 60 * 1000 : null
}));
},
get(key) {
const storedItem = localStorage.getItem(key);
if (storedItem) {
const parsedItem = JSON.parse(storedItem);
if (parsedItem === null || parsedItem === void 0 ? void 0 : parsedItem.expire) {
const now = Date.now();
if (parsedItem.expire === Infinity || parsedItem.expire > now) {
return parsedItem.value;
}
localStorage.removeItem(key);
return null;
}
delete parsedItem.expire;
return parsedItem.value;
}
return null;
},
delete(key) {
localStorage.removeItem(key);
},
clear() {
localStorage.clear();
}
};
/* harmony default export */ __webpack_exports__["default"] = (localStorageHelper);
/***/ }),
/* 13 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ isElement; }
/* harmony export */ });
/**
* 是否为 DOM
* @param element 元素
* @return {element is Element}
*/
function isElement(element) {
return (element instanceof Element ||
element !== undefined &&
element !== null &&
typeof element === "object" &&
"nodeType" in element &&
typeof element.nodeType === "number" &&
"nodeName" in element &&
typeof element.nodeName === "string");
}
/***/ }),
/* 14 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ isEqual; }
/* harmony export */ });
/**
* 比较对象是否相等
* @param obj1
* @param obj2
* @returns boolean
*/
function isEqual(obj1, obj2, visited = new Set()) {
if (obj1 === obj2) {
return true;
}
if (typeof obj1 !== "object" ||
obj1 === null ||
typeof obj2 !== "object" ||
obj2 === null) {
return false;
}
if (visited.has(obj1) || visited.has(obj2)) {
return true;
}
visited.add(obj1);
visited.add(obj2);
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) {
visited.clear();
return false;
}
for (const key of keys1) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (!keys2.includes(key) || !isEqual(obj1[key], obj2[key], visited)) {
visited.clear();
return false;
}
}
visited.clear();
// 新增日期比较和数组顺序比较
if (obj1 instanceof Date && obj2 instanceof Date) {
return obj1.getTime() === obj2.getTime();
}
if (Array.isArray(obj1) && Array.isArray(obj2)) {
if (obj1.length !== obj2.length) {
return false;
}
for (const [i, element] of obj1.entries()) {
if (!isEqual(element, obj2[i], visited)) {
return false;
}
}
return true;
}
return true;
}
// // 测试
// const objA = { a: 1, b: { c: 2 } };
// const objB = { a: 1, b: { c: 2 } };
// const objC = { a: 1, b: { c: 3 } };
// console.log(isEqual(objA, objB)); // true
// console.log(isEqual(objA, objC)); // false
// // 循环引用测试
// const objD = { a: 1, b: { c: 2 } };
// objD.d = objD;
// const objE = { a: 1, b: { c: 2 } };
// objE.b.d = objE;
// console.log(isEqual(objD, objE)); // true
/***/ }),
/* 15 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ isFunction; }
/* harmony export */ });
/* eslint-disable @typescript-eslint/no-explicit-any */
/**
* 是否函数类型判断
* @param value
* @return {value is Function} 如果 value 为 function,则返回 true,否则返回 false
*/
function isFunction(value) {
return typeof value === "function";
}
/***/ }),
/* 16 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* eslint-disable @typescript-eslint/no-explicit-any */
/**
* 判断是否为 null
* @param value
* @returns boolean
*/
function isNull(value) {
return value == null;
}
/* harmony default export */ __webpack_exports__["default"] = (isNull);
/***/ }),
/* 17 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ isObject; }
/* harmony export */ });
/**
* 是否对象类型判断
*
* value is Record<string, any>
* 函数的返回类型是 value is Record<string, any>,这种形式的返回类型是 TypeScript 中用于表达类型守卫的一种方式。这意味着如果函数返回 true,TypeScript 将会把传入的参数视为 Record<string, any> 类型;如果返回 false,则参数不会被视为这个类型。
*
* @return 如果 value 为 object,则返回 true,否则返回 false
*/
function isObject(value) {
const type = typeof value;
return value !== null && (type === "object" || type === "function");
}
/***/ }),
/* 18 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ isUndefined; }
/* harmony export */ });
/**
* 是否为 undefined
* @param value value要检查的值
* @return {boolean} 如果 value 为 undefined,则返回 true,否则返回 false
*/
function isUndefined(value) {
return value === undefined;
}
/***/ }),
/* 19 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ clone; }
/* harmony export */ });
/**
* 浅拷贝
*/
function clone(value) {
/**
* 或:
* return Object.assign({}, value);
*/
return {
...value
};
}
/***/ }),
/* 20 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ cloneDeep; }
/* harmony export */ });
/* harmony import */ var _is_function__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(15);
/* harmony import */ var _is_object__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(17);
/* eslint-disable guard-for-in */
/* eslint-disable @typescript-eslint/no-empty-object-type */
/**
* 深拷贝
*
* @param value
* @param map 外部使用的时候,不需要传入
* @return value
*
* 对所有类型都进行了拷贝
*
* lodashjs、underscorejs 对函数、Symbol、Set、Map 等没做深拷贝处理
*
* 不建议使用:JSON.parse(JSON.stringify(value)); 它存在以下缺陷(案例见 ../stories/demo-clone-deep.html):
* ① 无法解析 Symbol 作为 key 或者 value
* ② 无法循环引用
*/
function cloneDeep(value, map = new WeakMap()) {
try {
// Set 类型
if (value instanceof Set) {
if (map.has(value)) {
return map.get(value);
}
const newSet = new Set();
map.set(value, newSet);
value.forEach(item => {
newSet.add(cloneDeep(item, map));
});
return newSet;
}
// Map 类型
if (value instanceof Map) {
if (map.has(value)) {
return map.get(value);
}
const newMap = new Map();
map.set(value, newMap);
value.forEach((val, key) => {
newMap.set(cloneDeep(key, map), cloneDeep(val, map));
});
return newMap;
}
// Symbol 类型
if (typeof value === "symbol") {
return Symbol(value.description);
}
// 函数类型
if ((0,_is_function__WEBPACK_IMPORTED_MODULE_0__["default"])(value)) {
return function (...args) {
return value.apply(this, args);
};
}
// 对象类型
if (!(0,_is_object__WEBPACK_IMPORTED_MODULE_1__["default"])(value)) {
return value;
}
// 判断 map 中是否有值,有了直接 return
if (map.has(value)) {
return map.get(value);
}
// 判断传入的对象是数组, 还是对象
const newValue = Array.isArray(value) ? [] : {};
// Map 没有值
map.set(value, newValue);
for (const key in value) {
newValue[key] = cloneDeep(value[key], map);
}
// Symbol 作为 key 的处理(这个可以不做 Symbol(sKey.description) 处理)
const symbolKeys = Object.getOwnPropertySymbols(value);
for (const sKey of symbolKeys) {
const newSKey = Symbol(sKey.description);
Object.defineProperty(newValue, newSKey, {
enumerable: true,
configurable: true,
writable: true,
value: cloneDeep(Reflect.get(value, sKey), map)
});
}
return newValue;
}
catch {
throw new Error("Deep clone handle error!");
}
}
/***/ }),
/* 21 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ debounce; }
/* harmony export */ });
/**
* 防抖
*
* 只有在某个时间内,没有再次触发某个函数时,才真正的调用这个函数
*
* 防抖的应用场景:
* ① 搜索框(确保不会每次输入都发送请求);
* ② 频繁的点击按钮,触发某个事件;
* ③ 监听浏览器滚动事件,完成某些特定操作;
* ④ 用户缩放浏览器的 resize 事件。
*
* @param {Function} func 执行的方法
* @param {number} wait 毫秒
* @param {boolean} immediate 立即执行(让其在第一次输入的时候,就给用户一个联想)
* @returns 返回一个函数,该函数返回一个 Promise,解析为执行的方法的返回值。另外,该函数还具有一个 cancel 方法,用于取消防抖
*/
function debounce(func, wait = 250, immediate = false) {
/**
* setTimeout 的返回类型是 number | NodeJS.Timeout。这是因为在 Node.js 环境中,setTimeout 返回的是一个 Timeout 对象,而在浏览器环境中,返回的是一个数字。
*/
let timer = null;
/**
* 控制在中间暂停的时候,接下来也能立即执行
*/
let isInvoke = false;
const _debounce = function (...args) {
/**
* 在外部获取 fn 中的返回值
*/
return new Promise((resolve, reject) => {
try {
if (timer) {
clearTimeout(timer);
}
if (immediate && !isInvoke) {
const result = func.apply(this, args);
isInvoke = true;
resolve(result);
return;
}
timer = setTimeout(() => {
/**
* 确保 this 指向的正确
*/
const result = func.apply(this, args);
isInvoke = false;
resolve(result);
}, wait);
}
catch (error) {
reject(error);
}
});
};
/**
* 取消功能:在触发的过程中,突然要取消
* 取消之后,重置所有变量
*/
_debounce.cancel = function () {
if (timer) {
clearTimeout(timer);
timer = null;
isInvoke = false;
}
};
return _debounce;
}
/*
// 简易版
let timer = null;
function debounce() {
if(timer!=null){
window.clearTimeout(myTimer);
}
//重新启动定时器
timer = setTimeout(()=>{
console.log("我是防抖");
timer =null;
},200);
}
// ts 类型定义解释:
//
// 通过泛型 T,你明确定义了 func 参数的类型,即一个函数,它接受任意参数并返回任意类型。
//
// 对于返回的函数,你使用了 Parameters<T> 获取 func 参数的类型,确保返回的函数接受与原始函数相同的参数。
//
// 使用 Promise<ReturnType<T>> 表示返回的函数返回一个 Promise,该 Promise 解析为原始函数的返回类型。
//
// 你使用了一个交叉类型 &,将返回的函数与具有 cancel 方法的对象类型组合在一起。这使得你的函数在使用时既能调用返回的函数,又能调用 cancel 方法。
*/
/***/ }),
/* 22 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ throttle; }
/* harmony export */ });
/**
* 节流
*
* ① 当事件触发时,会执行这个事件的响应函数,如果这个事件会被频繁触发,那么节流函数会按照一定的频率来执行函数
* ② 不管在这个中间有多少次触发这个事件,执行函数的频率总是固定的,不管在中间究竟点了几次
* ③ 他在初次是立即触发的
*
* 节流的应用场景:
* ① 监听页面的滚动事件;
* ② 鼠标移动事件;
* ③ 用户频繁点击按钮操作;
* ④ 按照固定的频率去触发时。
*
* @param {Function} func 执行的方法
* @param {number} wait 毫秒
* @param {IOptions} options
* @returns 返回一个函数,该函数返回一个 Promise,解析为执行的方法的返回值。另外,该函数还具有一个 cancel 方法,用于取消防抖
*
* 使用:
*
* const inputEl = document.querySelector("input");
*
* const onInput = function(event) {
* console.log(event);
* };
*
* const onInputThrottle = throttle(onInput, 3000);
*
* inputEl.oninput = onInputThrottle;
*/
const defaultOptions = {
leading: true,
trailing: false
};
function throttle(func, wait = 300, options = defaultOptions) {
const { leading, trailing } = options;
let lastTime = 0;
let timer = null;
/**
* 事件触发时真正执行的函数
*/
const _throttle = function (...args) {
return new Promise((resolve, reject) => {
try {
/**
* 获取最新的时间
* 当第一次执行完 lastTime = nowTime 时,wait - (nowTime - lastTime) 一定大于 0,这个时候是不执行的
*/
const nowTime = Date.now();
const remainTime = wait - (nowTime - lastTime);
if (lastTime === 0 && leading === false) {
lastTime = nowTime;
return;
}
if (remainTime <= 0) {
/**
* 只有在这重置了,才能开启下一个定时器
*/
if (timer) {
clearTimeout(timer);
timer = null;
}
const result = func.apply(this, args);
resolve(result);
lastTime = nowTime;
return;
}
if (trailing === true && remainTime > 0 && timer === null) {
timer = setTimeout(() => {
timer = null;
const result = func.apply(this, args);
/**
* 处理边界性问题
*/
lastTime = leading === true ? Date.now() : 0;
resolve(result);
}, remainTime);
}
}
catch (error) {
reject(error);
}
});
};
/**
* 取消节流
*/
_throttle.cancel = function () {
if (timer) {
clearTimeout(timer);
timer = null;
}
lastTime = 0;
};
return _throttle;
}
/*
// 简易版
let timer = null;
function throttle() {
if( timer !== null ){
return;
}
timer = setTimeout(()=>{
console.log("我是节流");
timer = null;
},200);
}
*/
/***/ }),
/* 23 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ queue; }
/* harmony export */ });
/**
* 消息队列
* 支持两种模式:
* 1. 串行模式:按顺序执行,一个完成后再执行下一个
* 2. 持续防抖模式:一段时间内有新请求就取消前面的,只保留最后一个,且只有在最后一次请求结束后的一段时间内没有新请求,才真正执行
*/
// 默认防抖时间(毫秒)
const DEFAULT_DEBOUNCE_TIME = 300;
// 存储各队列的待执行任务
const queues = new Map();
// 存储各队列正在执行的任务ID (用于取消正在执行的任务)
const runningTaskIds = new Map();
// 存储各队列的取消ID集合
const cancelledIds = new Map();
// 存储队列是否正在处理中
const processing = new Map();
// 存储防抖模式下的待执行任务 (key -> item)
const pendingDebounceItem = new Map();
/**
* 检查任务是否被取消
*/
const isCancelled = (key, id) => { var _a, _b; return (_b = (_a = cancelledIds.get(key)) === null || _a === void 0 ? void 0 : _a.has(id)) !== null && _b !== void 0 ? _b : false; };
/**
* 标记之前的任务为已取消
*/
const markPreviousAsCancelled = (key, currentId) => {
var _a, _b;
const cancelledSet = (_a = cancelledIds.get(key)) !== null && _a !== void 0 ? _a : new Set();
cancelledIds.set(key, cancelledSet);
// 1. 取消排队中的任务 (普通队列模式)
(_b = queues.get(key)) === null || _b === void 0 ? void 0 : _b.forEach(item => {
if (item.id !== currentId) {
cancelledSet.add(item.id);
}
});
// 2. 取消正在执行的任务
const runningId = runningTaskIds.get(key);
if (runningId && runningId !== currentId) {
cancelledSet.add(runningId);
}
// 3. 取消防抖等待中的任务
const pendingItem = pendingDebounceItem.get(key);
if (pendingItem && pendingItem.id !== currentId) {
cancelledSet.add(pendingItem.id);
if (pendingItem.timer) {
clearTimeout(pendingItem.timer);
}
// 立即 reject 旧任务
pendingItem.reject(new Error("任务已取消:新任务已到达"));
pendingDebounceItem.delete(key);
}
};
/**
* 清理已取消的任务ID(避免内存泄漏)
*/
const cleanupCancelledIds = (key) => {
const cancelledSet = cancelledIds.get(key);
if (!cancelledSet) {
return;
}
// 清理已不在队列中的取消ID
const queueList = queues.get(key);
const runningId = runningTaskIds.get(key);
const pendingItem = pendingDebounceItem.get(key);
const activeIds = new Set();
if (queueList) {
queueList.forEach(item => activeIds.add(item.id));
}
if (runningId) {
activeIds.add(runningId);
}
if (pendingItem) {
activeIds.add(pendingItem.id);
}
// 只保留活跃的取消ID,清理不再需要的
if (cancelledSet.size > activeIds.size * 2) {
// 如果取消集合太大,清理所有不在活跃列表中的ID
const toDelete = [];
cancelledSet.forEach(id => {
if (!activeIds.has(id)) {
toDelete.push(id);
}
});
toDelete.forEach(id => cancelledSet.delete(id));
}
};
/**
* 检查队列是否空闲,如果空闲则清理相关资源
*/
const checkAndCleanQueue = (key) => {
const queueList = queues.get(key);
const isQueueEmpty = !queueList || queueList.length === 0;
const isRunning = runningTaskIds.has(key);
const isPendingDebounce = pendingDebounceItem.has(key);
// 如果既没有排队的任务,也没有正在运行的任务,也没有正在防抖等待的任务,则清理资源
if (isQueueEmpty && !isRunning && !isPendingDebounce) {
queues.delete(key);
cancelledIds.delete(key);
processing.delete(key);
runningTaskIds.delete(key);
pendingDebounceItem.delete(key);
}
else {
// 队列还在使用中,清理已取消的ID避免内存泄漏
cleanupCancelledIds(key);
}
};
/**
* 处理普通队列
*/
const processQueue = async (key) => {
// 如果正在处理,直接返回
if (processing.get(key)) {
return;
}
const queueList = queues.get(key);
if (!queueList || queueList.length === 0) {
processing.set(key, false);
runningTaskIds.delete(key);
checkAndCleanQueue(key);
return;
}
// 开始处理队列
processing.set(key, true);
while (queueList.length > 0) {
const item = queueList.shift();
if (!item) {
break;
}
// 记录正在执行的任务ID
runningTaskIds.set(key, item.id);
// 检查是否被取消 (执行前)
if (isCancelled(key, item.id)) {
item.reject(new Error("任务已取消:前置任务已被取消"));
continue;
}
try {
// eslint-disable-next-line no-await-in-loop
const result = await item.task();
// 检查是否被取消 (执行后)
if (isCancelled(key, item.id)) {
item.reject(new Error("任务已取消"));
}
else {
item.resolve(result);
}
}
catch (error) {
// 检查是否被取消 (出错后)
if (!isCancelled(key, item.id)) {
item.reject(error);
}
// 如果被取消,静默忽略错误
}
}
// 处理完成,清理状态
runningTaskIds.delete(key);
processing.set(key, false);
checkAndCleanQueue(key);
};
/**
* 执行单个任务 (用于防抖模式)
*/
const executeTask = async (key, item) => {
var _a;
runningTaskIds.set(key, item.id);
if (isCancelled(key, item.id)) {
item.reject(new Error("任务已取消"));
runningTaskIds.delete(key);
checkAndCleanQueue(key);
return;
}
try {
const result = await item.task();
if (isCancelled(key, item.id)) {
item.reject(new Error("任务已取消"));
}
else {
item.resolve(result);
}
}
catch (error) {
if (!isCancelled(key, item.id)) {
item.reject(error);
}
}
finally {
runningTaskIds.delete(key);
// 执行完后清除 pending 记录 (虽然在开始执行前其实已经不在 pending 里了,但为了保险)
if (((_a = pendingDebounceItem.get(key)) === null || _a === void 0 ? void 0 : _a.id) === item.id) {
pendingDebounceItem.delete(key);
}
checkAndCleanQueue(key);
}
};
/**
* 队列请求方法
* @param fn 数据请求函数
* @param options 配置项 (包含 key, duration)
*/
function queue(fn, options) {
const { key = "default-queue", duration } = options !== null && options !== void 0 ? options : {};
// 参数验证
if (!key || typeof key !== "string") {
return Promise.reject(new Error("队列 key 必须是有效的字符串"));
}
if (typeof fn !== "function") {
return Promise.reject(new Error("任务必须是一个返回 Promise 的函数"));
}
return new Promise((resolve, reject) => {
var _a;
const id = Symbol(`${key}-${Date.now()}-${Math.random()}`);
// 确定是否启用防抖模式及时间
const isDebounceMode = typeof duration === "number" || duration === true;
let debounceTime = 0;
if (typeof duration === "number") {
// 验证防抖时间必须是非负数
if (duration < 0) {
reject(new Error("防抖时间不能为负数"));
return;
}
debounceTime = duration;
}
else if (duration === true) {
debounceTime = DEFAULT_DEBOUNCE_TIME;
}
// 初始化取消集合
if (!cancelledIds.has(key)) {
cancelledIds.set(key, new Set());
}
if (isDebounceMode) {
// 防抖模式:
// 1. 标记之前的任务为取消 (包括正在 pending 的和正在执行的)
markPreviousAsCancelled(key, id);
const item = {
id,
task: fn,
resolve,
reject
};
// 2. 设置定时器
item.timer = setTimeout(() => {
var _a;
// 定时器结束,执行任务
// 从 pending 中移除 (因为它即将开始执行)
if (((_a = pendingDebounceItem.get(key)) === null || _a === void 0 ? void 0 : _a.id) === id) {
pendingDebounceItem.delete(key);
executeTask(key, item);
}
}, debounceTime);
// 3. 存入 pending
// 类型兼容修正: 使 resolve 和 reject 适配 unknown
pendingDebounceItem.set(key, {
...item,
resolve: (value) => resolve(value),
reject
});
}
else {
// 普通串行模式
const queueList = (_a = queues.get(key)) !== null && _a !== void 0 ? _a : [];
if (!queues.has(key)) {
queues.set(key, queueList);
}
queueList.push({
id,
task: fn,
// 类型兼容修正: 使 resolve 和 reject 适配 unknown
resolve: (value) => resolve(value),
reject
});
processQueue(key);
}
});
}
/***/ }),
/* 24 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ omitBy; }
/* harmony export */ });
/* harmony import */ var _is_object__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(17);
/**
* 从创建的一个从对象中,排除满足某些条件的属性的属性
* @param obj 要处理的对象
* @param condition 用于判断是否排除属性的条件函数
* @returns 新的对象,排除了满足条件的属性
*/
function omitBy(obj, condition) {
const result = {};
if (!(0,_is_object__WEBPACK_IMPORTED_MODULE_0__["default"])(obj)) {
return result;
}
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
const value = obj[key];
if (!condition(value, key)) {
result[key] = value;
}
}
}
return result;
}
/*
// 示例
const sampleObject = {
a: 1,
b: 2,
c: 3,
d: 4,
};
// 从对象中排除值大于 2 的属性
const result = omitBy(sampleObject, (value) => value > 2);
console.log(result); // { a: 1, b: 2 }
*/
/***/ }),
/* 25 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ objectValueToString; }
/* harmony export */ });
/**
* obj 中所有 value 转换为 string
*/
function objectValueToString(query) {
return Object.fromEntries(Object.entries(query).map(([key, value]) => [
key, String(value)
]));
}
/***/ }),
/* 26 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
class IframeMessage {
constructor() {
this.iframe = null;
this.url = null;
// 页面卸载时自动移除 iframe
window.addEventListener("beforeunload", () => this.destroy());
}
createIframe(url) {
this.url = url;
this.iframe = document.createElement("iframe");
Object.assign(this.iframe.style, {
width: "1px",
height: "1px",
display: "none",
position: "absolute",
top: "0",
left: "0",
zIndex: "-1",
border: "none",
background: "transparent",
pointerEvents: "none",
opacity: "0",
visibility: "hidden"
});
this.iframe.src = url;
document.body.append(this.iframe);
return this.iframe;
}
postMessage(message) {
var _a;
if (this.iframe) {
(_a = this.iframe.contentWindow) === null || _a === void 0 ? void 0 : _a.postMessage(message, this.url || "*");
}
}
onMessage(callback) {
window.addEventListener("message", (event) => {
if (typeof event.data.type !== "string") {
return;
}
callback(event.data);
});
}
removeMessageListener(callback) {
window.removeEventListener("message", callback);
}
destroy() {
var _a;
if (this.iframe) {
(_a = this.iframe) === null || _a === void 0 ? void 0 : _a.remove();
this.iframe = null;
}
}
}
/* harmony default export */ __webpack_exports__["default"] = (IframeMessage);
/***/ }),
/* 27 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ flattenAndSort; }
/* harmony export */ });
/**
* 将对象扁平化为键值对并按键排序(确保确定性)
* @param obj 要扁平化的对象
* @param prefix 键前缀
* @returns 扁平化的对象
*/
function flattenAndSort(obj, prefix = "") {
const out = {};
for (const k of Object.keys(obj).sort()) {
const val = obj[k];
const key = prefix ? `${prefix}.${k}` : k;
if (val && typeof val === "object" && !Array.isArray(val)) {
Object.assign(out, flattenAndSort(val, key));
}
else {
out[key] = val === undefined || val === null ? "" : String(val);
}
}
return out;
}
/***/ }),
/* 28 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ sha256Base64; }
/* harmony export */ });
/* harmony import */ var _array_buffer_to_base64__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(29);
/**
* 🔑 将字符串转换为SHA-256哈希的Base64编码
* @param str 要哈希的字符串
* @returns Promise<string> Base64编码的哈希值
*/
async function sha256Base64(str) {
try {
const enc = new TextEncoder().encode(str);
const digest = await crypto.subtle.digest("SHA-256", enc);
return (0,_array_buffer_to_base64__WEBPACK_IMPORTED_MODULE_0__["default"])(digest);
}
catch (error) {
console.error("SHA-256 哈希失败:", error);
throw new Error("哈希生成失败");
}
}
/***/ }),
/* 29 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ arrayBufferToBase64; }
/* harmony export */ });
/**
* 将ArrayBuffer转换为Base64字符串
* @param buffer ArrayBuffer
* @returns Base64字符串,失败时返回空字符串
*/
function arrayBufferToBase64(buffer) {
try {
if (!buffer || !(buffer instanceof ArrayBuffer)) {
console.warn("提供的 ArrayBuffer 无效");
return "";
}
const bytes = new Uint8Array(buffer);
let binary = "";
// 使用String.fromCharCode,安全且高效
for (const byte of bytes) {
// eslint-disable-next-line unicorn/prefer-code-point
binary += String.fromCharCode(byte);
}
return btoa(binary);
}
catch (error) {
console.warn("Base64 编码失败:", error);
return "";
}
}
/***/ }),
/* 30 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ deviceAll: function() { return /* reexport safe */ _all__WEBPACK_IMPORTED_MODULE_14__["default"]; },
/* harmony export */ deviceBrowser: function() { return /* reexport safe */ _browser__WEBPACK_IMPORTED_MODULE_1__["default"]; },
/* harmony export */ deviceCpuCores: function() { return /* reexport safe */ _cpu_cores__WEBPACK_IMPORTED_MODULE_7__["default"]; },
/* harmony export */ deviceFeatures: function() { return /* reexport safe */ _features__WEBPACK_IMPORTED_MODULE_10__["default"]; },
/* harmony export */ deviceHardwareConcurrency: function() { return /* reexport safe */ _hardware_concurrency__WEBPACK_IMPORTED_MODULE_9__["default"]; },
/* harmony export */ deviceI18n: function() { return /* reexport safe */ _i18n__WEBPACK_IMPORTED_MODULE_12__["default"]; },
/* harmony export */ deviceLanguage: function() { return /* reexport safe */ _language__WEBPACK_IMPORTED_MODULE_2__["default"]; },
/* harmony export */ deviceLocation: function() { return /* reexport safe */ _location__WEBPACK_IMPORTED_MODULE_5__["default"]; },
/* harmony export */ deviceMemory: function() { return /* reexport safe */ _memory__WEBPACK_IMPORTED_MODULE_8__["default"]; },
/* harmony export */ deviceOnLine: function() { return /* reexport safe */ _onLine__WEBPACK_IMPORTED_MODULE_3__["default"]; },
/* harmony export */ deviceOperatingSystem: function() { return /* reexport safe */ _operating_system__WEBPACK_IMPORTED_MODULE_0__["default"]; },
/* harmony export */ devicePublicIp: function() { return /* reexport safe */ _public_ip__WEBPACK_IMPORTED_MODULE_6__["default"]; },
/* harmony export */ deviceScreen: function() { return /* reexport safe */ _screen__WEBPACK_IMPORTED_MODULE_4__["default"]; },
/* harmony export */ deviceSensor: function() { return /* reexport safe */ _sensor__WEBPACK_IMPORTED_MODULE_11__["default"]; },
/* harmony export */ deviceUa: function() { return /* reexport safe */ _ua__WEBPACK_IMPORTED_MODULE_13__["default"]; }
/* harmony export */ });
/* harmony import */ var _operating_system__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(31);
/* harmony import */ var _browser__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(33);
/* harmony import */ var _language__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(34);
/* harmony import */ var _onLine__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(35);
/* harmony import */ var _screen__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(36);
/* harmony import */ var _location__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(37);
/* harmony import */ var _public_ip__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(38);
/* harmony import */ var _cpu_cores__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(39);
/* harmony import */ var _memory__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(40);
/* harmony import */ var _hardware_concurrency__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(41);
/* harmony import */ var _features__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(42);
/* harmony import */ var _sensor__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(43);
/* harmony import */ var _i18n__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(44);
/* harmony import */ var _ua__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(45);
/* harmony import */ var _all__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(46);
/**
* 只要修改了 device 文件夹下的文件,都需要在这里导出,然后如果改变了结构等,需要发布一个新 Y 版本
*/
/***/ }),
/* 31 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ deviceOperatingSystem; }
/* harmony export */ });
/* harmony import */ var _enum__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(32