|
|
@@ -1,9 +1,3 @@
|
|
|
-/**
|
|
|
- * Parse the time to string
|
|
|
- * @param {(Object|string|number)} time
|
|
|
- * @param {string} cFormat
|
|
|
- * @returns {string | null}
|
|
|
- */
|
|
|
export function parseTime (time, cFormat) {
|
|
|
if (arguments.length === 0 || !time) {
|
|
|
return null
|
|
|
@@ -47,11 +41,6 @@ export function parseTime (time, cFormat) {
|
|
|
return time_str
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * @param {number} time
|
|
|
- * @param {string} option
|
|
|
- * @returns {string}
|
|
|
- */
|
|
|
export function formatTime (time, option) {
|
|
|
if (('' + time).length === 10) {
|
|
|
time = parseInt(time) * 1000
|
|
|
@@ -90,264 +79,109 @@ export function formatTime (time, option) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * @param {string} url
|
|
|
- * @returns {Object}
|
|
|
- */
|
|
|
-export function getQueryObject (url) {
|
|
|
- url = url == null ? window.location.href : url
|
|
|
- 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
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @param {string} input value
|
|
|
- * @returns {number} output value
|
|
|
- */
|
|
|
-export function byteLength (str) {
|
|
|
- // returns the byte length of an utf8 string
|
|
|
- let s = str.length
|
|
|
- for (var i = str.length - 1; i >= 0; i--) {
|
|
|
- const code = str.charCodeAt(i)
|
|
|
- if (code > 0x7f && code <= 0x7ff) s++
|
|
|
- else if (code > 0x7ff && code <= 0xffff) s += 2
|
|
|
- if (code >= 0xDC00 && code <= 0xDFFF) i--
|
|
|
- }
|
|
|
- return s
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @param {Array} actual
|
|
|
- * @returns {Array}
|
|
|
- */
|
|
|
-export function cleanArray (actual) {
|
|
|
- const newArray = []
|
|
|
- for (let i = 0; i < actual.length; i++) {
|
|
|
- if (actual[i]) {
|
|
|
- newArray.push(actual[i])
|
|
|
- }
|
|
|
- }
|
|
|
- return newArray
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @param {Object} json
|
|
|
- * @returns {Array}
|
|
|
- */
|
|
|
-export function param (json) {
|
|
|
- if (!json) return ''
|
|
|
- return cleanArray(
|
|
|
- Object.keys(json).map(key => {
|
|
|
- if (json[key] === undefined) return ''
|
|
|
- return encodeURIComponent(key) + '=' + encodeURIComponent(json[key])
|
|
|
- })
|
|
|
- ).join('&')
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @param {string} url
|
|
|
- * @returns {Object}
|
|
|
- */
|
|
|
-export function param2Obj (url) {
|
|
|
- const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
|
|
|
- if (!search) {
|
|
|
- return {}
|
|
|
- }
|
|
|
- const obj = {}
|
|
|
- const searchArr = search.split('&')
|
|
|
- searchArr.forEach(v => {
|
|
|
- const index = v.indexOf('=')
|
|
|
- if (index !== -1) {
|
|
|
- const name = v.substring(0, index)
|
|
|
- const val = v.substring(index + 1, v.length)
|
|
|
- obj[name] = val
|
|
|
- }
|
|
|
- })
|
|
|
- return obj
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @param {string} val
|
|
|
- * @returns {string}
|
|
|
- */
|
|
|
-export function html2Text (val) {
|
|
|
- const div = document.createElement('div')
|
|
|
- div.innerHTML = val
|
|
|
- return div.textContent || div.innerText
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * Merges two objects, giving the last one precedence
|
|
|
- * @param {Object} target
|
|
|
- * @param {(Object|Array)} source
|
|
|
- * @returns {Object}
|
|
|
- */
|
|
|
-export function objectMerge (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] = objectMerge(target[property], sourceProperty)
|
|
|
- } else {
|
|
|
- target[property] = sourceProperty
|
|
|
- }
|
|
|
- })
|
|
|
- return target
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @param {HTMLElement} element
|
|
|
- * @param {string} className
|
|
|
- */
|
|
|
-export function toggleClass (element, className) {
|
|
|
- if (!element || !className) {
|
|
|
- return
|
|
|
- }
|
|
|
- let classString = element.className
|
|
|
- const nameIndex = classString.indexOf(className)
|
|
|
- if (nameIndex === -1) {
|
|
|
- classString += '' + className
|
|
|
- } else {
|
|
|
- classString =
|
|
|
- classString.substr(0, nameIndex) +
|
|
|
- classString.substr(nameIndex + className.length)
|
|
|
- }
|
|
|
- element.className = classString
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @param {string} type
|
|
|
- * @returns {Date}
|
|
|
- */
|
|
|
-export function getTime (type) {
|
|
|
- if (type === 'start') {
|
|
|
- return new Date().getTime() - 3600 * 1000 * 24 * 90
|
|
|
- }
|
|
|
- return new Date()
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @param {Function} func
|
|
|
- * @param {number} wait
|
|
|
- * @param {boolean} immediate
|
|
|
- * @return {*}
|
|
|
- */
|
|
|
-export function debounce (func, wait, immediate) {
|
|
|
- let timeout, args, context, timestamp, result
|
|
|
+export function debounce (fn, wait, immediate) {
|
|
|
+ let timeout, context, args, timestamp
|
|
|
|
|
|
const later = function () {
|
|
|
// 据上一次触发时间间隔
|
|
|
- const last = +new Date() - timestamp
|
|
|
+ const last = Date.now() - timestamp
|
|
|
|
|
|
// 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
|
|
|
- if (last < wait && last > 0) {
|
|
|
+ if (last < wait) {
|
|
|
timeout = setTimeout(later, wait - last)
|
|
|
} else {
|
|
|
- timeout = null
|
|
|
- // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
|
|
|
if (!immediate) {
|
|
|
- result = func.apply(context, args)
|
|
|
- if (!timeout) context = args = null
|
|
|
+ fn.apply(context, args)
|
|
|
}
|
|
|
+ timeout = context = args = null
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return function (...args) {
|
|
|
+ return function (...params) {
|
|
|
+ timestamp = Date.now()
|
|
|
context = this
|
|
|
- timestamp = +new Date()
|
|
|
- const callNow = immediate && !timeout
|
|
|
+ args = params
|
|
|
// 如果延时不存在,重新设定延时
|
|
|
- if (!timeout) timeout = setTimeout(later, wait)
|
|
|
- if (callNow) {
|
|
|
- result = func.apply(context, args)
|
|
|
- context = args = null
|
|
|
+ if (!timeout) {
|
|
|
+ timeout = setTimeout(later, wait)
|
|
|
+ if (immediate) {
|
|
|
+ fn.apply(context, args)
|
|
|
+ context = params = null
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
- return result
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * This is just a simple version of deep copy
|
|
|
- * Has a lot of edge cases bug
|
|
|
- * If you want to use a perfect deep copy, use lodash's _.cloneDeep
|
|
|
- * @param {Object} source
|
|
|
- * @returns {Object}
|
|
|
- */
|
|
|
-export function deepClone (source) {
|
|
|
- if (!source && typeof source !== 'object') {
|
|
|
- throw new Error('error arguments', 'deepClone')
|
|
|
+export function throttle (func, wait, options) {
|
|
|
+ let timeout, context, args
|
|
|
+
|
|
|
+ // 上一次执行回调的时间戳
|
|
|
+ let previous = 0
|
|
|
+
|
|
|
+ // 无传入参数时,初始化 options 为空对象
|
|
|
+ if (!options) {
|
|
|
+ options = {}
|
|
|
}
|
|
|
- const targetObj = source.constructor === Array ? [] : {}
|
|
|
- Object.keys(source).forEach(keys => {
|
|
|
- if (source[keys] && typeof source[keys] === 'object') {
|
|
|
- targetObj[keys] = deepClone(source[keys])
|
|
|
- } else {
|
|
|
- targetObj[keys] = source[keys]
|
|
|
- }
|
|
|
- })
|
|
|
- return targetObj
|
|
|
-}
|
|
|
|
|
|
-/**
|
|
|
- * @param {Array} arr
|
|
|
- * @returns {Array}
|
|
|
- */
|
|
|
-export function uniqueArr (arr) {
|
|
|
- return Array.from(new Set(arr))
|
|
|
-}
|
|
|
+ const later = function () {
|
|
|
+ // 当设置 { leading: false } 时
|
|
|
+ // 每次触发回调函数后设置 previous 为 0
|
|
|
+ // 不然为当前时间
|
|
|
+ previous = options.leading === false ? 0 : Date.now()
|
|
|
|
|
|
-/**
|
|
|
- * @returns {string}
|
|
|
- */
|
|
|
-export function createUniqueString () {
|
|
|
- const timestamp = +new Date() + ''
|
|
|
- const randomNum = parseInt((1 + Math.random()) * 65536) + ''
|
|
|
- return (+(randomNum + timestamp)).toString(32)
|
|
|
-}
|
|
|
+ // 执行函数
|
|
|
+ func.apply(context, args)
|
|
|
|
|
|
-/**
|
|
|
- * Check if an element has a class
|
|
|
- * @param {HTMLElement} elm
|
|
|
- * @param {string} cls
|
|
|
- * @returns {boolean}
|
|
|
- */
|
|
|
-export function hasClass (ele, cls) {
|
|
|
- return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
|
|
|
-}
|
|
|
+ timeout = context = args = null
|
|
|
+ }
|
|
|
|
|
|
-/**
|
|
|
- * Add class to element
|
|
|
- * @param {HTMLElement} elm
|
|
|
- * @param {string} cls
|
|
|
- */
|
|
|
-export function addClass (ele, cls) {
|
|
|
- if (!hasClass(ele, cls)) ele.className += ' ' + cls
|
|
|
-}
|
|
|
+ // 每次触发事件回调都执行这个函数
|
|
|
+ // 函数内判断是否执行 func
|
|
|
+ // func 才是我们业务层代码想要执行的函数
|
|
|
+ return function (...params) {
|
|
|
+ // 记录当前时间
|
|
|
+ const now = Date.now()
|
|
|
+
|
|
|
+ // 第一次执行时(此时 previous 为 0,之后为上一次时间戳)
|
|
|
+ // 并且设置了 { leading: false }(表示第一次回调不执行)
|
|
|
+ // 此时设置 previous 为当前值,表示刚执行过,本次就不执行了
|
|
|
+ if (!previous && options.leading === false) {
|
|
|
+ previous = now
|
|
|
+ }
|
|
|
+
|
|
|
+ // 距离下次触发 func 还需要等待的时间
|
|
|
+ const remaining = wait - (now - previous)
|
|
|
+ context = this
|
|
|
+ args = params
|
|
|
+
|
|
|
+ // 要么是到了间隔时间了,随即触发方法(remaining <= 0)
|
|
|
+ // 要么是没有传入 {leading: false},且第一次触发回调,即立即触发
|
|
|
+ // 此时 previous 为 0,wait - (now - previous) 也满足 <= 0
|
|
|
+ // 之后便会把 previous 值迅速置为 now
|
|
|
+ if (remaining <= 0 || remaining > wait) {
|
|
|
+ if (timeout) {
|
|
|
+ clearTimeout(timeout)
|
|
|
+
|
|
|
+ // clearTimeout(timeout) 并不会把 timeout 设为 null
|
|
|
+ // 手动设置,便于后续判断
|
|
|
+ timeout = null
|
|
|
+ }
|
|
|
|
|
|
-/**
|
|
|
- * Remove class from element
|
|
|
- * @param {HTMLElement} elm
|
|
|
- * @param {string} cls
|
|
|
- */
|
|
|
-export function removeClass (ele, cls) {
|
|
|
- if (hasClass(ele, cls)) {
|
|
|
- const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')
|
|
|
- ele.className = ele.className.replace(reg, ' ')
|
|
|
+ // 设置 previous 为当前时间
|
|
|
+ previous = now
|
|
|
+
|
|
|
+ // 执行 func 函数
|
|
|
+ func.apply(context, args)
|
|
|
+ if (!timeout) {
|
|
|
+ context = args = null
|
|
|
+ }
|
|
|
+ } else if (!timeout && options.trailing !== false) {
|
|
|
+ // 最后一次需要触发的情况
|
|
|
+ // 如果已经存在一个定时器,则不会进入该 if 分支
|
|
|
+ // 如果 {trailing: false},即最后一次不需要触发了,也不会进入这个分支
|
|
|
+ // 间隔 remaining milliseconds 后触发 later 方法
|
|
|
+ timeout = setTimeout(later, remaining)
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|