// 引用 https://web.tianyunperfect.cn/simple/js/util.js function lt(obj) { console.table(JSON.parse(JSON.stringify(obj))); } /** * 深度克隆 * @param obj * @returns {any} */ function deepClone(obj) { return JSON.parse(JSON.stringify(obj)) } function debounce(fn, wait = 50) { // 通过闭包缓存一个定时器 id let timer = null // 将 debounce 处理结果当作函数返回 // 触发事件回调时执行这个返回函数 return function (...args) { // 如果已经设定过定时器就清空上一次的定时器 if (timer) clearTimeout(timer) // 开始设定一个新的定时器,定时器结束后执行传入的函数 fn timer = setTimeout(() => { fn.apply(this, args) }, wait) } } // 日期工具类 const dataUtil = { // 日期 -> 字符串:formatDate(date, 'yyyy-MM-dd hh:mm:ss'); formatDate: function (date, format) { const pad = (n) => (n < 10 ? '0' + n : n); const replacements = { 'yyyy': date.getFullYear(), 'MM': pad(date.getMonth() + 1), 'dd': pad(date.getDate()), 'hh': pad(date.getHours()), 'mm': pad(date.getMinutes()), 'ss': pad(date.getSeconds()), 'qq': Math.floor((date.getMonth() + 3) / 3), //季度 'SSS': pad(date.getMilliseconds(), 3) //毫秒 }; let result = format; for (const key in replacements) { result = result.replace(key, replacements[key]); } return result; }, // 日期字符串 -> 日期: parseDate("2022-10-30 16:13:49") parseDate: function (dateString) { const date = new Date(Date.parse(dateString)); return date; }, // 当前日期 getNowStr: function () { return this.formatDate(new Date(), 'yyyy-MM-dd hh:mm:ss'); }, } /** * 远程请求 * @type {{async: (function(*, *, *, *): Promise), xhr_send: request.xhr_send, sync: (function(*, *, *, *): any)}} */ const requestUtil = { xhr_send(xhr, method, headers, data) { if (headers) { for (const key in headers) { xhr.setRequestHeader(key, headers[key]); } } if (method.match(/^(POST|PUT)$/i)) { if (!headers || !headers.hasOwnProperty("Content-Type")) { xhr.setRequestHeader("Content-Type", "application/json"); } xhr.send(JSON.stringify(data)); } else { xhr.send(); } }, /** * 异步请求:requestUtil.async('https://jsonplaceholder.typicode.com/posts/1', 'GET', null, null) * .then(data => console.log(data)) * .catch(error => console.error(error)); */ async(url, method, data = {}, headers = {}) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open(method, url, true); this.xhr_send(xhr, method, headers, data); xhr.onload = () => { resolve(JSON.parse(xhr.responseText)); }; xhr.onerror = () => reject(xhr.statusText); }); }, /** * 拼接 url */ buildUrl(url, params) { const urlObj = new URL(url); // @ts-ignore for (const key in params) { urlObj.searchParams.set(key, params[key]); } return urlObj.toString(); }, /** * 同步请求 let a = request.sync("https://httpbin.tianyunperfect.cn/ip","GET",null,null) */ sync(url, method, data = {}, headers = {}) { const xhr = new XMLHttpRequest(); xhr.open(method, url, false); this.xhr_send(xhr, method, headers, data); return JSON.parse(xhr.responseText); }, }; /** * 休眠一段时间: await sleep(2000) * @param time * @returns {Promise} */ function sleep(time) { return new Promise((resolve) => setTimeout(resolve, time)); } /** * 根据选择器 选择某一个dom,10秒钟内 * @param sel * @returns {Promise<*>} */ async function getDom(sel) { for (let i = 0; i < 100; i++) { let dom = document.querySelector(sel); if (dom) { return dom; } else { await sleep(100); } } } /** * 根据选择器 选择所有dom,10秒钟内 * @param sel * @returns {Promise<*>} */ async function getDomAll(sel) { for (let i = 0; i < 100; i++) { let dom = document.querySelectorAll(sel); if (dom.length > 0) { return dom; } else { await sleep(100); } } } /** * 添加全局样式: addGlobalStyle('.box {height: 100px !important;}'); */ function addGlobalStyle(newStyle) { let styleElement = document.getElementById('styles_js'); if (!styleElement) { styleElement = document.createElement('style'); styleElement.type = 'text/css'; styleElement.id = 'styles_js'; document.getElementsByTagName('head')[0].appendChild(styleElement); } styleElement.appendChild(document.createTextNode(newStyle)); } /** * 获取 指定 name 的 url 参数 * @param url * @param name * @returns {string|string} */ function getQueryStringByUrl(url, name) { let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); let r = url.substring(url.indexOf('?') + 1).match(reg); //获取url中"?"符后的字符串并正则匹配 let context = ""; if (r != null) context = r[2]; reg = null; r = null; return context == null || context === "" || context === "undefined" ? "" : decodeURI(context); } /** * 获取 指定 name 的 url 参数 * @param name * @returns {string} */ function getQueryString(name) { return getQueryStringByUrl(location.href, name); } // 随机数 const randomUtil = { /** * 获取随机数 * @param min * @param max * @returns {number} */ getInt: function (min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min) + min); //The maximum is exclusive and the minimum is inclusive }, /** * 获取随机的一个值 * @param arr * @returns {*} */ getOneFromArray: function (arr) { return arr[this.getInt(0, arr.length)]; } } /** * 创建一个text样式的页面元素 * @param eleName * @param text * @param attrs * @returns {*} */ function createEle(eleName, text, attrs) { let ele = document.createElement(eleName); // innerText 也就是

text会被添加到这里

ele.innerText = text; // attrs 的类型是一个 map for (let k in attrs) { // 遍历 attrs, 给节点 ele 添加我们想要的属性 ele.setAttribute(k, attrs[k]); } // 返回节点 return ele; } /** * 自动关闭提示框 * @param str 提示文本 * @param sec 时间(秒) */ function showMsg(str, sec) { const borderColor = "#336699"; //提示窗口的边框颜色 const sWidth = document.body.offsetWidth; const sHeight = document.body.offsetHeight; //背景div const bgObj = document.createElement("div"); let alertBgDiv = 'alertBgDiv'; bgObj.setAttribute('id', alertBgDiv); bgObj.style.cssText = `position: fixed; top: 0; background: #E8E8E8; filter: progid:DXImageTransform.Microsoft.Alpha(style=3,opacity=25,finishOpacity=75; opacity: 0.6; left: 0; width: ${sWidth}px; height: ${sHeight}px; z-index: 10000`; document.body.appendChild(bgObj); //创建提示窗口的div const msgObj = document.createElement("div"); let alertMsgDiv = "alertMsgDiv"; msgObj.setAttribute("id", alertMsgDiv); msgObj.setAttribute("align", "center"); msgObj.style.cssText = `background: white; border: 1px solid ${borderColor}; position: fixed; left: 50%; font: 15px/1.6em Verdana, Geneva, Arial, Helvetica, sans-serif; margin-left: -225px; top: ${document.body.scrollTop + (window.screen.availHeight / 2) - 150}px; text-align: center; line-height: 25px; z-index: 10001; min-width: 300px`; document.body.appendChild(msgObj); //提示信息标题 const title = document.createElement("h4"); let alertMsgTitle = "alertMsgTitle"; title.setAttribute("id", alertMsgTitle); title.setAttribute("align", "left"); title.style.cssText = `margin:0; padding:3px; background:${borderColor}; filter:progid:DXImageTransform.Microsoft.Alpha(startX=20, startY=20, finishX=100, finishY=100,style=1,opacity=75,finishOpacity=100); opacity:0.75; border:1px solid ${borderColor}; font:12px Verdana, Geneva, Arial, Helvetica, sans-serif; color:white`; title.innerHTML = "提示信息"; document.getElementById(alertMsgDiv).appendChild(title); //提示信息 const txt = document.createElement("p"); txt.setAttribute("id", "msgTxt"); txt.style.margin = "16px 0"; txt.innerHTML = str; document.getElementById(alertMsgDiv).appendChild(txt); //设置关闭时间 window.setTimeout(() => { document.body.removeChild(document.getElementById(alertBgDiv)); document.getElementById(alertMsgDiv).removeChild(document.getElementById(alertMsgTitle)); document.body.removeChild(document.getElementById(alertMsgDiv)); }, sec * 1000); } /** * 打印信息 * @param obj */ function log(obj) { console.table(JSON.parse(JSON.stringify(obj))); } // 添加静态资源 const staticLoader = { /** * 添加js引用 : addRemoteJs("https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"); */ addRemoteJs: function (jsUrl) { if (document.querySelector(`script[src="${jsUrl}"]`)) { return; } const script = document.createElement('script'); script.src = jsUrl; script.type = 'text/javascript'; document.head.appendChild(script); }, addRemoteCss: function (cssUrl) { if (document.querySelector(`link[href="${cssUrl}"]`)) { return; } const link = document.createElement('link'); link.href = cssUrl; link.rel = 'stylesheet'; link.type = 'text/css'; document.head.appendChild(link); }, /** * 添加 Jq */ addJq: function () { const jqUrl = 'https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js'; this.addRemoteJs(jqUrl); } } // 复制文本工具类 const copyUtil = { /** * 复制,支持复制html: copyHtml('#wish_search_list .wish_s_item'); * @param css_selector * @returns {Promise} */ copyFromSelector: async function (css_selector) { const el = document.querySelector(css_selector); const html = el.outerHTML; await this.copyFromHtml(html); }, copyFromHtml: async function (html) { try { await navigator.clipboard.write([ new ClipboardItem({ 'text/html': new Blob([html], {type: 'text/html'}) }) ]); console.log('复制成功'); } catch (err) { console.error('复制失败', err); } }, copyText: async function (text) { if (navigator.clipboard) { // clipboard api 复制 await navigator.clipboard.writeText(text); } else { const textarea = document.createElement('textarea'); document.body.appendChild(textarea); // 隐藏此输入框 textarea.style.position = 'fixed'; textarea.style.clip = 'rect(0 0 0 0)'; textarea.style.top = '10px'; // 赋值 textarea.value = text; // 选中 textarea.select(); // 复制 document.execCommand('copy', true); // 移除输入框 document.body.removeChild(textarea); } }, getClipboardText: async function () { try { const text = await navigator.clipboard.readText(); console.log("剪贴板内容:", text); return text; } catch (err) { console.error("无法读取剪贴板内容:", err); } } } /** * base64图片转为webp格式 * @param base64Image * @returns {Promise} */ async function convertToWebPAsync(base64Image) { // 检查图像格式是否为WebP if (base64Image.startsWith('data:image/webp')) { // 如果是WebP格式,直接返回原始的base64字符串 return base64Image; } else { // 将图像转换为WebP格式 const image = new Image(); image.src = base64Image; await new Promise((resolve, reject) => { image.onload = resolve; image.onerror = reject; }); const canvas = document.createElement('canvas'); canvas.width = image.width; canvas.height = image.height; const ctx = canvas.getContext('2d'); ctx.drawImage(image, 0, 0); return canvas.toDataURL('image/webp'); } } function closeWindow() { const userAgent = navigator.userAgent; if (userAgent.indexOf("Firefox") !== -1 || userAgent.indexOf("Chrome") !== -1) { window.location.href = "about:blank"; window.close(); } else { window.opener = null; window.open("", "_self"); window.close(); } } function getTimeStamp() { const currentTimeStamp = Date.now(); const targetTimeStamp = new Date('2024-01-01').getTime(); return currentTimeStamp - targetTimeStamp; } /** 用于监控值的变化并执行相应的操作 * monitorAndAct(generateRandomValue, logValueChange); * * @param func1 入参:无 出参:值 generateRandomValue() * @param func2 入参:旧值、新值 出参:无 logValueChange(oldValue, newValue) */ function monitorAndAct(func1, func2) { let oldValue = func1(); function checkValue() { const newValue = func1(); if (newValue !== oldValue) { // 值已改变,执行func2并传入旧值和新值 func2(oldValue, newValue); // 更新旧值为新值 oldValue = newValue; } // 持续检查,这里假设每隔1秒检查一次 setTimeout(checkValue, 1000); } // 启动检查过程 checkValue(); } function showTextOnTopRight(text) { let id1 = "showTextOnTopRight"; // 删除之前的 let oldDiv = document.getElementById(id1); if (oldDiv) { document.body.removeChild(oldDiv); } // 在屏幕右上角显示一个文本 let div = document.createElement("div"); // 设置id div.id = id1; div.style.position = "fixed"; div.style.top = "8px"; div.style.right = "8px"; div.style.padding = "5px"; div.style.backgroundColor = "#fff"; div.style.border = "1px solid #ccc"; div.style.borderRadius = "5px"; div.style.zIndex = "9999"; // 字体大小 div.style.fontSize = "12px"; div.innerHTML = text; document.body.appendChild(div); } function showBusyText() { showTextOnTopRight("同步中..."); } function showDoneText() { showTextOnTopRight("✅"); } // dispatchEventClick('.btn') 触发点击事件 function dispatchEventClick(cssSelector) { let dom = document.querySelector(cssSelector); if (!dom) { console.log('dom is null'); return; } const event = new Event('click'); dom.dispatchEvent(event); }