/**
|
* Tools
|
* @author Tevin
|
*/
|
|
import moment from 'moment';
|
import Taro from '@tarojs/taro';
|
|
export class Tools {
|
|
/**
|
* 显示消息
|
* @param msg
|
* @param [duration=2000]
|
*/
|
static toast(msg, duration = 2000) {
|
Taro.showToast({
|
title: msg,
|
icon: 'none',
|
mask: true,
|
duration,
|
});
|
}
|
|
/**
|
* URL参数解析
|
* @param {String} name
|
* @param {String} [search]
|
* @return {String|Null}
|
*/
|
static getUrlParam(name, search) {
|
if (process.env.TARO_ENV === 'weapp') {
|
return null;
|
}
|
search = search || window.location.search;
|
const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
|
const r = search.substr(1).match(reg);
|
if (r !== null) {
|
return decodeURIComponent(r[2]);
|
} else {
|
return null;
|
}
|
}
|
|
/**
|
* 读取文件 base64
|
* @param {File} file
|
* @return {Promise<string>}
|
*/
|
static getFileBase64(file) {
|
return new Promise((resolve, reject) => {
|
const reader = new FileReader();
|
reader.onload = () => resolve(reader.result);
|
reader.onerror = error => reject(error);
|
reader.readAsDataURL(file);
|
});
|
}
|
|
/**
|
* 生成 GUID
|
* @return {string}
|
*/
|
static createGUID() {
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
let r = Math.random() * 16 | 0,
|
v = c === 'x' ? r : ((r & 0x3) | 0x8);
|
return v.toString(16);
|
});
|
}
|
|
/**
|
* 判断是否是数字
|
* @param {*} data
|
* @return {Boolean}
|
*/
|
static isNumber(data) {
|
return Object.prototype.toString.call(data) === '[object Number]';
|
}
|
|
/**
|
* 判断是否是字符串
|
* @param {*} data
|
* @return {Boolean}
|
*/
|
static isString(data) {
|
return Object.prototype.toString.call(data) === '[object String]';
|
}
|
|
/**
|
* 判断是否为布尔值
|
* @param {*} data
|
* @return {Boolean}
|
*/
|
static isBoolean(data) {
|
return Object.prototype.toString.call(data) === '[object Boolean]';
|
}
|
|
/**
|
* 判断是否是普通对象
|
* @param {*} data
|
* @return {Boolean}
|
*/
|
static isObject(data) {
|
return Object.prototype.toString.call(data) === '[object Object]';
|
}
|
|
/**
|
* 判断是否是数组
|
* @param {*} data
|
* @return {Boolean}
|
*/
|
static isArray(data) {
|
return Object.prototype.toString.call(data) === '[object Array]';
|
}
|
|
/**
|
* 判断是否是函数
|
* @param {*} data
|
* @return {Boolean}
|
*/
|
static isFunction(data) {
|
return Object.prototype.toString.call(data) === '[object Function]';
|
}
|
|
/**
|
* 判断是否为未定义
|
* @param {*} data
|
* @return {Boolean}
|
*/
|
static isUndefined(data) {
|
return Object.prototype.toString.call(data) === '[object Undefined]';
|
}
|
|
/**
|
* 判断是否为 null
|
* @param {*} data
|
* @return {Boolean}
|
*/
|
static isNull(data) {
|
return Object.prototype.toString.call(data) === '[object Null]';
|
}
|
|
/**
|
* 是否为空对象
|
* @param {*} obj
|
* @return {Boolean}
|
*/
|
static isEmptyObject(obj) {
|
if (!Tools.isObject(obj)) {
|
return true;
|
}
|
for (let p in obj) {
|
if (obj.hasOwnProperty(p)) {
|
return false;
|
}
|
}
|
return true;
|
}
|
|
/**
|
* 判断对象是否在属性上相等
|
* @param {String} a
|
* @param {String} b
|
* @return {Boolean}
|
*/
|
static isObjValEqual(a, b) {
|
const aProps = Object.getOwnPropertyNames(a);
|
const bProps = Object.getOwnPropertyNames(b);
|
if (aProps.length !== bProps.length) {
|
return false;
|
}
|
for (let i = 0, propName; i < aProps.length; i++) {
|
propName = aProps[i];
|
if (a[propName] !== b[propName]) {
|
return false;
|
}
|
}
|
return true;
|
}
|
|
/**
|
* 统计字符串占位宽度
|
* @param {String} string
|
* @return {Number}
|
*/
|
static countStringLength(string) {
|
let realLength = 0;
|
const len = string.length;
|
let charCode = -1;
|
for (let i = 0; i < len; i++) {
|
charCode = string.charCodeAt(i);
|
// 128编号内字符占1位宽度
|
if (charCode >= 0 && charCode <= 128) {
|
realLength += 1;
|
}
|
// 128编号后字符(包括中文)占2位宽度
|
else {
|
realLength += 2;
|
}
|
}
|
return realLength;
|
}
|
|
/**
|
* 获取字符串基于字节长度的剪切点
|
* @param {String} string
|
* @param {Number} byteLength
|
* @return {Number}
|
*/
|
static getStringCutIndex(string, byteLength) {
|
if (byteLength === 0) {
|
return 0;
|
}
|
let countLength = 0;
|
let charCode = -1;
|
let cutIndex = 0;
|
const len = string.length;
|
for (let i = 0; i < len; i++) {
|
charCode = string.charCodeAt(i);
|
// 128编号内字符占1位宽度
|
if (charCode >= 0 && charCode <= 128) {
|
countLength += 1;
|
}
|
// 128编号后字符(包括中文)占2位宽度
|
else {
|
countLength += 2;
|
}
|
// 裁剪位置
|
if (countLength > byteLength) {
|
cutIndex = i;
|
break;
|
}
|
}
|
return cutIndex;
|
}
|
|
/**
|
* 限制数值范围,超出边界返回边界值
|
* @param {Number|String} num
|
* @param {[Number,Number]} range
|
* @return {Number}
|
*/
|
static limitNumberRange(num, range) {
|
num = Number(num);
|
num = num < range[0] ? range[0] : num;
|
num = num > range[1] ? range[1] : num;
|
return num;
|
}
|
|
/**
|
* 深拷贝
|
* @param {Object} source
|
* @return {Object|Array}
|
*/
|
static deepCopy(source) {
|
let result = null;
|
if (source instanceof Array) {
|
result = [];
|
} else {
|
result = {};
|
}
|
for (let key in source) {
|
if (source.hasOwnProperty(key)) {
|
if (typeof source[key] === 'object') {
|
if (Tools.isNull(source[key])) {
|
result[key] = source[key];
|
} else {
|
result[key] = this.deepCopy(source[key]);
|
}
|
} else {
|
result[key] = source[key];
|
}
|
}
|
}
|
return result;
|
}
|
|
/**
|
* 深合并
|
* @param target
|
* @param source
|
* @return {Object|Array}
|
*/
|
static deepCombine(target, source) {
|
for (let key in source) {
|
if (source.hasOwnProperty(key)) {
|
if (typeof source[key] === 'object') {
|
if (Tools.isNull(source[key])) {
|
target[key] = source[key];
|
} else {
|
if (Tools.isArray(source[key])) {
|
target[key] = [];
|
} else {
|
target[key] = {};
|
}
|
this.deepCombine(target[key], source[key]);
|
}
|
} else {
|
target[key] = source[key];
|
}
|
}
|
}
|
return target;
|
}
|
|
/**
|
* 使用 moment.js 格式化时间戳
|
* @param {Number|String} timestamp
|
* @param {String} [type='date']
|
* @return {String}
|
*/
|
static momentFormat(timestamp, type = 'date') {
|
if (!timestamp || timestamp === '0' || timestamp === 0) {
|
return '';
|
}
|
// 字符串
|
if (Tools.isString(timestamp)) {
|
// 全数值
|
if (/^\d+$/.test(timestamp)) {
|
timestamp = parseInt(timestamp);
|
}
|
// 日期
|
else {
|
try {
|
timestamp = (new Date(timestamp)).getTime();
|
} catch (e) {
|
}
|
}
|
}
|
if (timestamp < 9 * 10e8) {
|
timestamp *= 1000;
|
}
|
const curMoment = moment(timestamp);
|
if (type === 'date') {
|
return curMoment.format('YYYY-MM-DD');
|
} else if (type === 'dateTime') {
|
return curMoment.format('YYYY-MM-DD HH:mm');
|
} else if (type === 'dateTimeShort') {
|
return curMoment.format('MM-DD HH:mm');
|
} else if (type === 'dateTimeFull') {
|
return curMoment.format('YYYY-MM-DD HH:mm:ss');
|
}
|
}
|
|
/**
|
* 数值转换为时长描述
|
* @param {number} timestamp
|
* @return {string}
|
*/
|
static durationFormat(timestamp) {
|
if (typeof timestamp !== 'number') {
|
return '';
|
}
|
let words = '';
|
const duration = moment.duration(timestamp);
|
const seconds = duration.get('seconds');
|
if (seconds) {
|
words = seconds + '秒';
|
}
|
const minutes = duration.get('minutes');
|
if (minutes) {
|
words = minutes + '分' + words;
|
}
|
const hours = parseInt(duration.as('hours'));
|
if (hours) {
|
words = hours + '小时' + words;
|
}
|
return words;
|
}
|
|
/**
|
* 数值转换为金钱格式
|
* @param {Number|String} number
|
* @return {string}
|
*/
|
static moneyFormat(number) {
|
if (!number && typeof number !== 'number' && typeof number !== 'string') {
|
return '';
|
}
|
if (typeof number === 'string') {
|
number = Number(number) || 0;
|
}
|
return number.toFixed(2);
|
}
|
|
/**
|
* 加法函数,用来得到精确的加法结果
|
* @param {Number|String} num1
|
* @param {Number|String} num2
|
*/
|
static accAdd(num1, num2) {
|
const r1 = Tools.getDecimalLength(num1);
|
const r2 = Tools.getDecimalLength(num2);
|
const m = Math.pow(10, Math.max(r1, r2));
|
return (Number(num1) * m + Number(num2) * m) / m;
|
}
|
|
/**
|
* 减法函数,用来得到精确的减法结果
|
* @param {Number|String} num1
|
* @param {Number|String} num2
|
*/
|
static accSub(num1, num2) {
|
return Tools.accAdd(num1, -num2);
|
}
|
|
/**
|
* 乘法函数,用来得到精确的乘法结果
|
* @param {Number|String} num1
|
* @param {Number|String} num2
|
*/
|
static accMul(num1, num2) {
|
let m = 0;
|
m += Tools.getDecimalLength(num1);
|
m += Tools.getDecimalLength(num2);
|
const r1 = Number(num1.toString().replace('.', ''));
|
const r2 = Number(num2.toString().replace('.', ''));
|
return (r1 * r2) / Math.pow(10, m);
|
}
|
|
/**
|
* 除法函数,用来得到精确的除法结果
|
* @param {Number|String} num1
|
* @param {Number|String} num2
|
*/
|
static accDiv(num1, num2) {
|
const t1 = Tools.getDecimalLength(num1);
|
const t2 = Tools.getDecimalLength(num2);
|
const r1 = Number(num1.toString().replace('.', ''));
|
const r2 = Number(num2.toString().replace('.', ''));
|
return (r1 / r2) * Math.pow(10, t2 - t1);
|
}
|
|
/**
|
* 求小数点后的数据长度
|
* @param {Number|String} num
|
* @private
|
*/
|
static getDecimalLength(num) {
|
let t = 0;
|
try {
|
t = num.toString().split('.')[1].length;
|
} catch (e) {
|
}
|
return t;
|
}
|
|
/**
|
* 判断是否为手机号码
|
* @param {Number|String} phone
|
* @returns {boolean}
|
*/
|
static isPhone(phone) {
|
return /^1[3456789]\d{9}$/.test('' + phone);
|
}
|
|
}
|
|
// h5 中,实现 rem 转换 px
|
if (process.env.NODE_ENV === 'development' && process.env.TARO_ENV === 'h5') {
|
window.rem = val => {
|
const p1 = {
|
x: parseFloat(Taro.pxTransform(10, 750)), y: 10,
|
};
|
const p2 = {
|
x: parseFloat(Taro.pxTransform(1000, 750)), y: 1000,
|
};
|
const value = typeof val === 'number' ? val : parseFloat(val);
|
const px = (value - p1.x) * (p2.y - p1.y) / (p2.x - p1.x) + p1.y;
|
console.info(Math.round(px) + 'px');
|
};
|
}
|