1、科学计算法
var countDecimals = function(num) {
var len = 0;
try {
num = Number(num);
var str = num.toString().toUpperCase();
if (str.split('E').length === 2) { // scientific notation
var isDecimal = false;
if (str.split('.').length === 2) {
str = str.split('.')[1];
if (parseInt(str.split('E')[0]) !== 0) {
isDecimal = true;
}
}
let x = str.split('E');
if (isDecimal) {
len = x[0].length;
}
len -= parseInt(x[1]);
} else if (str.split('.').length === 2) { // decimal
if (parseInt(str.split('.')[1]) !== 0) {
len = str.split('.')[1].length;
}
}
} catch (e) {
throw e;
} finally {
if (isNaN(len) || len < 0) {
len = 0;
}
return len;
}
};
var convertToInt = function(num) {
num = Number(num);
var newNum = num;
var times = countDecimals(num);
var temp_num = num.toString().toUpperCase();
if (temp_num.split('E').length === 2) {
newNum = Math.round(num * Math.pow(10, times));
} else {
newNum = Number(temp_num.replace(".", ""));
}
return newNum;
};
var getCorrectResult = function(type, num1, num2, result) {
var temp_result = 0;
switch (type) {
case "add":
temp_result = num1 + num2;
break;
case "sub":
temp_result = num1 - num2;
break;
case "div":
temp_result = num1 / num2;
break;
case "mul":
temp_result = num1 * num2;
break;
}
if (Math.abs(result - temp_result) > 1) {
return temp_result;
}
return result;
};
export default {
// 加法
accAdd(num1, num2) {
num1 = Number(num1);
num2 = Number(num2);
var dec1, dec2, times;
try { dec1 = countDecimals(num1) + 1; } catch (e) { dec1 = 0; }
try { dec2 = countDecimals(num2) + 1; } catch (e) { dec2 = 0; }
times = Math.pow(10, Math.max(dec1, dec2));
// var result = (num1 * times + num2 * times) / times;
var result = (this.accMul(num1, times) + this.accMul(num2, times)) / times;
return getCorrectResult("add", num1, num2, result);
// return result;
},
// 减法
accSub(num1, num2) {
num1 = Number(num1);
num2 = Number(num2);
var dec1, dec2, times;
try { dec1 = countDecimals(num1) + 1; } catch (e) { dec1 = 0; }
try { dec2 = countDecimals(num2) + 1; } catch (e) { dec2 = 0; }
times = Math.pow(10, Math.max(dec1, dec2));
// var result = Number(((num1 * times - num2 * times) / times);
var result = Number((this.accMul(num1, times) - this.accMul(num2, times)) / times);
return getCorrectResult("sub", num1, num2, result);
// return result;
},
// 除法
accDiv(num1, num2) {
num1 = Number(num1);
num2 = Number(num2);
var t1 = 0,
t2 = 0,
dec1, dec2;
try { t1 = countDecimals(num1); } catch (e) {}
try { t2 = countDecimals(num2); } catch (e) {}
dec1 = convertToInt(num1);
dec2 = convertToInt(num2);
var result = this.accMul((dec1 / dec2), Math.pow(10, t2 - t1));
return getCorrectResult("div", num1, num2, result);
// return result;
},
// 乘法
accMul(num1, num2) {
num1 = Number(num1);
num2 = Number(num2);
var times = 0,
s1 = num1.toString(),
s2 = num2.toString();
try { times += countDecimals(s1); } catch (e) {}
try { times += countDecimals(s2); } catch (e) {}
var result = convertToInt(s1) * convertToInt(s2) / Math.pow(10, times);
return getCorrectResult("mul", num1, num2, result);
// return result;
}
}
2、防抖节流插槽版
/**
* 防抖函数(可用于防止重复提交), 就是指触发事件后在 n 秒内函数只能执行一次
* 节流函数, 就是指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率
*
* @param func 执行函数
* @param time 执行时间间隔
* @param isDebounce 是否防抖或者节流
* @param ctx event
*/
const debounce = (func, time, isDebounce, ctx) => {
var timer, lastCall, rtn;
// 防抖函数
if (isDebounce) {
rtn = (...params) => {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
func.apply(ctx, params);
}, time);
};
// 节流函数
} else {
rtn = (...params) => {
const now = new Date().getTime();
if (now - lastCall < time && lastCall) return;
lastCall = now;
func.apply(ctx, params);
};
}
return rtn;
};
export default {
name: 'Debounce',
abstract: true,
props: {
time: {
type: Number,
default: 800,
},
events: {
type: String,
default: 'click',
},
isDebounce: {
type: Boolean,
default: true,
},
},
created() {
this.eventKeys = this.events.split(',');
this.originMap = {};
this.debouncedMap = {};
},
render() {
const vnode = this.$slots.default[0];
this.eventKeys.forEach(key => {
const target = vnode.data.on[key];
if (target === this.originMap[key] && this.debouncedMap[key]) {
vnode.data.on[key] = this.debouncedMap[key];
} else if (target) {
this.originMap[key] = target;
this.debouncedMap[key] = debounce(
target,
this.time,
this.isDebounce,
vnode
);
vnode.data.on[key] = this.debouncedMap[key];
}
});
return vnode;
},
};
使用方法:
<Debounce :time='200' >
<el-button @click.native="handleUserLogin">登录</el-button>
</Debounce>
main.js
// 防抖 or 节流
import Debounce from '@/utils/debounce'
Vue.component('Debounce', Debounce)
3、其他公共方法(待完善)
/**
* 防抖函数(可用于防止重复提交)
* 当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,
* 如果设定时间到来之前,又触发了事件,就重新开始延时。也就是说当一个用户一直触发这个函数,
* 且每次触发函数的间隔小于既定时间,那么防抖的情况下只会执行一次。
*
* @param fn 执行函数
* @param delay 间隔时间
*/
function debounce (fn, delay) {
let timeout = null;
return function() {
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(() => {
this[fn](); // 兼容vue函数
}, delay);
};
}
/**
* 节流函数
* 当持续触发事件时,保证在一定时间内只调用一次事件处理函数
* 小于既定值,函数节流会每隔这个时间调用一次
*
* @param fn 执行函数
* @param delay 间隔时间
*/
function throttle(fn, delay){
let lastCall = 0;
let throttled = function() {
const now = new Date().getTime();
// remaining 不触发下一次函数的剩余时间
if (now - lastCall < delay && lastCall) return;
lastCall = now;
this[fn].apply(this, arguments);
}
return throttled;
}
/**
* 时间戳转换方法
*
* @param timestamp 时间戳
* @param format 时间格式
*/
function formatDate (timestamp, format = 'YYYY-MM-dd HH:mm:ss') {
let time = new Date(timestamp)
// 获取年月日时分秒,使用es6 padStart补0
let year = time.getFullYear()
const month = (time.getMonth() + 1).toString().padStart(2, '0')
const date = (time.getDate()).toString().padStart(2, '0')
const hours = (time.getHours()).toString().padStart(2, '0')
const minute = (time.getMinutes()).toString().padStart(2, '0')
const second = (time.getSeconds()).toString().padStart(2, '0')
// 替换时间格式
format = format
.replace('YYYY', year)
.replace('MM', month)
.replace('dd', date)
.replace('HH', hours)
.replace('mm', minute)
.replace('ss', second)
return format
}
// 数组去重
function dedupe (array){
return Array.from(new Set(array));
}
// 对象深克隆
function deepClone (o) {
// 判断如果不是引用类型,直接返回数据即可
if (typeof o === 'string' || typeof o === 'number' || typeof o === 'boolean' || typeof o === 'undefined') {
return o
} else if (Array.isArray(o)) { // 如果是数组,则定义一个新数组,完成复制后返回
// 注意,这里判断数组不能用typeof,因为typeof Array 返回的是object
var _arr = []
o.forEach(item => { _arr.push(item) })
return _arr
} else if (typeof o === 'object') {
var _o = {}
for (let key in o) {
_o[key] = deepClone(o[key])
}
return _o
}
}
/**
* 下划线转驼峰
* @param string
* @returns {*}
*/
export function underLine2CamelCase(string){
return string.replace( /_([a-z])/g, function( all, letter ) {
return letter.toUpperCase();
});
}
export {
debounce,
throttle,
formatDate,
dedupe,
deepClone,
underLine2CamelCase,
}