const oneMinuteSeconds = 60 const onehourSeconds = oneMinuteSeconds * 60 const oneDaySeconds = onehourSeconds * 24 let forbiddenWords: string[] = undefined export class Utils { //是否空值 public static isNull(o: any): boolean { let type = Object.prototype.toString.call(o); return ("[object Null]" === type || "[object Undefined]" === type); } //是否字符串 public static isString(o: any): boolean { return ("[object String]" === Object.prototype.toString.call(o)); } //是否数字 public static isNumber(o: any): boolean { return ("[object Number]" === Object.prototype.toString.call(o)); } //是否数组 public static isArray(o: any): boolean { return ("[object Array]" === Object.prototype.toString.call(o)); } //是否字典 public static isObject(o: any): boolean { return ("[object Object]" === Object.prototype.toString.call(o)); } //是否方法 public static isFunction(o: any): boolean { return ("[object Function]" === Object.prototype.toString.call(o)); } //继承 public static inherit(base: Function, obj: Function) { for (let key in base.prototype) { obj.prototype[key] = base.prototype[key]; } return obj; } //继承 public static queryUrl(url: string) { let querys = {}; let index = url.indexOf("?") cc.log(index) if (index >= 0) { let strs = url.substr(index + 1).split("&") for (let i = 0, len = strs.length; i < len; i++) { if (strs[i].indexOf("=") > 0) { let params = strs[i].split("="); if (params[0].trim() != "") { querys[params[0]] = params[1]; } } } } return querys; } // 将base64字符串转换成图片 public static getSpritFrameFromBase64(base64: string): cc.SpriteFrame { base64 = "data:image/jpeg;base64," + base64; let img = new Image(); img.src = base64; let texture = new cc.Texture2D(); texture.initWithElement(img); texture.handleLoadedTexture(); return new cc.SpriteFrame(texture); } //生成uuid public static uuid(length: number) { let chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); let uuid = [], i = 0; let radix = chars.length; if (length > 0) { // Compact form for (i = 0; i < length; i++) uuid[i] = chars[0 | Math.random() * radix]; } else { // rfc4122, version 4 form let r: number = 0; // rfc4122 requires these characters uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'; uuid[14] = '4'; // Fill in random data. At i==19 set the high bits of clock sequence as // per rfc4122, sec. 4.1.5 for (i = 0; i < 36; i++) { if (!uuid[i]) { r = 0 | Math.random() * 16; uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]; } } } return uuid.join(''); } //复制文本 public static onCopyText(copyText: string): boolean { if (cc.sys.isBrowser) { let input = document.createElement("input"); input.setAttribute("readonly", "readonly"); input.setAttribute("value", copyText); input.style.position = "absolute"; input.style.left = "-9999px"; input.style.fontSize = "12pt"; // Prevent zooming on iOS document.body.appendChild(input); input.select(); input.setSelectionRange(0, 128); let success = false; try { if (document.execCommand("Copy")) { success = true; } } catch (e) { console.log(e) } document.body.removeChild(input); return success; } else { // if (Common.OpenFunction.COPYTEXT) { // if (cc.sys.os == cc.sys.OS_ANDROID) { // jsb.reflection.callStaticMethod("org/cocos2dx/javascript/AppActivity", "JavaCopy", "(Ljava/lang/String;)V", copyText); // return true // } // else if (cc.sys.os == cc.sys.OS_IOS) { // let IOS_API = "AppController"; // jsb.reflection.callStaticMethod(IOS_API, "JavaCopy:", copyText); // return true // } // } } return false } //复制文本 public static getCopyText(): string { let copyText = "" // if (Common.OpenFunction.COPYTEXT) { // if (cc.sys.os == cc.sys.OS_ANDROID) { // copyText = jsb.reflection.callStaticMethod("org/cocos2dx/javascript/AppActivity", "getDuplicateContent", "()Ljava/lang/String;"); // } // else if (cc.sys.os == cc.sys.OS_IOS) { // let IOS_API = "AppController"; // copyText = jsb.reflection.callStaticMethod(IOS_API, "getDuplicateContent:", ""); // } // } return copyText } /** * 尋找當前scrollView滑動百分比 * @param scrollView */ public static judgeScrollPercent(scrollView: cc.ScrollView) { const offset = scrollView.getScrollOffset() const maxOffset = scrollView.getMaxScrollOffset() const offsetArray = [offset.x, offset.y] const maxOffsetArray = [maxOffset.x, maxOffset.y, maxOffset.y] const index = maxOffsetArray.indexOf(Math.max(...maxOffsetArray)) offsetArray[index] = Math.abs(offsetArray[index]) offsetArray[index] = offsetArray[index] < 0 ? 0 : offsetArray[index] offsetArray[index] = offsetArray[index] > maxOffsetArray[index] ? maxOffsetArray[index] : offsetArray[index] return offsetArray[index] / maxOffsetArray[index] } /** * 轉換錢幣 */ public static moneyUnitConvert(money: number) { if (money < 1000) { return money + '' } else { return money / 1000 + 'K' } } /** * 三位一撇 */ public static numberWithCommas(number: number) { let parts = number.toFixed(2).split('.') let decimal = parts[1].slice(); for (let i = parts[1].length - 1; i >= 0; i--) { if (parts[1][i] != '0') { break; } else { decimal = decimal.substr(0, i); } } parts[1] = decimal; return parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',') + (parts[1] ? '.' + parts[1] : '') } /** * 無條件捨去 */ public static roundDown(number: number) { return Number(String(number).split(".")[0]) } public static deepClone(data: any) { if (data === undefined || data === null) { return data } return JSON.parse(JSON.stringify(data || {})) } /** * 閃爍動畫 * @param node 閃爍節點 * @param duration 間隔 * @param repeat 重複次數(-1為無限) * @param callBack 回調函式 */ public static blink(node: cc.Node, duration: number, repeat = 0, endShow: boolean = true, callBack?: Function) { // cc.log(`blick duration:${duration} repeat:${repeat}`); node.active = true cc.Tween.stopAllByTarget(node) node.opacity = 0; const show = endShow ? 255 : 0; let action = cc.tween() .to(duration, { opacity: 0 }, { easing: 'quadIn' }) .to(duration, { opacity: 255 }, { easing: 'quadOut' }) cc.tween(node).repeat(repeat, action).call(() => { node.opacity = show; callBack && callBack() }).start(); } public static currencyFilter(value: number) { if (value < 1000) { return `${value}` } value = value - (value % 100) return `${value / 1000}K` } public static getCanvasInParent(node: cc.Node): cc.Canvas { if (!node) { return undefined } let canvas = undefined let parent = node.parent while (!canvas) { if (!parent) { break } canvas = parent.getComponent(cc.Canvas) parent = parent.parent } return canvas } public static clamp(val: number, min: number, max: number): number { return val < min ? min : (val > max ? max : val) } public static copyString(str: string) { const el = document.createElement('textarea') el.value = str el.setAttribute('readonly', '') // el.style.contain = 'strict'; el.style.position = 'absolute' el.style.left = '-9999px' el.style.fontSize = '12pt' // Prevent zooming on iOS const selection = getSelection() let originalRange = null if (selection.rangeCount > 0) { originalRange = selection.getRangeAt(0) } document.body.appendChild(el) el.select() el.selectionStart = 0 el.selectionEnd = str.length let success = false try { success = document.execCommand('copy') } catch (err) { } document.body.removeChild(el) if (originalRange) { selection.removeAllRanges() selection.addRange(originalRange) } if (success) { console.log('复制成功') } else { console.log('复制失败') } return success } public static setButtonInteractable(button: cc.Button, value: boolean) { if (!button) { return } button.interactable = value } public static changeNodeParent(node, parent) { if (!node) { cc.error("changeNodeParent node is null"); return; } if (!parent) { cc.error("changeNodeParent parent is null"); return; } let pos = node.parent.convertToWorldSpaceAR(node.getPosition()); let changePos = parent.convertToNodeSpaceAR(pos); node.parent = parent; node.setPosition(changePos); } public static tweenNumberLabel(label: cc.Label, num: number, suffix: string = '') { const currentNum = Number(label.string.replace(/,/g, '').replace(suffix, '')) if (!Utils.isNumber(currentNum)) { console.warn('label is not number:', label.string) return } if (currentNum >= num) { label.string = Utils.numberWithCommas(num) + suffix return } const plusNum = num - currentNum const betweenTime = 0.01 const count = 80 let currentCount = 0 label.unscheduleAllCallbacks() label.schedule( () => { if (!label) { return } currentCount += 1 label.string = Utils.numberWithCommas(Math.round(currentNum + (plusNum / count) * currentCount)) + suffix if (currentCount === count) { label.string = Utils.numberWithCommas(num) + suffix } }, betweenTime, count - 1 ) } public static tweenSpriteFillrange(sprite: cc.Sprite, percent: number) { // cc.log("tweenSpriteFillrange ", percent) let changeTotal = percent - sprite.fillRange; const count = 80; const betweenTime = 0.01 let per = changeTotal / count; let curRange = sprite.fillRange; sprite.unscheduleAllCallbacks(); sprite.schedule(() => { curRange += per; sprite.fillRange = curRange; }, betweenTime, count - 1); } // 計算字符長度 (英文數字當成1 其他當成2) public static countMultiLangStrLength(str: string): number { const originalSize = str.length const digitNLetter = str.replace(/[^a-zA-Z0-9]/g, '') const englishSize = digitNLetter.length const otherLength = (originalSize - digitNLetter.length) * 2 return englishSize + otherLength } public static formatNickname(str: string, maxLen = 6) { let len = Utils.countMultiLangStrLength(str); let subLen = len; while (subLen > maxLen) { str = str.substr(0, str.length - 1); subLen = Utils.countMultiLangStrLength(str); } return len > 6 ? (str + "...") : str; } /** * 數字換行(奇數上排數字大於下排, 偶數對半) * @param numStr 欲轉換數字 * @param limitNum 幾位後要換行 */ public static convertChipStr(numStr: string, limitNum: number = 3) { const len = numStr.length if (len > limitNum) { const sliceLen = Math.ceil(len * 0.5) return `${numStr.slice(0, sliceLen)}\n${numStr.slice(sliceLen)}` } else { return numStr } } /** 發送訊息提示 */ public static showSendLog(eventName: string, message?: any) { if (CC_DEBUG) { message = message || {}; const time = this.convertTimestamp(new Date().getTime()); let data = JSON.parse(JSON.stringify(message)); // Deep Copy console.log("%s %c %s", time, "background: Green; color: White;", "發送 " + eventName + " ", data); } } /** 回傳訊息提示 */ public static showResponseLog(eventName: string, message?: any) { if (CC_DEBUG) { message = message || {}; const time = this.convertTimestamp(new Date().getTime()); let data = JSON.parse(JSON.stringify(message)); // Deep Copy console.log("%s %c %s", time, "background: Green; color: White;", "回應 " + eventName + " ", data); } } /** 廣播訊息提示 */ public static showPushLog(eventName: string, message: any) { if (CC_DEBUG) { message = message || {}; const time = this.convertTimestamp(new Date().getTime()); let data = JSON.parse(JSON.stringify(message)); // Deep Copy console.log("%s %c %s", time, "background: Blue; color: White;", "廣播 " + eventName + " ", data); } } private static convertTimestamp(value: number): string { const t = new Date(value); // const yyyy = t.getFullYear(); // const MM = t.getMonth() < 9 ? "0" + (t.getMonth()+1):t.getMonth()+1; // const DD = t.getDate() < 10 ? "0" + t.getDate() : t.getDate(); const hh = t.getHours() < 10 ? "0" + t.getHours() : t.getHours(); const mm = t.getMinutes() < 10 ? "0" + t.getMinutes() : t.getMinutes() const ss = t.getSeconds() < 10 ? "0" + t.getSeconds() : t.getSeconds() return `${hh}:${mm}:${ss}`; } }