UNPKG

mtfunit

Version:

Mtfunit is a tiny JavaScript library that includes useful functions to operate strings and DOM

248 lines (229 loc) 11.1 kB
/** * 获取指定的 querystring 中指定 name 的 value * @param {String} name 查询名 * @param {String} querystring 查询到的值 * @return {String|undefined} 查询到返回String,没有返回undefined */ function query (name, querystring) { if (name && name.match(/(?:http[s]?:|^)\/{2}.*?(?:\.)/)) name = encodeURIComponent(name) // 仅编码Url const r = (querystring + '').match(new RegExp('(?:^|&)\\s*?' + name + '\\s*=\\s*(.*?)\\s*(?:&|$)')) return r === null ? undefined : decodeURIComponent(r[1]) } /** * 序列化对象,把对象转成URL查询字符串 * @param {Object} data 对象 * @return {String} 返回查询字符串 */ function serialize (data) { let queryString = [] Object.keys(data || {}).forEach(key => typeof key === 'string' && queryString.push(encodeURIComponent(key) + '=' + encodeURIComponent(typeof data[key] === 'object' ? JSON.stringify(data[key]) : data[key]))) return queryString.join('&') } /** * 根据选择器查找 DOM * @param {String} selector 选择器名称,用法同CSS选择器 * @return {DOM|Null|Array} 群组选择器(含,)返回Array。其他选择器,找到返回第一个DOM,没有返回Null */ function $ (selector) { if (!selector) return null let selectorStr = (selector + '').replace(/,$/, '') , i = -1 try { const nComma = selectorStr.split(',').length, r = document.querySelectorAll(selectorStr), res = [] if (nComma > 1) { while (++i < nComma && r[i]) res[i] = r[i] return res } return r[0] || null } catch (e) { return null } } /** * 删除 DOM 节点 * @param {DOM|ArrayLike} node 要删除的节点或节点列表 * @return {DOM|ArrayLike} 返回值被删除的节点或节点列表,与传参 node 相同 */ function removeNode (node) { return (node && node.length ? Array.from(node) : [node]).map(node => node?.parentNode?.removeChild(node)), node } /** * 在 target 节点之后插入 node 节点 * @param {DOM|ArrayLike} node 要插入的节点或节点列表 * @param {DOM|Null} target 插入目标节点的后方,若目标节点不存在,则插入父节点的末尾 * @return {DOM|ArrayLike} 返回被插入的节点或节点列表,与传参 node 相同 */ function insertAfter (node, target) { if (!node || node.length === 0) return null let fragment = document.createDocumentFragment() if (node && node.length) for (let i = 0; i < node.length; i++) fragment.appendChild(node[i]) else fragment = node return (target?.parentNode || document.body).insertBefore(fragment, target?.nextSibling || null), node } /** * 添加类名 * @param {DOM|ArrayLike} node 要添加类名的节点或节点列表 * @param {String|Array} className 要添加的类名 * @return {DOM|ArrayLike} 返回添加类名的节点或节点列表,与传参 node 相同 */ function addClass (node, className) { return (node && node.length ? Array.from(node) : [node]).map(node => node?.classList.add(className)), node } /** * 移除类名 * @param {DOM|Array<Dom>} node 要移除类名的节点或节点列表 * @param {String|Array} className 要移除的类名 * @return {DOM|ArrayLike} 返回移除类名的节点或节点列表,与传参 node 相同 */ function removeClass (node, className) { return (node && node.length ? Array.from(node) : [node]).map(node => node?.classList.remove(className)), node } /** * 获取绝对路径 * @param {String} url // 相对路径 * @return {String} // 返回路径的值与浏览器处理相对路径相同 */ function getAbsoluteUrl (url) { if (!url) return location.href url += '' const { origin, pathname } = location const stack = pathname.replace(/^\/|\/$/g, '').split('/') for (let i = 0, w = ''; i <= url.length; i++) { const s = url[i] if (s === '/' || s === void 0) { if (w.substring(0, 2) === '..') { stack.pop() } else if (w !== '.') { i === 0 ? stack.length = 0 : stack.push(w) } w = '' } else w += s } return origin + '/' + stack.join('/') } /** * 防抖 * @param {Function} callback 回调函数 * @param {Number} time 延迟时间 * @return {Function} 防抖的函数 */ function debounce (callback, time) { let timer = null return function (...args) { if (timer) clearTimeout(timer) timer = setTimeout(() => { timer = null callback.apply(this, args) }, time + '' | 0 || 1000 / 60) } } /** * 节流 * @param {Function} callback 回调函数 * @param {Number} time 时间间隔 * @return {Function} 节流的函数 */ function throttle (callback, time) { let timer = null return function (...args) { if (timer) return timer = setTimeout(() => { timer = null callback.apply(this, args) }, time + '' | 0 || 1000 / 60) } } /** * 根据索引移出数组的某一项 * @param {Number} index 要删除的索引。正负和边界处理与Array.prototype.splice的第一参数相同 * @param {Array} arr 要操作的数组 * @return {Array} 返回操作后的数组 */ function removeItemByIndex (index, arr) { if (!arr || !arr.length || typeof index === 'bigint') return arr const n = arr.length index |= 0 if (index >= n) return arr if (index < 0) index = index <= -n ? 0 : index % n + n const r = Array(n - 1) for (let i = 0, j = 0; i < n; i++) if (i !== index) r[j++] = arr[i] return r } /** * 根据值移出数组的某一项 * @param {Number} index 要删除的值。严格相等匹配与Array.prototype.indexOf相同 * @param {Array} arr 要操作的数组 * @return {Array} 返回操作后的数组 */ function removeItemByValue (value, arr) { if (!arr || !arr.length) return arr const n = arr.length, r = [] for (let i = 0, j = 0; i < n; i++) if (arr[i] !== value) r[j++] = arr[i] return r } /** * JSON.stringify:保留对象中undefined、BigInt值和Function、Symbol结构 * @param {Object} obj JS对象 * @return {String} 返回序列化后的字符串 */ function stringifyJSON (obj) { const s = new Set(['undefined', 'bigint', 'function', 'symbol']) return JSON.stringify(obj, (_, v) => s.has(typeof v) ? String(v) : v) } /** * 富文本 → 纯文本 * @param {String} html 富文本字符串 * @return {String} 返回纯文本字符串 * ALL HTML TAG List Source:https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element */ function delHtmlTag (html) { const TAG = 'html|base|head|link|meta|style|title|body|address|article|aside|footer|header|h1|h2|h3|h4|h5|h6|hgroup|main|nav|section|blockquote|dd|dir|div|dl|dt|figcaption|figure|hr|li|main|ol|p|pre|ul|a|abbr|b|bdi|bdo|br|cite|code|data|dfn|em|i|kbd|mark|q|rb|rp|rt|rtc|ruby|s|samp|small|span|strong|sub|sup|time|tt|u|var|wbr|area|audio|img|map|track|video|applet|embed|iframe|noembed|object|param|picture|source|canvas|noscript|script|del|ins|caption|col|colgroup|table|tbody|td|tfoot|th|thead|tr|button|datalist|fieldset|form|input|label|legend|meter|optgroup|option|output|progress|select|textarea|details|dialog|menu|menuitem|summary|content|element|shadow|slot|template|acronym|applet|basefont|bgsound|big|blink|center|command|content|dir|element|font|frame|frameset|image|isindex|keygen|listing|marquee|menuitem|multicol|nextid|nobr|noembed|noframes|plaintext|shadow|spacer|strike|tt|xmp' return ((html || '') + '').replace(new RegExp('<\\/?(' + TAG + ')([\\s\\S]*?)>((?!<)>)*', 'ig'), '') } /** * 转义:HTML → HTMLEntites * @param {String} html 富文本字符串 * @return {String} 返回转义后的字符串,转换非ASCII编码字符 */ function htmlEncode (html) { const h = { "10": "<br/>", "32": "&nbsp;", "34": "&quot;", "38": "&amp;", "39": "&#x27;", "47": "&#x2F;", "60": "&lt;", "62": "&gt;", "162": "&cent;", "192": "&Agrave;", "193": "&Aacute;", "194": "&Acirc;", "195": "&Atilde;", "196": "&Auml;", "197": "&Aring;", "198": "&AElig;", "199": "&Ccedil;", "200": "&Egrave;", "201": "&Eacute;", "202": "&Ecirc;", "203": "&Euml;", "204": "&Igrave;", "205": "&Iacute;", "206": "&Icirc;", "207": "&Iuml;", "208": "&ETH;", "209": "&Ntilde;", "210": "&Ograve;", "211": "&Oacute;", "212": "&Ocirc;", "213": "&Otilde;", "214": "&Ouml;", "216": "&Oslash;", "217": "&Ugrave;", "218": "&Uacute;", "219": "&Ucirc;", "220": "&Uuml;", "221": "&Yacute;", "222": "&THORN;", "223": "&szlig;", "224": "&agrave;", "225": "&aacute;", "226": "&acirc;", "227": "&atilde;", "228": "&auml;", "229": "&aring;", "230": "&aelig;", "231": "&ccedil;", "232": "&egrave;", "233": "&eacute;", "234": "&ecirc;", "235": "&euml;", "236": "&igrave;", "237": "&iacute;", "238": "&icirc;", "239": "&iuml;", "240": "&eth;", "241": "&ntilde;", "242": "&ograve;", "243": "&oacute;", "244": "&ocirc;", "245": "&otilde;", "246": "&ouml;", "248": "&oslash;", "249": "&ugrave;", "250": "&uacute;", "251": "&ucirc;", "252": "&uuml;", "253": "&yacute;", "254": "&thorn;", "255": "&yuml;" } html = (html || '') + '' let r = '', t, i = -1 while (++i < html.length) r += h[t = html.charCodeAt(i)] || (t > 127 ? `&#x${t.toString(16).padStart(4, 0)};` : html[i]) return r } /** * 转义:JavaScript代码 → 字符串 * @param {String} js JavaScript代码 * @return {String} 返回转义后的字符串,转换非ASCII编码字符 */ function javaScriptEncode (js) { const h = { 8: '\\b', 9: '\\t', 10: '\\n', 12: '\\f', 13: '\\r', 34: '\\"', 38: '\\&', 39: '\\\'', 47: '\\x2f', 60: '\\x3c', 62: '\\x3e', 92: '\\\\' } const isW = t => t > 47 && t < 58 || t > 64 && t < 91 || t > 96 && t < 123 // 大小写字母 + 数字(不含_) js = (js || '') + '' let r = '', t, i = -1 while (++i < js.length) r += h[t = js.charCodeAt(i)] || (t > 127 ? `\\u${t.toString(16).padStart(4, 0)}` : isW(t) ? js[i] : `\\x${t.toString(16)}`) return r } /** * @param {String} referer 来源 * @param {Boolean} nullable 允许为空:默认允许 * @param {Array}} whiteList 白名单:域名 + 端口 白名单(不含http和https) */ function isRefererValid (referer, { nullable = true, whiteList = [] }) { const punycode = require('./punycode') return nullable && !referer || RegExp('^http[s]?://(' + whiteList.map(v => { let [ host, port ] = v.split(':') if (port === void 0) port = '(443|80)' else if (port === '*') port = '\\d+' host = punycode.ToASCII(host).replace(/\*+(?!$)/g, '\\w+').replace(/\*+$/, '') return host + ':' + port }).join('|') + ')(\\?|/|$)').test( referer.replace(/(?<=^http(s)?:\/\/[^:]*?)(\/|\?|$)/, (_, ssl, end) => ':' + (ssl ? 443 : 80) + end) ) } module.exports = { query, serialize, $, removeNode, insertAfter, addClass, removeClass, getAbsoluteUrl, debounce, throttle, removeItemByIndex, removeItemByValue, stringifyJSON, delHtmlTag, htmlEncode, javaScriptEncode, isRefererValid }