JavaScript utility library.
Many util methods about Date, Cookie, Function, url, detector, collection, timeout, and so on.
Support tree shaking.
Installation
- npm:
npm install --save relax-utils
- straight download:
http://wangwl.net/static/demo/relax-utils/index.umd.js
Usage
- ES module:
import { dateFormat } from "relax-utils";
// or:
import * as utils from "relax-utils";
- commonjs:
const { dateFormat } = require("relax-utils");
// or:
const utils = require("relax-utils");
- AMD:
define( ["./index.umd.js"] , (utils)=>{ /*...*/ } )
- window.relaxUtils:
<script src="http://wangwl.net/static/demo/relax-utils/index.umd.js"></script>
- self.relaxUtils:
importScripts("./index.umd.js")
Issue
https://wangwl.net/static/pages/mynpm_utils.html
Tree Shaking
relax-utils
supports tree shaking by default.
You just import like this:
import {dateFormat, dateParse, isSafari} from 'relax-utils';
If you prefer commonjs syntax, like this:
const {dateFormat} = require('relax-utils');
By mini tool's(eg: terser) dead-code elimination, tree-shaking can also work.
API
tick
function tick(preFix?: string): string;
return timestamp.
utils.tick(); // "1632199932127"
utils.tick('prefix'); // "prefix1632199932127"
noop
function noop(): void;
Equivalent: function(){};
isUrl
function isUrl(str: string): boolean;
isArrayLike
function isArrayLike(obj: any): boolean;
If isArrayLike
return true, obj can be converted to Array
by Array#slice
or Array.from
.
isAndroid、isIos、isWeiXin
function (ua = navigator.userAgent): boolean;
Detect System by navigator.userAgent
.
You can also pass a custom userAgent string.
var ua = "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1";
utils.isIos(); //false
utils.isIos(ua); //true
isWindows、isMac
function(): boolean
Detect System by navigator.platform
.
isWifi
function isWifi(): boolean | undefined;
If network type is detected successfully, return Boolean value.
If detecting is failed(eg: browser do not support some API), return undefined
.
isIE、isEdge、isChrome、isFirefox、isSafari
function isIE(ua = navigator.userAgent): null | string;
function isEdge(ua = navigator.userAgent): null | string;
function isChrome(ua = navigator.userAgent): null | string;
function isFirefox(ua = navigator.userAgent): null | string;
function isSafari(ua = navigator.userAgent): null | string;
Detect browser by navigator.userAgent
. If matched, return the browser version. If Not matched, return null
.
var ua = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Safari/604.1.38";
utils.isChrome(); //null;
utils.isSafari(ua); //"604"
defer
function defer(): { promise: Promise, resolve: (data: any) => void, reject: (err: any) => void };
Just return a defer-object.
promisify
function promisify(original: Function, context?: object): Function
将node.js回调风格的函数,转换为返回promise的函数。
模仿node.js中的util.promisify,调用方式一致。
通过可选的context参数设置original执行时的this值。
//node.js异步回调风格: 最后一个参数为回调函数,且回调函数的第一个参数为err。
var add = function (a, b, callback) {
if (typeof a !== 'number') callback('not a number');
else callback(null, a + b);
}
utils.promisify(add)(1, 2).then(
(result) => console.log(result === 3),//true
(err) => console.log(err) //该回调不会执行
);
utils.promisify(add)('abc', 2).then(
(result) => console.log(result), //该回调不执行
(err) => console.log(err) //"not a number"
)
与node.js中util.promisify的区别在于,
- 该promisify()会判断当传入参数个数小于original时,会补全参数。
- 支持callback返回多个值的情况。
// nodejs环境
const nodeUtil = require('util');
const relaxUtil = require('relax-utils');
const print = function (a, b, cb) {
cb(null, a, b);
}
const printSingle = function (a, cb) {
cb(null, a);
}
const nodePromisify = nodeUtil.promisify(print);
const relaxPromisify = relaxUtil.promisify(print);
const relaxPromisifySingle = relaxUtil.promisify(printSingle);
nodePromisify('param1').then(
(result) => console.log('success:', result),
(error) => console.log('error:', error)
);
//error: TypeError: cb is not a function
nodePromisify('param1', 'param2').then(
(result) => console.log('success', result),
);
//success: param1
relaxPromisify('param1').then(
(result) => console.log('success:', result),
)
//success: ['param1',undefined]
relaxPromisify('param1', 'param2').then(
(results) => console.log('success:', results),
);
//success: ['param1','param2']
relaxPromisifySingle('param1').then(
(result) => console.log('success:', result)
);
//success: 'param1'
可以通过设置original[utils.promisify.custom]
来自定义promise的返回值。
当original不是标准的node.js回调风格函数时候,utils.promisify.custom会比较有用。
var add = function (cb, a, b) {
return cb(a + b);
};
add[utils.promisify.custom] = function (a, b) {
return new Promise(function (resolve, reject) {
add(resolve, a + 1, b);
})
}
utils.promisify(add)(1, 2).then((result) => {
console.log(result)
}) //4
pick
function pick(tar: object, keys: (key: string) => boolean | string[]): object;
创建只包含指定属性的对象。
var tar = {
name: 'wwl',
sex: 'male',
birth: '03'
};
utils.pick(tar, ['sex', 'name']) // {name: 'wwl', sex: 'male'}
utils.pick(tar, (key) => {
return key === 'name'
}); // {name: 'wwl'}
each
function each(
obj: Object | Array<any>,
fn: (value: any, index: string | number, obj: object | Array) => void,
context?: any): void;
Foreach array or object.
When obj
is object, this method just foreach enumerable/self property. Because in the underlying
using Object.keys(obj)
to iterate.
map
function map(
obj: Object | Array<any>,
fn: (value: any, index: string | number, obj: Object | Array) => any,
context?: any): any[];
映射一个新的数组或对象。
如果obj为对象,则借助Object.keys(obj)进行映射。
find
function find(
obj: Array | Object,
fn: (value: any, index: string | number, obj: Array | Object) => boolean,
context: Object): any | undefined;
返回fn为true时的值。
如果obj为数组,则调用Array#find() , 如果obj为对象,则借助Object.keys(obj)#find()进行查找。
unique
function unique<T>(
arr: Array<T>,
isSort = false,
map?: (item: T, index: number, arr: Array<T>) => any,
context?: Object): Array<any>;
不改变数组顺序的情况下去重,返回一个新的数据。uniq为unique的别名。
isSort:是否已排序,默认false。如果未排序,则借助includes判断是否存在。
map:映射函数,根据map函数的返回值进行比较。会调用arr.length次map函数。
context:map函数的this值。
当未指定map且支持Set
时: 则忽略isSort,优先借助Set
进行去重。
utils.unique([5, 2, 3, '5', 2]); //[5,2,3,5]
utils.unique([5, 2, 3, '5', 2], item => parseInt(item)); //[5,2,3]
loop
function loop(fn: Function, tick: number, immediate = false ): string;
根据setTimeout循环执行fn,支持fn返回一个promise来控制是否继续循环
返回一个key值。在clearLoop()中传入该值来取消循环。
clearLoop
function clearLoop(key: string): void;
取消循环执行。
key为loop()方法返回的值。
timeout
function timeout
setTimeout的promise版本。返回一个Promise对象。 fn是可选的,如果传入fn,则该Promise返回的是fn的返回的值,如果未传入fn,则该Promise返回undefined。
返回的Promise对象带有abort()方法,该方法内部调用clearTimeout,可以通过该方法取消该定时任务。
var promise = utils.timeout(() => {
return 5
}, 1000);
promise.then(data => data === 5); //true
typeof promise.abort === 'function'; //true
download
function download(url: string, fileName: string): void;
触发下载指定的url,而不是打开一个新窗口。
在node环境下,该方法为noop()。
param
function param(params: object, encodeEx?: boolean | string[] ): string;
将对象转换为key=val&key1=value1的字符串形式。
value默认通过encodeURIComponent转义,
encodeEx设置为true,则不进行转义,或者设置为一个数组[key1,key2]指定特定的key不进行转义。
utils.param({name: '+wwl'}); //"name=%2Bwwl"
utils.param({name: '+wwl'}, true); //"name=+wwl"
utils.param({name: '+wwl'}, ['name']);//"name=+wwl"
resolveUrl
function resolveUrl(url: string, param?: object , encodeEx?: boolean | string[] ): string;
在指定的url上添加查询字符串。
encodeEx参数默认为false,具体规则和param()
中encodeEx
参数规则一致。
//该方法不是一个绝对安全的方法,可能会改变原url中查询字符串中参数的顺序,以及丢失无法解析的值。
//例如:
resolveUrl('localhost?name=wwl&abc', {sex: 'male'});
//会返回: localhost?sex=male&name=wwl
parseParam
function parseParam(paramStr: string, decodeEx?: boolean | string[] ): {};
将key=value&key1=value1形式的字符串转换成对象,param的反向操作。
value默认会通过decodeURIComponent进行解密。
通过设置decodeEx参数为true则不进行解密。或者设置为数组[key1,key2]
指定特定的key不进行解密。
utils.parseParam('name=%2Bwwl') //{name:"+wwl"}
utils.parseParam('name=%2Bwwl', true) //{name:"%2Bwwl"}
utils.parseParam('name=%2Bwwl', ['name']) //{name:"%2Bwwl"}
注意,当paramStr参数不规范时候,decodeURIComponent
会报错,例如:
decodeURIComponent('sex=%');
// Uncaught URIError: URI malformed
这里,utils.parseParam
和decodeURIComponent
保持一样的逻辑,当参数不规范时候,会抛出错误。
utils.parseParam('name=wwl&sex=%');
// Uncaught URIError: URI malformed (malformed key: sex)
getQuery
function getQuery(url = location.search, decodeEx?: boolean | string[] ): object;
返回代表查询字符串的键值对。
默认处理当前页面的url。
默认会使用decodeURIComponent
对解析到的值进行解密。
可通过设置decodeEx
不进行解密,具体规则和parseParam()
中的decodeEx
参数规则一致。
utils.getQuery().id;
utils.getQuery('localhost/indexhtml?id=idinfo').id
类似parseParam
,如果参数不规范,向上传递decodeURIComponent
的报错。
utils.getQuery('?name=wwl&sex=%');
// Uncaught URIError: URI malformed (malformed key: sex)
countStr
function countStr(txt: string, fullVal = 1, halfVal = 0.5, enterVal = 1): number;
计算字符长度。该方法区分全角字符和半角字符。
fullVal: 全角字符的权重值,默认为1
halfVal: 半角字符的权重值,默认为0.5
enterVal: 回车字符的权重值,默认为1
copyTxt
function copyTxt(txt: string): boolean;
复制txt到剪切板。
如果操作成功,则返回true。
如果操作失败(浏览器不支持),则返回false。
htmlEncode 、 htmlDecode
function htmlEncode(txt: string): string;
function htmlDecode(val: string): string;
html转义和解密。
如果是node环境,htmlDecode只能正确解密由htmlEncode()返回的内容
utils.htmlEncode('<body>'); //&#60;body&#62;
utils.htmlDecode('&lt;body') //<body
camelCase
function camelCase(…args: string[]): string;
"camel-case"转换为"camelCase"。
或者传入多个字符串,合并为驼峰式。
utils.camelCase('camel-case'); //camelCase
utils.camelCase('I-am', 'wwl'); //IAmWwl
kebabCase
function kebabCase(…args: string[]): string;
将驼峰命名法字符串,转换为小写的短横线分隔形式。
"kebabCase"转换为"kebab-case"。 或传入多个字符串,合并为短横线分隔形式。
utils.kebabCase('this', 'IsTest'); //this-is-test
utils.kebabCase('KebabCase'); //kebab-case
paddingLeft
function paddingLeft(target = '', len: number, paddingChar = " "): string
补齐位数。
utils.paddingLeft('1', 3, '0'); //001
utils.paddingLeft('12345', 3); //12345
template
function template(template : string, data: object): string
模板函数。计算表达式生成字符串。支持ES6模板字符串语法。
utils.template('hello,${firstName+secondName}', {firstName: 'wang', secondName: 'wl'});
//"hello,wangwl"
retry
function retry(fn, max: number, wait=0, context?: object) : function
创建重试函数。
创建的新函数,内部实际执行fn
,如果fn
返回了失败的Promise,则会在间隔wait
时间之后,重新执行fn
,最多执行max
次。
其中wait
默认为0,即立即进行重试。如果wait
大于0,则使用setTimeout
在间隔wait之后进行重试。
通过context
设置fn执行时候的this
的值,默认和返回的函数执行时的this
一致。
var cnt = 0;
var fn = function () {
console.log('retry', ++cnt, this);
return Promise.reject();
}
utils.retry(fn, 3, 300).bind({test: 'this'})();
// retry1 {test:"this"}
// retry2 {test:"this"}
// retry3 {test:"this"}
cache
function cache(
fn: Function,
context?: Object,
predicate?: (...args) => boolean): (refresh, ...args) => any;
返回一个新的缓存函数。
返回的函数签名为:function(refresh,…args); refresh判断是否强制刷新,剩余参数传给fn。
predicate为可选的,如果传入predicate,在refresh为false时,会根据predicate的返回值判断是否需要刷新。
context为可选的,可以通过context设置返回函数和predicate的this值,
var ori = function (a, b) {
return a;
};
var cache = utils.cache(ori, function (a, b) {
return a > b
});
cache(true, 1, 2); //1
cache(); //1
cache(false, 5, 6); //1
cache(true, 5, 6); //5
cache(false, 8, 7); //8
throttle 、 debounce
function throttle(fn: Function, alwaysFn?: Function, immediately?: boolean, wait=300, context?: object)
function debounce(fn: Function, alwaysFn?: Function, immediately?: boolean, wait=300, context?: object)
截流和防抖动。
fn: 目标执行方法。
alwaysFn: 每次调用都会执行的方法。
immediately: 是否立即执行。如果为true,则会在第一次调用时立即执行fn,忽略后续的调用。
wait:指定时间,以毫秒为单位。
context: 指定alwaysFn和fn的this值,如果省略,则为结果函数的this值。
var obj = {};
var fn = function () {
console.log(this === obj)
};
obj.fn = utils.debounce(fn, () => {
console.log(1)
}, 1000);
obj.fn();
obj.fn();
//1
//1
//true
dateFormat
function dateFormat(date: Date, fmt = 'yyyy-MM-dd hh:mm:ss'): string;
格式化时间。
- 支持:年y, 月M, 天d, 24小时制H, 12小时制h, 分m, 秒s, 毫秒S, am/pm a。
- 支持转义: 使用中括号对以上字符进行转义。
年份根据y的数量截取,其他值,只补齐不截取。
utils.dateFormat(new Date(), 'yy-MM-dd HH:mm:ss'); //"17-10-30 18:08:08"
utils.dateFormat(new Date(), 'yyyy-M-d h:m:s a'); //"2017-10-30 6:8:8 pm"
//转义:
utils.dateFormat(new Date(), '[today] M-d') //"today 10-30"
dateParse
function dateParse(str: string, fmt = 'yyyy-MM-dd hh:mm:ss'): Date;
根据时间字符串和指定的格式,返回Date对象。
- 支持:年y, 月M, 天d, 24小时制H, 12小时制h, 分m, 秒s, 毫秒S, am/pm a。
- 支持转义: 使用中括号对以上字符进行转义。
utils.dateFormat(
utils.dateParse('2017-10-30 18:8:8', 'yyyy-M-d H:m:s'),
'yy-MM-dd HH-mm-ss'); //"17-10-30 18-08-08"
utils.dateFormat(
utils.dateParse('today 6:10 pm', '[today] h:m a'),
'HH:mm'); //"18:10"
dateAdd(日期计算)
function dateAdd(date, config: number | { year?: number, month?: number, day?: number, hour?: number, min?: number,
sec?: number }): Date;
日期加减法。返回新的Date对象。
var today = utils.dateParse('2017,10,10 10:10:10', 'yyyy,MM,dd hh:mm:ss');
utils.dateAdd(today, -2); //2017,10,8 10:10:10 等效于utils.dateAdd(today,{day:-2});
utils.dateAdd(today, {hour: 2}); //2017,10,10 12:10:10
firstDateInMonth、 lastDateInMonth
function firstDateInMonth(date: Date): Date;
function lastDateInMonth(date: Date): Date;
返回传入date所在月份的第一天、最后一天的Date对象。
firstWeekInMonth 、 lastWeekInMonth
function firstWeekInMonth(date: Date): Date;
function lastWeekInMonth(date: Date): Date;
返回传入日期所在月份的,第一周的周一、最后一周的周日。
weekRange
function weekRange(
startDate: Date,
endDate: Date,
splitDay = 1): Array<{ start: Date, end: Date, duration: number }>
返回开始日期和结束日期的周。计算时忽略时间,只计算日期。
splitDay:分割点。对应date.getDay()取值0~6。 例如取周一至周日,则splitDay传入1,取周日至周六,splitDay传入0。
返回周的数组。 每一项为:{start:date,end:date,duration:number}。
//获取该月的所有周。
var today = new Date();
utils.weekRange(utils.firstWeekInMonth(today), utils.lastWeekInMonth(today));
weekendsCount
function weekendsCount(startDate: Date, endDate: Date): number
计算开始日期和结束日期共有周六日多少天。计算时忽略时间,只计算日期。
getCookie
function getCookie(refresh = false): object;
返回一个指代当前cookie的对象。兼容.NET中的多值cookie。
该方法内部缓存一个cookie对象,当多次调用时,只对document.cookie解析一次;
refresh: 传入true,强制重新解析cookie并返回。
utils.getCookie().cookieName.value; //单值cookie,获取键为cookieName的cookie的值。
if (utils.getCookie().multiCookie.values) { //多值cookie,获取multiCookie中key1的值。
utils.getCookie().multiCookie.values.key1;
}
setCookie
function setCookie(
key: string,
value: string | object,
option?: {
path?: string,
domain?: string,
secure?: boolean,
expires?: Date | { day: number, hour: number, min: number, sec: number }
}): string
设置或添加一个cookie,返回cookie的值。
key:cookie名称
value:cookie的值。 如果传入一个对象,则认为是多值cookie
option.path: cookie路径,默认为当前路径。
option.domain: cookie的域名,默认为当前域名。
option.secure: 是否加密,默认为false
option.expires: 过期时间,默认为session-Cookie。可以传入对象,或一个类似{day?:num,hour?:num,min?:num,sec?:num}的对象向后递推时间。例如{expires:{day:
1}}代表该cookie有效时间为1天。
deleteCookie
function deleteCookie(key: string, option): boolean;
删除一个cookie
cookie对象
let cookie: {
del: typeof deleteCookie,
delete: typeof deleteCookie,
set: typeof setCookie,
get(name: string, refresh = false): string | undefined
};
cookie.del 、cookie.delete 为 deleteCookie的别名。
cookie.set 为setCookie的别名。
get(name,refresh),获取指定名称的cookie值,只支持单值cookie
注意
在node环境下,'isWifi', 'download', 'copyTxt','getCookie', 'setCookie', 'deleteCookie'不可用;