import moment from 'moment'
import XEUtils from 'xe-utils'
// 切割url
function splitUrl(url) {
return url.split('?')[0]
}
function toArrayTree(list, options) {
return XEUtils.toArrayTree(list, options)
}
/**
* 日期时间格式化
* @param {date} time js的date类型或时间戳
* @param {string} format 自定义时间格式,选填,默认为'{y}-{m}-{d} {h}:{i}:{s}'
* @return {string} 默认格式 2018-09-01 10:55:00
*/
function formatDate(time, format) {
time = time || new Date()
format = format || '{y}-{m}-{d}'
let date = time
if (typeof time !== 'object') {
if (('' + time).length === 10) time = +time * 1000
date = new Date(time)
}
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate(),
h: date.getHours(),
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay()
}
const timeStr = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
let value = formatObj[key]
if (key === 'a') return ['一', '二', '三', '四', '五', '六', '日'][value - 1]
if (result.length > 0 && value < 10) {
value = '0' + value
}
return value || 0
})
return timeStr
}
/**
* 日期格式转时间戳
* @param {date} date date类型 2019-05-24 14:22:17
* @return {string} 1558678937000
*/
function getTimestamp(date) {
if (!date) {
return new Date().getTime()
}
if (typeof date === 'string') {
date = date.replace(/-/g, '/')
}
return new Date(date).getTime()
}
/**
* 日期格式转换成和当前时间相比剩余天数
* @param {date} startDate 开始时间点 startDate类型 2020-08-26 10:48:36,该参数不存在时,开始时间点为当前时间
* @param {date} endDate 结束时间点 endDate类型 2020-08-26 10:57:36
* @return {string} number 数字n
*/
function getRemainDay(endDate, startDate) {
if (typeof endDate === 'string') {
// "-" 移动端ios部分机型不识别,需要转化
endDate = endDate.replace(/-/g, '/')
}
if (startDate && typeof startDate === 'string') {
// "-" 移动端ios部分机型不识别,需要转化
startDate = startDate.replace(/-/g, '/')
}
const curr = startDate ? new Date(startDate).getTime() : new Date().getTime()
const end = new Date(endDate).getTime()
const cha = Math.ceil((end - curr) / 1000 / 3600 / 24)
return cha
}
/**
* 获取7天前的 00:00:00 至当天的前一天 23:59:59
* 例如: 2020-10-14 11:01:36 ==> ["2020-10-07 00:00:00","2020-10-13 23:59:59"]
* @return {array} ["2020-10-07 00:00:00","2020-10-13 23:59:59"]
*/
function getWeekAgo() {
const currTs = new Date(new Date().toLocaleDateString()).getTime()
const startTime = formatDate(currTs - 24 * 60 * 60 * 7 * 1000)
const endTime = formatDate(currTs - 1000)
return [startTime, endTime]
}
/**
*获取当前时间的字符串形式
*例如2020-10-14 ==》 20201014
* @param {date} date date类型 2019-05-24 14:22:17
* @return {string}
*/
function dateToString(date) {
const year = date.getFullYear()
let month = (date.getMonth() + 1).toString()
let day = (date.getDate()).toString()
if (month.length === 1) {
month = '0' + month
}
if (day.length === 1) {
day = '0' + day
}
const dateTime = `${year}${month}${day}`
return dateTime
}
/**
* 最近多少天
* @param {number} days 默认30天
* @param {string} format 自定义时间类型,默认 '{y}-{m}-{d}', '{y}-{m}-{d} {h}:{i}:{s}'
* @return {array} ['2020-10-01','2020-10-14']
*/
function getLatelyDays(days, startDate, format) {
days = days || 30
format = format || '{y}-{m}-{d}'
// let currTs = new Date(new Date().toLocaleDateString()).getTime()
const currTs = getTimestamp(formatDate(new Date(), format))
const startTime = startDate || formatDate(currTs, format)
const endTime = formatDate(currTs + 24 * 60 * 60 * days * 1000, format)
return [startTime, endTime]
}
/**
* 日期时间文字化
* 比较传入时间与当前本地时间,文字化显示日期时间
* @param {date} time js的date类型或时间戳
* @param {string} cFormat 自定义两天前的时间格式,选填
* @return {string} 刚刚 n分钟前 n小时前 1天前
*/
function txtFormatTime(time, format) {
if (!time) {
return 'null'
}
const d = new Date(time)
const now = Date.now()
const diff = (now - d) / 1000
if (diff < 30) {
return '刚刚'
} else if (diff < 3600) {
// less 1 hour
return Math.ceil(diff / 60) + '分钟前'
} else if (diff < 3600 * 24) {
return Math.ceil(diff / 3600) + '小时前'
} else if (diff < 3600 * 24 * 2) {
return '1天前'
} else {
return formatDate(time, format)
}
}
/**
* 得到开始和结束日期,得到中间所有天返回数组
* @param {String} string 开始日期'2021-7-1'
* @param {String} String 结束日期'2021-8-1'
* @return {Array} ['2021-07-01', '2021-07-01'...., '2021-08-01']
*/
function getDayArr(startDay, endDay) {
let startVal = moment(new Date(startDay)).format('YYYY-MM-DD')
const dayArr = []
while (moment(startVal).isBefore(endDay)) {
dayArr.push(startVal)
// 自增
startVal = moment(new Date(startVal)).add(1, 'day').format('YYYY-MM-DD')
}
// 将结束日期的天放进数组
dayArr.push(moment(new Date(endDay)).format('YYYY-MM-DD'))
return dayArr
}
/**
* 对象参数序列化
* @param {object} obj 对象参数
* @return {string} a=1&b=2&c=3
*/
function objToUrlParams(obj) {
let str = ''
Object.keys(obj).forEach(v => {
if (obj[v] !== undefined) {
str += `${encodeURIComponent(v)}=${encodeURIComponent(obj[v])}&`
}
})
return str.slice(0, -1)
}
/**
* 获取地址参数
* @param {string} url 指定地址,默认取当前页地址
* @return {string} { a: 1, b: 2, c: 3 }
*/
function getQueryObject(url) {
url = url || window.location.href
const search = url.substring(url.lastIndexOf('?') + 1)
const obj = {}
const reg = /([^?&=]+)=([^?&=]*)/g
search.replace(reg, (rs, $1, $2) => {
const name = decodeURIComponent($1)
let val = decodeURIComponent($2)
val = String(val)
obj[name] = val
return rs
})
return obj
}
/**
* 创建唯一的字符串
* @return {string} ojgdvbvaua40
*/
function createUniqueString() {
const timestamp = +new Date() + ''
const randomNum = parseInt((1 + Math.random()) * 65536) + ''
return (+(randomNum + timestamp)).toString(32)
}
/**
* 文件下载
* @param {string} url 文件下载链接url,带上接口参数
* @param {string} name 前端自定义的下载文件名,带上文件后缀名,选填
* chrome会优先使用接口返回的命名,edge会优先使用此name
*/
function downloadFile(url, name) {
url = url || ''
name = name || ''
const ele = document.createElement('a')
ele.target = '_blank'
ele.href = url
ele.download = name
document.body.appendChild(ele)
ele.click()
document.body.removeChild(ele)
}
/**
* 获取字符串的字节长度
* @param {String} str 字符串
* @returns {number} 字节长度
*/
function getByteLength(str) {
let len = 0
for (let i = 0; i < str.length; i++) {
// eslint-disable-next-line
if (str[i].match(/[^\x00-\xff]/gi) != null) {
len += 2
} else {
len += 1
}
}
return len
}
/**
* 数字千分化
* @param {number} num 数字
* @return {number} 10,000
*/
function toThousands(num) {
return (+num || 0).toString().replace(/^-?\d+/g, m => m.replace(/(?=(?!\b)(\d{3})+$)/g, ','))
}
/**
* 数字存储大小格式化
* @param {number} num 存储大小 单位:Byte
* @param {number} digits 保留几位小数
* @return {string} 2MB
*/
function toStorage(num, digits) {
digits = digits || 2
if (num < 1024) {
return num + 'B'
}
num = (num * 1000) / 1024
const si = [
{ value: 1e18, symbol: 'E' },
{ value: 1e15, symbol: 'P' },
{ value: 1e12, symbol: 'T' },
{ value: 1e9, symbol: 'G' },
{ value: 1e6, symbol: 'M' },
{ value: 1e3, symbol: 'K' }
]
for (let i = 0; i < si.length; i++) {
if (num >= si[i].value) {
return (
(num / (si[i].value * 1.024)).toFixed(digits).replace(/\.0+$|(\.[0-9]*[1-9])0+$/, '$1') + si[i].symbol + 'B'
)
}
}
}
/**
* 函数防抖
* @param {function} fn 函数
* @param {number} t 等待时间(毫秒)
* @return {function}
*/
function debounce(fn, t = 500) {
return XEUtils.debounce(fn, t, {
leading: true,
trailing: false
})
}
/**
* 函数节流
* @param {function} fn 函数
* @param {number} t 间隔时间(毫秒)
* @return {function}
*/
function throttle(fn, t) {
let timeId
let firstTime = true
const interval = t || 500
return function() {
const args = arguments
if (firstTime) {
fn.apply(this, args)
firstTime = false
return
}
if (timeId) {
return
}
timeId = setTimeout(() => {
clearTimeout(timeId)
timeId = null
fn.apply(this, args)
}, interval)
}
}
/**
* 深克隆
* @param {object|array} 源数据
* @return {object|array}
*/
function deepClone(source) {
return XEUtils.clone(source, true)
}
/**
* 遍历树的方法
* @tree {array} 源数据
*/
function filterTree(tree, fn) {
return XEUtils.filterTree(tree, fn)
}
/**
* 获取数据类型
* @param {any} data 数据
* @return {string} 'array'
*/
function getDataType(data) {
const str = Object.prototype.toString.call(data)
return str.match(/\s(\w*)\]/)[1].toLowerCase()
}
/**
* 对象合并 (对象属性深度合并,其他属性覆盖更新(a覆盖b))
* @param {object} a 对象
* @param {object} b 对象
* @return {object} 合并后的对象 (新)
*/
function objectMerge(a, b) {
const obj = JSON.parse(JSON.stringify(a))
return (function merge(target, source) {
if (typeof target !== 'object') {
target = {}
}
if (Array.isArray(source)) {
return source.slice()
}
Object.keys(source).forEach(property => {
const sourceProperty = source[property]
if (typeof sourceProperty === 'object') {
target[property] = merge(target[property], sourceProperty)
} else {
target[property] = sourceProperty
}
})
return target
})(obj, b)
}
/**
* 获取日期范围内的所有日期项
* @param {string} type 'day'按天 'month'按月
* @param {array} range 日期范围,第一项为开始日期,第二项为结束日期(可选,不传时默认30天或者12个月)
* @return {array} 该范围内的所有日期项数组
*/
function getDateRangeItems(type, range) {
const arr = []
let start, end, times
if (type === 'day') {
// 按天
if (!range || range.length === 0) {
start = new Date()
end = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 29)
} else {
start = new Date(range[0])
end = new Date(range[1])
}
times = (end.getFullYear() - start.getFullYear() + 1) * 366
for (let i = 0; i < times; i++) {
arr.push(formatDate(start, '{y}-{m}-{d}'))
if (formatDate(start, '{y}-{m}-{d}') === formatDate(end, '{y}-{m}-{d}')) {
break
}
start.setTime(start.getTime() + 3600 * 1000 * 24)
}
} else if (type === 'month') {
// 按月
if (!range || range.length === 0) {
start = new Date()
end = new Date()
start.setMonth(start.getMonth() - 11)
} else {
start = new Date(range[0])
end = new Date(range[1])
}
times = (end.getFullYear() - start.getFullYear() + 1) * 12
for (let i = 0; i < times; i++) {
arr.push(formatDate(start, '{y}-{m}'))
if (formatDate(start, '{y}-{m}') === formatDate(end, '{y}-{m}')) {
break
}
start.setMonth(start.getMonth() + 1)
}
}
return arr
}
/**
* 对象数组转换成带有children属性的对象数组
* @param {array} list 数据源
* @param {string} pAttr 参照属性名
* @param {string} cAttr 比较属性名
* @param {number | string} 参照属性名对应的属性值
* @return {array}
*/
export function treeData(list, pAttr, cAttr, pAttrVal) {
const pList = []
const cList = []
list.map(val => {
if (val[cAttr] !== pAttrVal) {
cList.push(val)
} else {
pList.push({ children: [], ...val })
}
})
pList.map((val, index) => {
pList[index].children = cList.filter(c => c[cAttr] === val[pAttr])
})
return pList
}
/**
* 文件转base64
* @param {object} file 数据源
* @return {array}
*/
export function getBase64(file) {
return new Promise(function(resolve, reject) {
const reader = new FileReader()
let imgResult = ''
reader.readAsDataURL(file)
reader.onload = function() {
imgResult = reader.result
}
reader.onerror = (error) => {
reject(error)
}
reader.onloadend = () => {
resolve(imgResult)
}
})
}
/**
* 通过字节动态计算input长度
* @param {String} str 数据源输入文本
* @param {Number} length 想要限制文本的长度
* @return { calcLength, flag, newStr } calcLength计算的长度 flag触发超出长度的标识 newStr新生成的文本
*/
export function getLength(str, length) {
let calcLength = 0
let flag = ''
const content = str
let newStr = ''
for (let i = 0; i < content.length; i++) {
if (content[i].charCodeAt() > 0 && content[i].charCodeAt() < 255) {
calcLength += 1
} else {
calcLength += 2
}
if (calcLength <= length) {
newStr += content[i].charAt()
}
}
flag = calcLength > length
return { calcLength, flag, newStr }
}
/**
* 字符串转bytes
* @param {String} str 数据源输入文本
* @return {Array} bytes字节流数组
*/
export function stringToByte(str) {
const blockSize = 16
const bytes = []
let c
const len = str.length
for (let i = 0; i < len; i++) {
c = str.charCodeAt(i)
if (c >= 0x010000 && c <= 0x10FFFF) {
bytes.push(((c >> 18) & 0x07) | 0xF0)
bytes.push(((c >> 12) & 0x3F) | 0x80)
bytes.push(((c >> 6) & 0x3F) | 0x80)
bytes.push((c & 0x3F) | 0x80)
} else if (c >= 0x000800 && c <= 0x00FFFF) {
bytes.push(((c >> 12) & 0x0F) | 0xE0)
bytes.push(((c >> 6) & 0x3F) | 0x80)
bytes.push((c & 0x3F) | 0x80)
} else if (c >= 0x000080 && c <= 0x0007FF) {
bytes.push(((c >> 6) & 0x1F) | 0xC0)
bytes.push((c & 0x3F) | 0x80)
} else {
bytes.push(c & 0xFF)
}
}
if (bytes.length % blockSize !== 0) {
bytes.length += blockSize - bytes.length % blockSize
}
return bytes
}
/**
* 获取当前日期
* @return {Array} 日期和星期数的集合
*/
export const getNowFormatDate = _ => {
const date = new Date()
const year = date.getFullYear()
let month = date.getMonth() + 1
let nowDate = date.getDate()
const day = date.getDay()
const h = date.getHours()
const m = date.getMinutes() < 10 ? ('0' + date.getMinutes()) : date.getMinutes()
month = month < 10 ? '0' + month : month
nowDate = nowDate < 10 ? '0' + nowDate : nowDate
const formatDate = `${year}年${month}月${nowDate}日`
const week = '星期' + '日一二三四五六'.charAt(day)
const time = h + ':' + m
return {formatDate, week, time}
}
/**
* byte转字符串
* @param {Array} arr 数据源输入文本
* @return {String} 字符串
*/
export function byteToString(arr) {
if (typeof arr === 'string') {
return arr
}
let str = ''
const _arr = arr
for (let i = 0; i < _arr.length; i++) {
if (_arr[i]) {
const one = _arr[i].toString(2)
const v = one.match(/^1+?(?=0)/)
if (v && one.length === 8) {
const bytesLength = v[0].length
let store = _arr[i].toString(2).slice(7 - bytesLength)
for (let st = 1; st < bytesLength; st++) {
store += _arr[st + i].toString(2).slice(2)
}
str += String.fromCharCode(parseInt(store, 2))
i += bytesLength - 1
} else {
str += String.fromCharCode(_arr[i])
}
}
}
return str
}
export default {
// 处理url
splitUrl,
// 数组转树结构
toArrayTree,
// 日期时间格式化
formatDate,
// 日期格式转时间戳
getTimestamp,
// 日期格式转化成剩余时间n天
getRemainDay,
// 日期时间文字化
txtFormatTime,
// 获取时间字符串形式
dateToString,
// 获取间隔时间
getDayArr,
// 对象参数序列化
objToUrlParams,
// 获取地址参数
getQueryObject,
// 创建唯一的字符串
createUniqueString,
// 文件下载
downloadFile,
// 获取字符串的字节长度
getByteLength,
// 数字千分化
toThousands,
// 数字存储大小格式化
toStorage,
// 函数防抖
debounce,
// 函数节流
throttle,
// 深克隆
deepClone,
// 获取数据类型
getDataType,
// 对象合并
objectMerge,
// 获取日期范围内的所有日期项
getDateRangeItems,
// 获取一周前零点至今天的前一天23:59:59
getWeekAgo,
// 获取最近n天
getLatelyDays,
//
treeData,
// 文件转为base64
getBase64,
// 通过字节动态计算input长度
getLength,
// 字符串转byte
stringToByte,
// byte转字符串
byteToString,
// 树结构数据循环
filterTree
}
常用工具方法总结
于 2022-02-15 14:22:44 首次发布