url参数序列化
/** * json序列化为URLencode * @return {string} */ let json_to_URLencode = json => { return Object.keys(json) .map(function(key) { return encodeURIComponent(key) + '=' + encodeURIComponent(json[key]); }) .join('&'); }; console.log('www.baidu.com?' + json_to_URLencode({ name: 'kaka', age: 18 })); /** * URL 参数序列化 * @param { String } baseURL :url地址 * @param { Object } params :参数对象 * @return string: 参数序列化后的字符串 */ const ParamSerialize = function(baseURL, params) { return Object.keys(params).reduce((pre, cur) => (pre += (pre === baseURL ? '?' : '&') + `${cur}=${params[cur]}`), baseURL); }; ParamSerialize('www.baidu.com', { name: '', age: 19 }); //www.baidu.com?name=&age=19 ParamSerialize('www.baidu.com', { name: 'wuming', age: '' }); //www.baidu.com?name=wuming&age= ParamSerialize('www.baidu.com', { name: 'wuming', age: 19 }); //www.baidu.com?name=wuming&age=19 ParamSerialize('www.baidu.com', {}); //www.baidu.com
url参数获取
/** * 获取url参数 * ie不兼容解决:npm install url-search-params-polyfill * 在index.js中引入 import 'url-search-params-polyfill'; * **/ let location = new URL('http://www.baidu.com?name=ronle'); console.log(new URLSearchParams(location.search).get('name')); // 如果是哈希路由 let url = 'http://www.baidu.com/#/?name=ronle'; let location = new URL(url.split('#')[0] + url.split('#')[1]); console.log(new URLSearchParams(location.search).get('name')); /** * URL 参数获取 * @param { String } url :url地址 可选,不传则默认值是window.location.href * @return object */ const getUrlParms = function(url) { return (url ? url : location.href).includes('?') ? (url ? url : location.href) .split('?')[1] .match(/([^&=]*)=([^&]*)/g) .reduce((pre, cur) => { pre[cur.split('=')[0]] = cur.split('=')[1]; return pre; }, {}) : {}; }; //测试用例 getUrlParms('www.baidu.com?name=&age=19'); //{name: "", age: "19"} getUrlParms('www.baidu.com?name=wuming&age='); //{name: "ronle", age: ""} getUrlParms('www.baidu.com?name=wuming&age=19'); //{name: "ronle", age: "19"} getUrlParms('www.baidu.com'); //{} getUrlParms(); //当前页面的window.location.href = 'www.baidu.com?name=ronle&age=29',则返回 {name: "wuming", age: "19"} getUrlParms(); //当前页面的window.location.href = 'www.baidu.com',则返回 {}
url模板格式化
/** * 请求相关: * * @param {String} URL: 模板路径,例:'/uap/msg/announcementRecord/{sysId}/{tenantId}/{userId}' 或 '/uap/msg/announcementRecord' * @param {Object} params: 传入的参数,包含路径参数 或 不包含 * @param {Boolean} flag:是否拼接路径和查询参数 * * PS:flag为true时,一定是GET请求,GET请求才会拼接参数到URL后面 */ function getFormatUrl(URL, params, flag = false) { let url = /{(w+)}/g.test(URL) ? URL.replace(/{(w+)}/g, (a, b) => { let tmp = params[b]; delete params[b]; return tmp; }) : URL; return flag ? Object.keys(params).reduce((pre, cur) => (pre += (pre === url ? '?' : '&') + `${cur}=${params[cur]}`), url) : url; } //测试用例 getFormatUrl('/uap/msg/announcementRecord/{sysId}/{tenantId}/{userId}', { sysId: '001', tenantId: '002', userId: '003', username: 'wuming', age: 39 }); //输出:/uap/msg/announcementRecord/001/002/003 getFormatUrl( '/uap/msg/announcementRecord/{sysId}/{tenantId}/{userId}', { sysId: '001', tenantId: '002', userId: '003', username: 'wuming', age: 39 }, true ); //输出:/uap/msg/announcementRecord/001/002/003?username=wuming&age=39 getFormatUrl('/uap/msg/announcementRecord', {}); // 输出:/uap/msg/announcementRecord getFormatUrl('/api/getUerInfo/{userId}/{roleId}', { userId: 12, roleId: 33 }); //输出:api/getUerInfo/12/33 getFormatUrl('/api/getUerInfo/{userId}/{roleId}', { userId: 12, roleId: 33, extraParam: '555' }); //输出:api/getUerInfo/12/33 getFormatUrl('/api/getUerInfo/{userId}/{roleId}', { userId: 12, roleId: 33, extraParam: '555' }, true); //输出:/api/getUerInfo/12/33?extraParam=555 console.log(getFormatUrl('/api/getUerInfo/{userId}/{roleId}', { userId: 12, roleId: 33, extraParam: '555' }, true));
随机字符串
/** * 生成随机字符串 * @param {Number} len 随机字符串的长度 随机不重复字符串长度最大为62 * @param {Boolean} isRepeat 是否重复 默认true * @return 长度为len的随机字符串 */ const randomStr = function(count, isRepeat = true) { var strArr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'.split(''), res = ''; var _count = isRepeat === true ? count : count > 62 ? 62 : count; while (res.length < _count) { var random = Math.floor(Math.random() * 62); if (isRepeat) { res += strArr[random]; } else { if (!res.includes(strArr[random])) { res += strArr[random]; } } } return res; }; //测试用例 randomStr(10); randomStr(10, false); randomStr(5); randomStr(63, false); randomStr(100);
随机数
/** * 生成随机数 * @param {Number | Object} start 范围起始数字 * @param {Number} end 范围终止数字 * @param {Number} count 随机数个数 * @param {Boolean} isRepeat 是否重复 * @return 随机数数组 */ const randomNum = function(start, end, count, isRepeat = true) { let _isRepeat = true; if (arguments.length === 1 && arguments[0] !== null && typeof arguments[0] === 'object') { let { start, end, count, ...reset } = arguments[0]; _isRepeat = reset.isRepeat === undefined ? true : reset.isRepeat === false ? false : reset.isRepeat; } else { _isRepeat = isRepeat; } let _arr = []; let _max_count = isRepeat ? count : end - start + 1; let _count = count > _max_count ? _max_count : count; while (_arr.length < _count) { let random = Math.ceil(Math.random() * end); let _condition = random >= start && random <= end; if (_condition) { if (_isRepeat) { _arr.push(random); } else { !_arr.includes(random) && _arr.push(random); } } } return _arr; }; //测试用例 randomNum(10, 20, 10); randomNum(0, 9, 1); randomNum(0, 9, 0); randomNum(90, 100, 5, false);
基于当前 / 指定时间的 过去 n 天时间(包含当天日期)
/** * 生成 基于当前 / 指定时间的 过去 n 天时间(包含当天日期) * @param {Number} days 基于当前 / 指定时间的 过去 n 天时间(包含当天日期) * @param {Boolean} s 指定时间 * @return string[] 日期数组 */ const passDaysDate = function(days, s) { if (!arguments.length) return []; return [...Array(days + 1).keys()] .map(days => new Date((s ? new Date(s) : Date.now()) - 86400000 * days).toLocaleDateString()) .map(item => item .split(//|-/) .map(i => i.padStart(2, '0')) .join('-') ) .splice(1); }; //测试用例 passDaysDate(); //[] passDaysDate(3, '2020/3/13'); //["2020-03-12", "2020-03-11", "2020-03-10"] passDaysDate(3); //["2020-03-14", "2020-03-13", "2020-03-12"] passDaysDate(3, 1530975600000); // 13位时间戳日期是:2018/07/07 23:00:00 返回:["2018-07-06", "2018-07-05", "2018-07-04"]
生成 范围内所有日期 包含起止日期
/** * 生成 范围内所有日期 包含起止日期 * @param {String | Number} startDate 开始时间 * @param {String | Number} endDate 结束时间 选填,不填则默认值是当前日期 * @return 数组 */ const betweenDate = function(startDate,endDate){ var arr=[]; var now=new Date(); var endDate=endDate?endDate:(now.getFullYear()+'/'+(now.getMonth()+1)+'/'+now.getDate()); var days=parseInt(Math.abs(new Date(startDate.split(' ')[0]+' 00:00:00') - new Date(endDate.split(' ')[0]+' 00:00:00'))/1000/24/60/60)+1; for(let i=0;i<days;i++){ let stamp=new Date(new Date(startDate).getTime()+i*86400000); arr.push(stamp.getFullYear()+'-'+String(stamp.getMonth()+1).padStart(2,0)+'-'+String(stamp.getDate()).padStart(2,0)) } return arr } //测试用例 betweenDate('2017-01-01','2017-01-03') //["2017-01-01", "2017-01-02", "2017-01-03"] betweenDate('2020-03-13') //当前日期:2020/3/15 ,返回 :["2020-03-13", "2020-03-14", "2020-03-15"]
快速生成不确定长度值不确定的数组
//方法1 function GenerateArray(len,value){ return ','.repeat(len-1).split(',').fill(value) } //方法2 function GenerateArray(len,value){ return new Array(len).toString().split(',').fill(value) } //方法3 function GenerateArray(len,value){ return ','.repeat(len-1).split(',').map(i=>value) } //方法4 function GenerateArray(len,value){ return new Array(len).toString().split(',').map(i=>value) } //方法5 function GenerateArray(len,value){ return new Array(len).fill(value) } //方法6 function GenerateArray(len,value){ return Array(len).fill(value) } //测试用例 //生成长度为2 值为空对象的数组 GenerateArray(2,{}) //[{},{}] //生成长度为5 值为0的数组 GenerateArray(5,0) //[0,0,0,0,0] //生成长度为5 值为[]的数组 GenerateArray(5,[]) //[[],[],[],[],[]]
快速生成 值为索引递增 长度为len 的数组
function GenerateArray(len){ return [...Array(len).keys()] } //测试用例 GenerateArray(10) //[0,1,2,3,4,5,6,7,8,9]
不按索引,从1开始递增
function GenerateArray(len){ let arr = [...Array(len+1).keys()] arr.splice(0,1) return arr } //测试用例 GenerateArray(10) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
月份回显
export const previewMonth = function(i){ return i>0&&i<13? ['一','二','三','四','五','六','七','八','九','十','十一','十二'][i-1]+'月':'Invalid month' } //测试用例 previewMonth(0) //Invalid month previewMonth(1) //一月 previewMonth(2) //二月 previewMonth(3) //三月 previewMonth(4) //四月 previewMonth(5) //五月 previewMonth(6) //六月 previewMonth(7) //七月 previewMonth(8) //八月 previewMonth(9) //九月 previewMonth(10) //十月 previewMonth(11) //十一月 previewMonth(12) //十二月 previewMonth(13)//Invalid month
星期回显
const previewWeek = function(i){ return i>0&&i<8?'周'+['一','二','三','四','五','六','日'][i-1]:'Invalid week' } //测试用例 previewWeek(0) //Invalid week previewWeek(1) //周一 previewWeek(2) //周二 previewWeek(3) //周三 previewWeek(4) //周四 previewWeek(5) //周五 previewWeek(6) //周六 previewWeek(7) //周日 previewWeek(8) //Invalid week
时刻回显
const previewDate = function(target = Date.now()){ /** * 回显 规则: * { * <60s:'刚刚', * '>60s && 3600s':'x分钟之前', * '>3600s && <86400s':'x小时之前', * '昨天':'昨天', * '前天':'前天', * '具体日期':'月日', * '不是当年':'显示年月日' * } * */ // 时间格式参数 2018/07/08 06:05:59 | 2018-07-08 06:05:59 | 时间戳 let targetStamp = parseInt(new Date(target).getTime()/1000)//参数转时间戳 let diff = parseInt((Date.now()/1000 - targetStamp))// 计算 与当前时间相差秒数 let dt =new Date(); let today = dt.toLocaleDateString() //今天日期 年月日 let yestoday = new Date(dt.setDate(dt.getDate() - 1)).toLocaleDateString()//昨天日期 年月日 let beforeYestoday = new Date(dt.setDate(dt.getDate() - 1)).toLocaleDateString()//前天日期 年月日 let todayDawnStamp = new Date(today +' 00:00:00').getTime()/1000 //2020/2/8 let yestodayDawnStamp =new Date(yestoday +' 00:00:00').getTime()/1000 //昨天凌晨 时间戳 (秒)2020/2/7 let beforeYestodayDawnStamp = new Date(beforeYestoday +' 00:00:00').getTime()/1000 //前天凌晨 时间戳(秒) 2020/2/6 if(diff < 60) { return '刚刚' }else if(diff > 60 && diff <3600) { return parseInt(diff/60)+'分钟前' }else if(diff >= 3600 && diff < 86400){ return parseInt(diff/3600)+'小时前' }else if( targetStamp < todayDawnStamp && targetStamp >= yestodayDawnStamp){ return '昨天' }else if(targetStamp <= yestodayDawnStamp && targetStamp >= beforeYestodayDawnStamp){ return '前天' }else if(targetStamp > beforeYestodayDawnStamp){ let d = new Date(target); return (d.getMonth() +1) +'-'+ d.getDate() }else { let t = new Date(targetStamp*1000).toLocaleDateString(); let c = new Date().getFullYear(); return t.substr(0,4) == c?t.slice(5):t } } //测试用例 previewDate() //刚刚 previewDate('2020/3/14') //昨天 测试日期:2020-3-15 previewDate('2020/3/13') //前天 测试日期:2020-3-15 previewDate('2020/1/14') // 1/14 previewDate('2019/12/14') //2019/12/14
JSON 转 fromData
/** * JSON 转 fromData * @param {Object} o 需要转成formData 的对象 */ const jsonToFromData = function jsonToFromData(o){ return Object.keys(o).reduce((p, c) => !p.append(c, o[c]) && p, new FormData()) } //测试用例 let FromData = jsonToFromData({ sysId:"001", tenantId:"002", userId:"003", username:'wuming', age:39, }) FromData // FormData{} FromData.forEach((v,k)=>{ console.log(k,v) }) /**输出: * sysId 001 * tenantId 002 * userId 003 * username wuming * age 39 */
获取字符串模板内容
/** * 获取模板字符串里模板里的值 * @param {String} str 模板字符串 * @param {String} f 指定模板的左部分 * @param {String} l 指定模板的右部分 * @param {Number} pattern 指定模板的右部分 获取匹配内容的类型 默认1 * @param {Number} index 结果数组的索引 * @return any */ function betweenContent(str, f, l, pattern = 1, index = -1) { let meta = '([{}])^$|)?*+.', F = meta.includes(f) ? `\${f}` : f, L = meta.includes(l) ? `\${l}` : l, p1 = '*?', p2 = '?', p3 = '', regStr = `[${F}]${pattern == 2 ? '?' : ''}([^${F + L}]+)[${L}]${pattern == 1 ? p1 : pattern == 2 ? p2 : p3}`, reg = new RegExp(regStr, 'gi'), result = pattern == 1 ? str.match(reg).map(i => i.substr(1)) : str.match(reg); return index == -1 ? result : result[index] } //测试用例 betweenContent('1[2①3]4[35②35]35[43③45]345', '[', ']')// ["2①3", "35②35", "43③45"] betweenContent('1[2①3]4[35②35]35[43③45]345', '[', ']', 1) //["2①3", "35②35", "43③45"] betweenContent('1[2①3]4[35②35]35[43③45]345', '[', ']', 1,1) //35②35 betweenContent('1{2①3}4{35②35}35{43③45}345', '{', '}') //["2①3", "35②35", "43③45"] betweenContent('1{2①3}4{35②35}35{43③45}345', '{', '}', 1)//["2①3", "35②35", "43③45"] betweenContent('1{2①3}4{35②35}35{43③45}345', '{', '}', 2)//["1", "{2①3}", "4", "{35②35}", "35", "{43③45}", "345"] betweenContent('1{2①3}4{35②35}35{43③45}345', '{', '}', 3)//["{2①3}", "{35②35}", "{43③45}"] betweenContent('1{2①3}4{35②35}35{43③45}345', '{', '}', 1,0)//2①3 betweenContent('1-2①3-4-35②35-35-43③45-345', '-', '-')//["2①3", "4", "35②35", "35", "43③45", "345"] betweenContent('1-2①3-4-35②35-35-43③45-345', '-', '-', 1)//["2①3", "4", "35②35", "35", "43③45", "345"] betweenContent('1-2①3-4-35②35-35-43③45-345', '-', '-', 2)//["1-", "2①3-", "4-", "35②35-", "35-", "43③45-", "345"] betweenContent('1-2①3-4-35②35-35-43③45-345', '-', '-', 3)//["-2①3-", "-35②35-", "-43③45-"] betweenContent('1-2①3-4-35②35-35-43③45-345', '-', '-', 3,1) //-35②35-
获取字html字符串中的img的地址
function getImgSrc(s) { var r=[]; s.replace(/<img [^>]*src=['"]([^'"]+)[^>]*>/gi, function (m,c) { r.push(c);}); return r; } function getImgSrc(s) { let container = document.createElement('div') container.innerHTML = s return [...container.querySelectorAll('img')].map(i=>i.getAttribute('src')) } //测试用例 let s= `<p style="white-space: normal;"> <img title="" alt="1.jpg" src="https://lb.yimiyijia.cn/attached/attachment/201812/f7/71/f7f33bd36bfc80118956aaf3817d2d71.jpg_600x2000.jpg"/> <img title="" alt="2.jpg" src="https://lb.yimiyijia.cn/attached/attachment/201812/d3/da/d3fb189830bb4654a44661ea25d374da.jpg_600x2000.jpg"/> </p >`; getImgSrc(s) //输出:["https://lb.yimiyijia.cn/attached/attachment/201812…f7f33bd36bfc80118956aaf3817d2d71.jpg_600x2000.jpg", "https://lb.yimiyijia.cn/attached/attachment/201812…d3fb189830bb4654a44661ea25d374da.jpg_600x2000.jpg"]
数组 findAllIndexJson 扩展
Array.prototype.findIndexAllJson = function(callback){ let arr = []; for(let i=0;i<this.length;i++){ if(callback(this[i])) { arr.push(i) } } return arr } let jsonArr = [{name:'list',age:27},{name:'wangbo',age:28},{name:'zhangsan',age:27}] jsonArr.findIndexAllJson(item=>item.age==27) // [0, 2]
数组切片 substr 扩展(类似字符串的 substr)
Array.prototype.substr= function(startIndex,len){ let res = [] for(let i=0;i<this.length;i++){ if(i>=startIndex && res.length<len){ res.push(this[i]) } } return res } let arr = [1,2,3,4,5] arr.substr(0,1) // [1] arr.substr(0,2) // [1,2] arr.substr(0,3) // [1,2,3] arr.substr(1,3) // [2,3,4]
数据类型检测
string
function isString(s){ return typeof(s) === 'string' } function isString(s){ return ({}).toString.call(s).slice(8,-1) === 'String' }
Boolean
function isBoolean(s){ return ({}).toString.call(s).slice(8,-1) === 'Boolean' } function isBoolean(s){ return s=== false || s=== true }
Null
function isNull(s){ return ({}).toString.call(s).slice(8,-1) === 'Null' } function isNull(s){ return s === null }
Undefined
function isUndefined(s){ return ({}).toString.call(s).slice(8,-1) === 'Undefined' } function isUndefined(s){ return s === undefined }
Number
function isNumber(p){ try{ return p.constructor === Number }catch(e){ return false } } function isNumber(p){ return typeof p === 'number' } function isNumber(o){//准确 包含NaN return Object.prototype.toString.call(o).slice(8,-1) === 'Number' } // 测试 [ {}, [], undefined, null, 123, '123', Symbol('111'), function(){}, new Date(), false, /d+/gi, NaN ].map(item=>{ console.log(isNumber(item)) }) //4false true 6false true
Symbol
function isSymbol(s){ return ({}).toString.call(s).slice(8,-1) === 'Symbol' } function isSymbol(s){ return typeof s === 'symbol' }
Function
function isFunction(s){ return ({}).toString.call(s).slice(8,-1) === 'Function' } function isFunction(s){ return typeof s === 'function' }
Array
/** *第一种 通过try catch 避免 : * Cannot read property 'constructor' of undefined * Cannot read property 'constructor' of null */ function isArray(o){//准确 try{ return o.constructor === Array }catch(e){ return false } } //第二种 isArray 判断 function isArray(o){//准确 return Array.isArray(o) } //第三种 isArray 判断 function isArray(o){//准确 return o instanceof Array } //第四种 function isArray(o){//准确 return Object.prototype.toString.call(o).slice(8,-1) === 'Array' }
[ {}, [], undefined, null, 123, '123', Symbol('111'), function(){}, new Date(), false, /d+/gi ].map(item=>{ console.log(isArray(item)) }) // false true 9false
Date
function isDate(s){ return ({}).toString.call(s).slice(8,-1) === 'Date' }
判断对象类型
/** *第一种 通过try catch 避免 : * Cannot read property 'constructor' of undefined * Cannot read property 'constructor' of null */ function isObject(o){ //准确 try{ return o.constructor === Object }catch(e){ return false } } //第二种 function isObject(o){//准确 return Object.prototype.toString.call(o).slice(8,-1) === 'Object' }
判断一个值是否为 有效的 数字(不包含NaN),可以是数字字符串,例如 “123"
function idValidNumber(n){ try{ return !isNaN(parseFloat(n)) && isFinite(n); }catch(e){ return false } }
判断空对象
function isEmptyObject(o){ return ({}).toString.call(o).slice(8,-1) === "Object" && !Object.keys(o).length }
判断空数组
function isEmptyArray(o){ return Array.isArray(o) && !o.length }
判断奇数偶数
3 & 1
取整
-3.52 | 0
优雅的 switch
let value = 'a' switch (value) { case 'a': console.log(1) break; case 'b': console.log(2) break; case 'c': console.log(3) break; case 'd': console.log(4) break; } // 修改后 let obj = { 'a': () => { console.log(1) }, 'b': () => { console.log(2) }, 'c': () => { console.log(3) }, 'd': () => { console.log(4) }, } obj['a']()
优雅的 if switch替代方式
const actions = new Map([ [1, ['成功', 'IndexPage']], [2, ['失败', 'failPage']], [3, ['失败', 'failPage']], [4, ['超时', 'timeoutPage']], [5, ['系统内部错区', 'errorPage']], ['default', ['其他', 'otherPage']] ]) function fun(status) { let action = actions.get(status) || actions.get('default') console.log(action[0]) console.log(action[1]) // go(action[1])//跳页面方法 } fun(3) const actions2 = new Map([ ['guest', () => { console.log('guest') }], ['master', () => { console.log('master') }], ['default', () => { console.log('default') }], ]) function fun2(identity) { let action = actions2.get(`${identity}`) || actions2.get('default') action.call(this) } fun2('master')
获取浏览器放大倍数
//获取当前页面的缩放值 function detectZoom() { let ratio = 0, screen = window.screen, ua = navigator.userAgent.toLowerCase(); if (window.devicePixelRatio !== undefined) { ratio = window.devicePixelRatio; } else if (~ua.indexOf("msie")) { if (screen.deviceXDPI && screen.logicalXDPI) { ratio = screen.deviceXDPI / screen.logicalXDPI; } } else if ( window.outerWidth !== undefined && window.innerWidth !== undefined ) { ratio = window.outerWidth / window.innerWidth; } if (ratio) { ratio = Math.round(ratio * 100); } return ratio; } $(window).resize(function() { console.log(detectZoom()); }); // window.addEventListener("resize", () => { // console.log(detectZoom()); // });
截取视频帧
<button onclick="getCurTime()" type="button">获得当前时间的位置</button> <button onclick="setCurTime()" type="button">把时间位置设置为 5 秒</button> <video id="video1" controls="controls"> <source src="/example/html5/mov_bbb.mp4" type="video/mp4"> <source src="/example/html5/mov_bbb.ogg" type="video/ogg"> Your browser does not support HTML5 video. </video> <img id='img' style='200px;height:100px'/> <script> myVid = document.getElementById("video1"); function getCurTime() { alert(myVid.currentTime); } function setCurTime() { myVid.currentTime = 5; } var canvas = document.createElement('canvas'); var img = document.getElementById('img'); const video = document.getElementById('video1'); video.setAttribute('crossOrigin', 'anonymous'); canvas.width = video.clientWidth; canvas.height = video.clientHeight; video.currentTime = 0.5 video.onloadeddata = (() => { canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height); var dataURL = canvas.toDataURL('image/png'); img.setAttribute('src', dataURL); }) </script>
有些视频第一帧黑屏,可以借用video currentTime将视频指定到一个位置再来进行截图 如第一帧黑屏时可以将视频调到第1秒的位置再进行截图 video.currentTime = 1