import { isJson } from './is.js';
/**
* @module index
* @author linjielinlin 993353454@qq.com
* @date 2022-05-11 22:07:43
* @description 公共函数,使用'lj-utils'引入
*/
let isOnline = true;
let ENV = {};
let DATA_OBJECT = {};
// 断网监听
if (globalThis && globalThis.addEventListener) {
// #ifdef H5
globalThis.addEventListener('offline', function () {
console.debug('offLine');
isOnline = false;
});
globalThis.addEventListener('online', function () {
console.debug('onLine');
isOnline = true;
});
// #endif
}
/**
* @function
* @description 获取当前网络状态(H5)
* @return boolean
* @returns {boolean}
* @example
* ```
* const status = getNetworkStatus();
* ```
*/
const getNetworkStatus = () => {
return isOnline;
};
/**
* @function
* @description 正则收集
* @returns {object}
* @returns {object}
* @example
* ```
* const regex = getRegexp();
* ```
*/
const getRegexp = () => {
return {
// 匹配html标签,提取html文字: htmlCode.replace(reg.html,'')
html: /<[^>]+>/gim,
// 至少1数字1字母1字符,8-16位
password: /^(?=.*?[A-Za-z])(?=.*?[0-9])(?=.*?[\W_]).{8,16}$/,
// 普通身份证号正则,isIdCard更为严格
idCard: /^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$/,
// 简易身份证号 数字+x
idCardNormal: /^[0-9]\d+([0-9]|X|x)*$/,
// 手机号
phone: /^1\d{10}$/,
// 邮箱
email: /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/,
// 网址
http: /http:\/\/|https:\/\//,
// 含0整数(得分)
score: /^[1-9]\d*|0$/,
// 整数
int: /^[1-9]\d*$/,
// 匹配数字
number: /^\d*$/,
// >=0||1位小数
float1: /^(([1-9]\d*)|0|(0.\d{0,1})|([1-9]\d*.\d{0,1}))$/,
// >=0||2位小数
float2: /^(([1-9]\d*)|0|(0.\d{0,2})|([1-9]\d*.\d{0,2}))$/,
// >=0||3位小数
float3: /^(([1-9]\d*)|0|(0.\d{0,3})|([1-9]\d*.\d{0,3}))$/,
// 字母+数字组合
letterNumber: /^[a-zA-Z0-9]*$/,
// 字母
letter: /^[a-zA-Z]*$/,
// 帐号50个字内:大小写+数字+中文+'_'+'-'
account: /^[a-zA-Z0-9_\-\u4e00-\u9fa5]{1,50}$/,
// 中英文姓名 50个字内/中文 中文/英文-. 英文-./
realName: /^([\u4e00-\u9fa5]{1,50}|[\u4e00-\u9fa5]{1,25}[\s][\u4e00-\u9fa5]{1,24}|[a-zA-Z_\-.]{1,50}|[a-zA-Z_\-.]{1,25}[\s][a-zA-Z_\-.]{1,24})$/,
// 匹配中文
cn: /^[\u4e00-\u9fa5]*$/,
// 匹配ASCII,非中文之外的字符(全角字符)
ascii: /^[\x20-\x7E]+$/,
};
};
/**
* @function
* @description 设置标题
* @param {string} argTitle 标题
*/
const setTitle = (argTitle) => {
if (typeof globalThis.document === 'object') {
globalThis.document.title = String(argTitle);
}
if (getInfo().isAppleMobile) {
const i = document.createElement('iframe');
i.onload = () => {
setTimeout(() => {
console.debug('apple mobile setting title');
i.remove();
}, 10);
};
globalThis.document.body.appendChild(i);
}
};
/**
* @function
* @description 使用postcss-px2rem时使用
* @param {number} argBaseSize 基础大小 16px(要跟配置一致)
* @param {number} argWidth 基准宽度
*/
const remInit = (argBaseSize = 16, argWidth = 375) => {
// 设置 rem 函数
const setRem = () => {
// 当前页面宽度相对于 argWidth 宽的缩放比例,可根据自己需要修改。
const scale = safeData(globalThis, 'document.documentElement.clientWidth', argWidth) /
argWidth;
// 设置页面根节点字体大小
safeData(globalThis, 'document.documentElement.style.fontSize', argBaseSize * scale + 'px', true);
};
// 初始化
setRem();
// 改变窗口大小时重新设置 rem
globalThis.onresize = () => {
setRem();
};
};
/**
* @function
* @description 获取cookie
* @param {string} argName 要获取的值
* @returns {string}
*/
const getCookie = (argName) => {
const cookies = globalThis.document.cookie.split('; ');
const cookie = cookies.find((cookie) => {
const [name] = cookie.split('=');
return argName === name;
});
return cookie ? decodeURIComponent(cookie.split('=')[1] || '') : '';
};
/**
* @function
* @description 获取cookie对象
* @returns {object}
*/
const getCookieObj = () => {
const cookies = globalThis.document.cookie.split('; ');
const cookieObj = {};
cookies.forEach((cookie) => {
const [key, value = ''] = cookie.split('=');
cookieObj[key] = decodeURIComponent(value);
});
return cookieObj;
};
/**
* @function
* @description 设置cookie
* @param {string} argName 要设置的key
* @param {string} argValue 要设置的value
* @param {number} argTime 过期时间/时 默认24
* @param {number} argPath path
* @param {number} domain domain
*/
const setCookie = (argName, argValue = '', argTime = 24, argPath = '/', domain = globalThis.location.hostname) => {
if (argTime === 0) {
globalThis.document.cookie = `${argName}=${encodeURIComponent(argValue)};path=${argPath};domain=${domain};`;
}
else {
const now = new Date();
const offset = 8;
const utc = now.getTime() + now.getTimezoneOffset() * 60000;
const nd = utc + 3600000 * offset;
const exp = new Date(nd);
exp.setTime(exp.getTime() + argTime * 60 * 60 * 1000);
globalThis.document.cookie = `${argName}=${encodeURIComponent(argValue)};path=${argPath};expires=${exp.toUTCString()};domain=${domain};`;
}
};
/**
* @function
* @description 清除cookie
* @param {string} argName 要清除的值
*/
const delCookie = (argName = '') => {
setCookie(argName, '', -1);
};
/**
* @function
* @description 检测浏览器状态,系统状态 *
* @returns {Info} {
* ua: ua,
* platform: 平台,
* isMobile: 移动端,
* isWin: winPC端,
* isIphone: iphone,
* isIpad: ipad,
* isMac: mac,
* isAppleMobile: 苹果移动端webview
* isSafari: Safari浏览器,
* isIos: Ios平台,
* isAndroid: android平台,
* isIE: 显示8 9 10, true为11以上
* ...
* }
*/
const getInfo = () => {
let ua = safeData(globalThis, 'navigator.userAgent', '').toLowerCase();
let platform = safeData(globalThis, 'navigator.userAgentData.platform', '').toLowerCase();
let info = {
ua: ua,
platform: platform,
isMobile: !!ua.match(/mobile/),
isWin: !!platform.match('win'),
isIphone: !!ua.match(/iphone/),
isIpad: !!ua.match(/ipad/),
isMac: !!platform.match('mac'),
isIos: !!platform.match('ios'),
isAndroid: !!platform.match('android'),
isSafari: ua.indexOf('safari') > -1 && ua.indexOf('chrome') < 1,
isIE: 'ActiveXObject' in globalThis,
ieVersion: 0,
isAppleMobile: false,
isWeixin: !!ua.match(/MicroMessenger/i),
isAlipay: !!ua.match(/Alipay/i),
};
if (info.ua.match('msie')) {
let IE = info.ua.match(/msie\s([0-9]*)/);
if (IE && IE.length >= 2) {
info.ieVersion = +IE[1];
}
}
info.isAppleMobile = !!(info.isMobile &&
ua.toLowerCase().indexOf('applewebkit') &&
ua.indexOf('chrome') < 1);
return info;
};
/**
* @function
* @description 获取随机颜色
* @return string
*/
const getRandomColor = function () {
return ('#' +
('00000' + ((Math.random() * 0x1000000) << 0).toString(16)).substring(-6));
};
/**
* @function
* @description 获取storage的值,默认将json转为obj
* @param {string} argKey 要获取的key
* @param {string} argNoJson true时不自动转换JSON字符串
* @returns {any} key对应的数据
*/
const getStorage = (argKey, argNoJson) => {
let res = globalThis.localStorage.getItem(argKey);
// 默认转义JSON字符串
if (!argNoJson && isJson(res) && res) {
res = JSON.parse(res);
}
return res || '';
};
/**
* @function
* @description 设置storage的值,默认将obj转为json
* @param {string} argKey 要获取的key
* @param {unknown} argData 要保存的数据
* @returns {string} 保存的数据String
*/
const setStorage = (argKey, argData) => {
if (typeof argData === 'object') {
argData = JSON.stringify(argData);
}
globalThis.localStorage.setItem(argKey, String(argData));
return String(argData);
};
/**
* @function
* @description setTimeout promise版,异步阻塞函数
* @param {number} ms 时间,毫秒
*/
const sleep = (ms) => {
return new Promise((resolve) => setTimeout(resolve, ms));
};
/**
* @description 同步阻塞函数。
* @param {number} time - 延迟的时间量,单位为毫秒
*/
const delay = (time = 0) => {
};
/**
* @function
* @description 数据安全访问
* @param {any} argData [原始数据]
* @param {string} argCheck [要返回的数据,用'.'连接,数组用'.+数字表示']
* @param {any} argValue [如果数据有误,返回的值,选填]
* @param {boolean|0|1} argSetValueForce [是否强制赋值argValue]
* @returns {any}
*/
const safe = function safe(argData, argCheck, argValue, argSetValueForce) {
return safeData(argData, argCheck, argValue, argSetValueForce);
};
/**
* @function
* @description 数据安全访问
* @param {any} argData [原始数据]
* @param {string} argCheck [要返回的数据,用'.'连接,数组用'.+数字表示']
* @param {any} argValue [如果数据为undefined/null,返回argValue,选填]
* @param {boolean|0|1} argSetValueForce [是否强制赋值argValue,强制赋值时只返回true/false]
* @returns {any}
*/
const safeData = (argData, argCheck, argValue = undefined, argSetValueForce) => {
if (typeof argCheck !== 'string' && typeof argCheck !== 'number') {
console.warn('argCheck请传入string当前为:' + argCheck);
return '';
}
const temKey = argCheck.toString().split('.');
const temLen = temKey.length;
if (!argData) {
return argValue;
}
if (temLen > 1) {
for (let i = 0; i < temLen - 1; i++) {
if (typeof argData[temKey[i]] !== 'object') {
if (argSetValueForce) {
console.warn('safeData setValue err,data:', argData, 'no key:', argCheck);
return false;
}
else {
console.warn('noData return argValue', i);
return argValue;
}
}
argData = argData[temKey[i]] || {};
}
}
if (argSetValueForce) {
argData[temKey[temLen - 1]] = argValue;
return true;
}
if (typeof argValue === 'undefined') {
return argData[temKey[temLen - 1]];
}
else {
return argData[temKey[temLen - 1]] ?? argValue;
}
};
/**
* @description obj转url参数
* @function
* @param {any} argParams 参数对象
* @param {boolean?} noMark 默认带?,true时,不带
* @returns {string}
*/
const setUrlParams = (argParams, noMark) => {
let re = '';
if (!noMark) {
re = '?';
}
let paramsList = Object.keys(argParams);
let temLength = paramsList.length;
if (!temLength) {
return '';
}
paramsList.map((v, k) => {
re += v + '=' + argParams[v];
if (k < temLength - 1) {
re += '&';
}
});
return re;
};
/**
* @description 获取url参数
* @function
* @param {string} argName 要获取的key
* @param {string} argUrl url数据
* @returns {string}
*/
const getUrlParam = (argName, argUrl = globalThis.location.search || globalThis.location.hash) => {
let result = argUrl.match(new RegExp('[?&]' + argName + '=([^&]+)', 'i'));
if (!result) {
return '';
}
return decodeURIComponent(result[1]);
};
/**
* @description 获取所有url参数,eg: a=1&b=2 to {a:1,b:2}
* @function
* @param {string} argData 要处理的数据
* @returns {any}
*/
const getUrlParamObj = (argData = globalThis.location.search || globalThis.location.hash) => {
const res = {};
try {
argData
.slice(argData.indexOf('?') + 1)
.split('&')
.forEach((v) => {
const [key, val] = v.split('=');
if (key !== v) {
res[key] = decodeURIComponent(val);
}
});
return res;
}
catch (e) {
console.error('转换失败', e);
return res;
}
// let temObj = new URLSearchParams(argData)
// let resObj = {}
// for (const [key, value] of temObj) {
// resObj[key] = value
// }
// return resObj
};
/**
* @description 通过正则匹配修改当前页面的url中的参数
* @function
* @param {string} name key
* @param {string | number| undefined | null} value 要替换的value
* @param {string} url 要替换的网址,默认location.href
* @returns {string}
*/
const replaceUrlParam = (name, value, url = globalThis.location.href || '') => {
const reg = new RegExp('([?]|&)(' + name + '=)([^&#]*)([&]?|$)', 'img');
const r = url.match(reg);
const search = url.split('?');
let strValue = url;
if (value === undefined || value === null) {
if (r != null) {
strValue = url.replace(reg, (_match, p1, _p2, _p3, p4) => {
if (!p4 || !p4.length) {
return '';
}
else if (p1 === p4) {
return p1;
}
return p1 + p4;
});
strValue = strValue.replace('?&', '?');
}
}
else if (r != null) {
strValue = url.replace(reg, `$1$2${value}$4`);
}
else if (search.length > 1) {
const sub = search[1].split('#');
if (sub.length > 1) {
if (sub[1].length) {
strValue = `${search[0]}?${sub[0]}&${name}=${value}#${sub[1]}`;
}
else {
strValue = `${search[0]}?${sub[0]}&${name}=${value}${sub[1]}`;
}
}
else {
strValue = `${search[0]}?${search[1]}&${name}=${value}`;
}
}
else {
// 不存在?时,搜索hash
const sub = url.split('#');
if (sub.length > 1) {
strValue = `${sub[0]}?${name}=${value}#${sub[1]}`;
}
else {
strValue = `${url}?${name}=${value}`;
}
}
return strValue;
};
/**
* @function
* @description 获取简单uuid
* @returns {string} uuid
*/
const getUuid = () => {
const S4 = () => (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
return S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + Date.now();
};
/**
* @function
* @description 获取随机数,含最大值,含最小值
* @param {number} min 最小值
* @param {number} max 最大值
* @returns {number}
*/
const randomInt = (min = 0, max = 100) => {
min = Math.ceil(min);
max = Math.floor(max);
// 含最大值,含最小值
return Math.floor(Math.random() * (max - min + 1)) + min;
};
/**
* @function
* @description 设置env参数,一般在main.js中调用
* @param {AnyObject} env 要设置的值
* @example
* setEnv(import.meta.env)
*/
const setEnv = (env) => {
ENV = env;
};
/**
* @function
* @description 获取env参数
* @param {string} key 要获取的值
* @returns {string} 获取的值
*/
const getEnv = (key) => {
return safeData(ENV, key, '');
};
/**
* @function
* @description 设置object参数,可做运行时缓存
* @param {string} key 要设置的key
* @param {AnyObject} data 要设置的值
* @returns {AnyObject}
*/
const setObj = (key, data) => {
if (!key) {
DATA_OBJECT = data;
}
else {
DATA_OBJECT[key] = data;
}
return DATA_OBJECT;
};
/**
* @function
* @description 获取object参数
* @param {string} key 要获取的值
* @param {string} argData 要合并的值
* @param {boolean} isDeepCopy 是否深拷贝
* @returns {AnyObject} 获取的值
*/
const getObj = (key, argData, isDeepCopy) => {
let res = safeData(DATA_OBJECT, key, {});
if (typeof res !== 'object') {
console.warn('DATA_OBJECT.' + key + ' is not a object');
return res;
}
if (isDeepCopy) {
res = deepCopy(res);
}
if (argData) {
Object.assign(res, argData);
}
return res;
};
/**
* @function
* @description 设置日志输出logLevel 1 error 2 warn 3 info 4 log 5 debug
* @param {AnyObject} logConfig 重写配置
* @param {function} logConfig.error 错误日志回调(做额外处理用)
* @example
* setLog(localStorage.getItem('logLevel'),{
error: (...arg) => {
// todo
}
})
*/
const setLog = (logLevel = 4, logConfig = { error: 0 }) => {
// 1 error 2 warn 3 info 4 log 5 debug
logLevel = logLevel || getEnv('VUE_APP_LOG_LEVEL') || 4;
const logList = ['log', 'info', 'warn', 'error'];
const log = {};
logList.forEach((v) => {
log[v] = console[v];
});
for (let key in logConfig) {
if (console[key]) {
console[key] = (...arg) => {
const line = safeData(Error(), 'stack', [])?.split('\n')[2] || '';
log[key](...arg, 'line>>' + line);
// 回调处理
typeof logConfig[key] === 'function' && logConfig[key](...arg, line);
};
}
}
switch (+logLevel) {
case 1:
console.warn = () => { };
case 2:
console.info = () => { };
case 3:
console.log = () => { };
case 4:
console.debug = () => { };
}
// return log
};
/**
* @function
* @description深拷贝函数
* @param obj 需要拷贝的对象
* @returns 拷贝后的对象
*/
const deepCopy = (obj, hash = new WeakMap()) => {
if (obj === null || typeof obj !== 'object')
return obj;
if (obj instanceof Date)
return new Date(obj);
if (obj instanceof RegExp)
return new RegExp(obj);
if (obj instanceof Map)
return new Map(deepCopy(Array.from(obj), hash));
if (obj instanceof Set)
return new Set(deepCopy(Array.from(obj), hash));
if (hash.has(obj))
return hash.get(obj);
const copy = Array.isArray(obj)
? []
: Object.create(Object.getPrototypeOf(obj));
hash.set(obj, copy);
for (let key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
copy[key] = deepCopy(obj[key], hash);
}
}
return copy;
};
/**
* @function
* @description 摇一摇,请求使用 DeviceMotionEvent API 的权限。for ios
* @returns Promise,指示是否已授予权限。
* @example
* ```
* const hasRequest = await requestDeviceMotionPermission()
* if (hasRequest) {
* useEventListener(window, 'devicemotion', handleShake)
* } else {
* showToast('未授权访问运动传感器,请手动点击!')
* }
* ```
*/
const requestDeviceMotionPermission = () => {
if (typeof DeviceMotionEvent?.requestPermission === 'function') {
return DeviceMotionEvent
.requestPermission()
.then((permissionState) => {
if (permissionState === 'granted') {
return true;
}
else {
return false;
}
})
.catch(() => {
return false;
});
}
else {
return true;
}
};
/**
* @function
* @description 自动播放音频并返回音频元素。
* @param {string} audioUrl - 音频地址
* @param {boolean} isWeixin - 是否在微信中
* @returns {HTMLAudioElement} - 音频元素
*/
const autoPlayAudio = (audioUrl, isWeixin) => {
const audio = new Audio(audioUrl);
audio.addEventListener('ended', function () {
this.currentTime = 0;
this.play();
}, false);
audio.autoplay = true;
if (isWeixin) {
document.addEventListener('WeixinJSBridgeReady', function () {
audio.play();
}, false);
}
return audio;
};
/**
* @function
* @description 函数防抖,用于限制函数调用的频率。
* @param {Function} func - 要进行防抖的函数
* @param {number} delay - 延迟时间,单位毫秒
* @return {Function} 返回防抖后的函数
* @example
* ```
* const debouncedHello = debounce(sayHello, 1000);
* debouncedHello('Hello from 1');
* debouncedHello('Hello from 2');
* ```
*/
const debounce = (fn, delay = 300, ...extra) => {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => {
fn.call(this, ...args, ...extra);
}, delay);
};
};
/**
* @function
* @description 节流函数:该函数用于限制函数的执行频率,使其在指定的时间间隔内最多执行一次
* @param {Function} fn - 要节流的函数。
* @param {number} [delay=300] - 函数执行之间的延迟时间(毫秒)。默认为 300 毫秒。
* @param {...any} extra - 可选的额外参数,传递给节流函数的原始调用。
* @returns {Function} 返回一个新的函数,该函数具有节流行为。
* @example
* ```
* const sayHelloFn = (a: string,b:any) => {
* console.log(a,b);
* }
* const throttleHello = throttle(sayHelloFn, 300,'extra info);
* throttleHello('Hello from 1');
* throttleHello('Hello from 2');
* // Hello from 1 extra info
* ```
*/
const throttle = (fn, delay = 300, ...extra) => {
let temTime = 0;
return function (...args) {
const now = Date.now();
if (now - temTime > delay) {
temTime = now;
fn.call(this, ...args, ...extra);
}
};
};
/**
* @function
* @description 添加事件绑定
* @param {Element} el - 绑定元素
* @param {string} event - 事件名称
* @param {function} handler - 事件处理函数
*/
const on = (function () {
if (typeof globalThis.document?.addEventListener === 'function') {
return function (el, event, handler) {
if (el && event && handler) {
el.addEventListener(event, handler, false);
}
};
}
return function (el, event, handler) {
if (el && event && handler) {
el.attachEvent('on' + event, handler);
}
};
})();
/**
* @function
* @description 移除事件绑定
* @param {Element} el - 绑定元素
* @param {string} event - 事件名称
* @param {function} handler - 事件处理函数
*/
const off = (function () {
if (typeof globalThis.document?.removeEventListener === 'function') {
return function (el, event, handler) {
if (el && event) {
el.removeEventListener(event, handler, false);
}
};
}
return function (el, event, handler) {
if (el && event) {
el.detachEvent('on' + event, handler);
}
};
})();
export { autoPlayAudio, debounce, deepCopy, delCookie, delay, getCookie, getCookieObj, getEnv, getInfo, getNetworkStatus, getObj, getRandomColor, getRegexp, getStorage, getUrlParam, getUrlParamObj, getUuid, off, on, randomInt, remInit, replaceUrlParam, requestDeviceMotionPermission, safe, safeData, setCookie, setEnv, setLog, setObj, setStorage, setTitle, setUrlParams, sleep, throttle };