js工具函数
判断数据类型
Object.prototype.toString.call(5) // "[object Number]"
Object.prototype.toString.call('str') // "[object String]"
Object.prototype.toString.call(true) // "[object Boolean]"
Object.prototype.toString.call(undefined) // "[object Undefined]"
Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString.call(function () { }) // "[object Function]"
Object.prototype.toString.call([]) // "[object Array]"
Object.prototype.toString.call({}) // "[object Object]"
function checkDataType (value) {
const typeObj = Object.prototype.toString.call(value)
return typeObj.slice(8, -1)
}
完整深拷贝
function deepCopy1(obj, hash = new WeakMap()) {
// 日期对象直接返回一个新的日期对象
if (obj.constructor === Date) return new Date(obj)
// 正则对象直接返回一个新的正则对象
if (obj.constructor === RegExp) return new RegExp(obj)
// 如果循环引用了就用WeakMap解决
if (hash.has(obj)) return hash.get(obj)
// 遍历传图参数所有键的特性
let allDesc = Object.getOwnPropertyDescriptor(obj)
// 继承原型链
let copyObj = Object.create(Object.getPrototypeOf(obj), allDesc)
hash.set(obj, copyObj)
for (let key of Reflect.ownKeys(obj)) {
copyObj[key] = (isComplexDataType(obj[key]) && typeof obj[key] !== 'function') ? deepCopy(obj[key], hash) : obj[key]
}
function isComplexDataType(obj) {
return (typeof obj === 'object' || typeof obj === 'function') && obj !== null
}
return copyObj
}
格式化时间
/*
* 格式化时间
* 传入参数 date 被格式的时间,例如:var date = new Date();
* 传入参数 fmt 输出的时间格式,例如:yyyy-MM-dd
* 返回 格式化的时间
*/
function formatDate(date, fmt) {
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
}
let o = {
'M+': date.getMonth() + 1,
'd+': date.getDate(),
'h+': date.getHours(),
'm+': date.getMinutes(),
's+': date.getSeconds()
}
for (let k in o) {
if (new RegExp(`(${k})`).test(fmt)) {
let str = o[k] + ''
fmt = fmt.replace(RegExp.$1, RegExp.$1.length === 1 ? str : padLeftZero(str))
}
}
function padLeftZero(str) {
return ("00" + str).substr(str.length);
}
return fmt
}
格式化数值
/**
* 数值格式化
* @param number - 数值
* @param places - 保留小数位
* @param symbol - 前缀
* @param thousand - 分隔符
* @param decimal - 小数位符号
* @param isFormat
* @return {string}
*/
export function formatNumber (
number = 0,
places = 0,
symbol = '',
thousand = ',',
decimal = '.',
isFormat = true
) {
places = !isNaN((places = Math.abs(places))) ? places : 2
let negative = number < 0 ? '-' : ''
let i = parseInt((number = Math.abs(+number || 0).toFixed(places)), 10) + ''
let j = i.length > 3 ? i.length % 3 : 0
let num =
(j ? i.substr(0, j) + thousand : '') +
i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thousand) +
(places
? decimal +
Math.abs(number - i)
.toFixed(places)
.slice(2)
: '')
if (isFormat) {
num = num.match(/[\d,]+(?:\.\d*[1-9]+)?/)[0]
}
return symbol + negative + num
}
本地存储方法封装
class Storage {
constructor(o) {
this.o = o;
}
getItem(key) {
return JSON.parse(this.o.getItem(key)) || "";
}
setItem(key, value) {
this.o.setItem(key, JSON.stringify(value));
}
removeItem(key) {
this.o.removeItem(key);
}
clear() {
this.o.clear();
}
}
const { localStorage, sessionStorage } = window;
// lStorage是对localStorage的封装
export const lStorage = new Storage(localStorage);
// sStorage是对sessionStorage的封装
export const sStorage = new Storage(sessionStorage);
export default {
STORAGE_KEYS,
lStorage,
sStorage
};
window.resize事件封装
const resizeList = {}
const prefix = 'vue-resize-'
export const $resize = {
/**
* 注册监听
* @param name { String } - 自定义事件别名
* @param callback { Function } - 回调函数
* @param duration=100 可自定义间隔执行时间
*/
add: (name, callback, duration = 100) => {
const _name = prefix + name
let timer = ''
if (resizeList[_name]) {
console.error(name + ' already exists')
} else {
resizeList[_name] = () => {
if (timer) clearTimeout(timer)
timer = setTimeout(callback, duration)
}
window.addEventListener('resize', resizeList[_name])
}
},
/**
* 移除监听
* @param name 自定义事件别名
*/
remove: name => {
const _name = prefix + name
const resize = resizeList[_name]
if (resize) {
window.removeEventListener('resize', resize)
delete resizeList[_name]
}
}
}
轮播 + 鼠标滚动
/**
* 轮播 + 鼠标滚动
* @param {*} el 需要滚动的元素
* @param {*} distance 要滚动的距离
* @param {*} duration 单次滚动周期,默认值2000ms
* 注意:当滚动到底部时,可以根据条件触发`el.scrollTop = 0`复位后再次轮播
*/
export const handleScrollTop = (el, distance, duration = 2000) => {
const cosParameter = distance / 2
const cacheScrollTop = el.scrollTop
const requestAnimationFrame = window.requestAnimationFrame
let count = 0
let oldTimestamp = performance.now()
const step = newTimestamp => {
count += Math.PI / (duration / (newTimestamp - oldTimestamp))
if (count >= Math.PI) return
el.scrollTop = cacheScrollTop + Math.round(cosParameter - cosParameter * Math.cos(count))
oldTimestamp = newTimestamp
requestAnimationFrame(step)
}
requestAnimationFrame(step)
}
获取url附带的参数以及对应的值
/**
* @desc 获取url附带的参数以及对应的值
* @return {Object} obj 返回包含URL参数信息的对象
*/
function getRequest() {
var obj = {}
const { href } = window.location
const i = href.indexOf('?')
const str = href.substring(i + 1)
const arr = str.split('&')
for (var item of arr) {
let key = item.split('=')[0]
obj[key] = item.split('=')[1]
}
return obj
}
自定义的延时器,复写setTimeout方法
/**
* 自定义的延时器,复写setTimeout方法,优先使用requestAnimationFrame
*/
export const timeDelayFn = (fn, timeout) => {
let requestAnimationFrame = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame
if (requestAnimationFrame) {
// let s = new Date().getTime()
const tmpFn = (start, timeout) => {
if (new Date().getTime() - start < timeout) {
requestAnimationFrame(() => {
tmpFn(start, timeout)
})
}
}
} else {
window.setTimeout(fn, timeout)
}
}
计算方法封装
const Calc = {
/** 加法
* @param arg1 { number | string }
* @param arg2 { number | string }
* @Returns { Number }:两数相加的结果
*/
Add: function (arg1, arg2) {
arg1 = arg1.toString()
arg2 = arg2.toString()
let arg1Arr = arg1.split('.')
let arg2Arr = arg2.split('.')
let d1 = arg1Arr.length === 2 ? arg1Arr[1] : ''
let d2 = arg2Arr.length === 2 ? arg2Arr[1] : ''
let maxLen = Math.max(d1.length, d2.length)
let m = Math.pow(10, maxLen)
let result = Number(((arg1 * m + arg2 * m) / m).toFixed(maxLen))
let d = arguments[2]
return typeof d === 'number' ? Number(result.toFixed(d)) : result
},
/** 减法
* @param arg1 { number | string }
* @param arg2 { number | string }
* @Returns {number}: 两数相减的结果
*/
Sub: function (arg1, arg2) {
return this.Add(arg1, -Number(arg2), arguments[2])
},
/** 乘法
* @param arg1 { number | string }
* @param arg2 { number | string }
* @Returns {number}: 两数相乘的结果
*/
Mul: function (arg1, arg2) {
let r1 = arg1.toString()
let r2 = arg2.toString()
let m
let resultVal
let d = arguments[2]
m =
(r1.split('.')[1] ? r1.split('.')[1].length : 0) +
(r2.split('.')[1] ? r2.split('.')[1].length : 0)
resultVal = (Number(r1.replace('.', '')) * Number(r2.replace('.', ''))) / Math.pow(10, m)
return typeof d !== 'number' ? Number(resultVal) : Number(resultVal.toFixed(parseInt(d)))
},
/** 除法
* @param arg1 { number | string }
* @param arg2 { number | string }
* @Returns {number}: arg1除于arg2的结果
*/
Divs: function (arg1, arg2) {
let r1 = arg1.toString()
let r2 = arg2.toString()
let m
let resultVal
let d = arguments[2]
m =
(r2.split('.')[1] ? r2.split('.')[1].length : 0) -
(r1.split('.')[1] ? r1.split('.')[1].length : 0)
resultVal = (Number(r1.replace('.', '')) / Number(r2.replace('.', ''))) * Math.pow(10, m)
return typeof d !== 'number' ? Number(resultVal) : Number(resultVal.toFixed(parseInt(d)))
}
}
H5设定网页标题
/**
* @desc H5设定网页标题
* @param {String} title 标题
*/
function setTitle(title) {
document.title = title
// 利用iframe的onload事件刷新页面
const iframe = document.createElement('iframe')
iframe.style.visibility = 'hidden'
iframe.style.width = '1px'
iframe.style.height = '1px'
iframe.onload = () => {
setTimeout(() => {
document.body.removeChild(iframe)
}, 0)
}
document.body.appendChild(iframe)
}
下载文件
/**
* @desc 下载文件
* @param {String} data 二进制流文件
* @param {String} fileName 文件名
* @param {boolean} transformBlob 是否是Blob,默认不传无需转换
*/
export function download(data, fileName, transformBlob) {
const blob = !transformBlob ? data : dataURLtoBlob(data);
const blobUrl = window.URL.createObjectURL(blob);
// desc:兼容IE浏览器blob文件下载
if (navigator.msSaveOrOpenBlob) {
navigator.msSaveOrOpenBlob(blob, fileName);
} else {
const a = document.createElement("a");
a.style.display = "none";
a.href = blobUrl;
a.download = fileName;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(blobUrl);
}
}
base64转blob
/**
* @desc base64转blob
* @param {String} dataurl base64
* @return {Blob} blob
*/
export function dataURLtoBlob(data) {
const dataAtob = atob(data);
let dataLength = dataAtob.length;
const u8arr = new Uint8Array(dataLength);
while (dataLength--) {
u8arr[dataLength] = dataAtob.charCodeAt(dataLength);
}
return new Blob([u8arr]);
}