great-jsutils

js工具类 时间示例演示:https://zhtt.gitee.io/angular-demo/great-ngform6/#/jsutils/time-test、

Usage no npm install needed!

<script type="module">
  import greatJsutils from 'https://cdn.skypack.dev/great-jsutils';
</script>

README

jsutils api

js工具类
时间示例演示:https://zhtt.gitee.io/angular-demo/great-ngform6/#/jsutils/time-test

数组示例演示:https://zhtt.gitee.io/angular-demo/great-ngform6/#/jsutils/array-test

友情链接

great-generatorgreat-jsutilsgreat-ngformgreat-zorroutils

安装

npm i great-jsutils --save

License

请查看 MIT license.

一、数组

import { ArrayUtils } from 'great-jsutils';

添加元素

ArrayUtils.add(array: any, obj: any, {idKey : 'id', pIdKey : 'parentId', childKey : 'children'} = {});

参数 名称 必传 参数类型
array 被操作的数组 Array
obj 被添加的元素 any
keys 主键、子属性对应关系 string

示例1:添加元素

function add01() {
    let data = [{
        'id': 'A', 'type': '1', 'children': [
            {
                'id': 'A01', 'type': '2', 'children': [
                    {'id': 'A01-01', 'type': '3'}
                ]
            },
            {'id': 'A03', 'type': '3'}
        ]
    }];
    let child = {'id': 'A03-01', 'parentId': 'A03'};
    let result = ArrayUtils.add(data, child);
    console.log(result,JSON.stringify(data));
}
function add02() {
    let data = [{
        'orgId': 'A', 'type': '1', 'children': [
            {'orgId': 'A01', 'type': '2'},
            {'orgId': 'A03', 'type': '3'}
        ]
    }];
    let child = {'orgId': 'A03-01', 'parentId': 'A03'};
    let result = ArrayUtils.add(data, child,{idKey:'orgId'});
    console.log(result,JSON.stringify(data));
}
function add03() {
    let data = [{
        'orgId': 'A', 'type': '1', 'items': [
            {'orgId': 'A01', 'type': '2'},
            {'orgId': 'A03', 'type': '3'}
        ]
    }];
    let child = {'orgId': 'A03-01', 'parentId': 'A03'};
    let result = ArrayUtils.add(data, child,{idKey:'orgId',childKey:'items'});
    console.log(result,JSON.stringify(data));
}
function add04() {
    let data = [{
        'id': 'A', 'type': '1', 'children': [
            {'id': 'A03', 'type': '3'}
        ]
    }];
    let keys = {'id': 'key'};
    let child = {'id': 'A03-01', 'parent': {'id': 'A03'}};
    let result = ArrayUtils.add(data, child,{'pIdKey':'parent'});
    console.log(result,JSON.stringify(data));
}

移除元素

ArrayUtils.remove(array,value,key);

参数 名称 必传 参数类型
array 被操作的数组 Array
value 需要移除的值 any
keys 主键、子属性对应关系 string

示例1:移除字符串

//字符串移除,第一个参数是被操作的数组,第二个参数是需要移除的字符串
function testArray(){
    let arr=['a','b','c'];
    ArrayUtils.remove(arr,'b');
    console.log(arr.join(','));//a,c
}

示例2:对象移除

function removeRoot01() {
    let objArr=[{'id':'1','name':'赵云'},{'id':'2','name':'诸葛亮'}];
    ArrayUtils.remove(objArr,{'id':'2'});
    console.log(JSON.stringify(objArr));//[{'id':'1','name':'赵云'}]
}

示例3:对象移除

function removeRoot02() {
    let objArr=[{'userId':'1','name':'赵云'},{'userId':'2','name':'诸葛亮'}];
    ArrayUtils.remove(objArr,{'userId':'2'},{idKey:'userId'});
    console.log(JSON.stringify(objArr));//[{'userId':'1','name':'赵云'}]
}

示例4:子节点移除

function removeChild01() {
    let objArr=[{'id':'1','name':'山东省','children':[{'id':'2','name':'济南市'}]}];
    ArrayUtils.remove(objArr,{'id':'2'});
    console.log(JSON.stringify(objArr));//[{'id':'1','name':'赵云'}]
}
function removeChild02() {
    let objArr=[{'id':'1','name':'山东省','items':[{'id':'2','name':'济南市'}]}];
    ArrayUtils.remove(objArr,{'id':'2'},{childKey:'items'});
    console.log(JSON.stringify(objArr));//[{'id':'1','name':'赵云'}]
}

更新元素

ArrayUtils.update(array,obj,keys);

参数 名称 必传 参数类型
array 被操作的数组 Array
obj 需要更新的对象 any
keys 主键、子属性对应关系 string

示例1:更新根节点中的元素

//字符串移除,第一个参数是被操作的数组,第二个参数是需要更新的对象

function updateRoot01() {
    let obj={'id':'001','name':'001'};
    let array=[{'id':'001','name':'111'}];
    let newArray=ArrayUtils.update(array,obj);
    console.log(JSON.stringify(array));
}

示例2:更新根节点中的元素

import { ArrayUtils } from 'great-jsutils';

function updateRoot02() {
    let obj={'userId':'002','name':'222'};
    let array=[{'userId':'002','name':'111'}];
    let newArray=ArrayUtils.update(array,obj,{idKey:'userId'});
    console.log(JSON.stringify(array));
}

示例3:更新子节点中的元素

import { ArrayUtils } from 'great-jsutils';
function updateChildren01() {
    let obj={'id':'001','name':'001'};
    let array=[{'id':'a','name':'111','children':[{'id':'001','name':'222'}]}];
    ArrayUtils.update(array,obj);
    console.log(JSON.stringify(array));
}

示例4:更新子节点中的元素

import { ArrayUtils } from 'great-jsutils';
function updateChildren02() {
    let obj={'userId':'001','name':'001'};
    let array=[{'userId':'A','name':'A','items':[{'userId':'001','name':'222'}]}];
    ArrayUtils.update(array,obj,{idKey:'userId',childKey:'items'});
    console.log(JSON.stringify(array));
}

**示例5:更新时,增加key


function updateChildren03() {
    let obj={'userId':'001','name':'001','checked':true};
    let array=[{'userId':'A','name':'A','items':[{'userId':'001','name':'222'}]}];
    ArrayUtils.update(array,obj,{idKey:'userId',childKey:'items'},function(oldData,newData){
        return {'checked':newData['checked']};
    });
    console.log(JSON.stringify(array));

}

合并元素

ArrayUtils.merge(array,obj,keys);

参数 名称 必传 参数类型
array 被操作的数组 Array
obj 需要更新的对象 any
keys 主键、子属性对应关系 string

与update类似,这个会增加第二个参数中的新属性

属性替换

ArrayUtils.updateKey(array,keys,function);

参数 名称 必传 参数类型
array 被操作的数组 Array
keys 原key与新key的对应关系 json
function 自定义需要添加的属性 string

示例1:属性替换

import { ArrayUtils } from 'great-jsutils';
//数组中的对象key替换,例如源数据为[{'name':'张三'}]替换为[{'text':'张三'}]
function testArray(){
    let datas=[{'name':'张三','sex':'1'}];
    let keys={'name':'text'};
    let result=ArrayUtils.updateKey(datas,keys);
    console.log(result);//{name: '张三', sex: '1'}
}

示例2:属性替换,并添加新属性

//数组中对象key替换,例如源数据为[{'name':'张三','age':80}]替换为[{'text':'张三','age':80,'ageGroup':'老年人'}];
//这里是根据某些值特征,增加新的属性
function testArray(){
    let datas=[{'name':'张三','sex':'1'}];
    let keys={'name':'text'};
    let result=ArrayUtils.updateKey(data,keys,function(){
        if(data['age']>75){
            return {'ageGroup':'老年人'};
        }
    });
    console.log(result);//[{'text':'张三','age':80,'ageGroup':'老年人'}];
}

获取树节点

ArrayUtils.get(array,obj,keys);

参数 名称 必传 参数类型
array 被操作的数组 Array
obj 需要更新的对象 any
keys 主键、子属性对应关系 string

示例1:根据主键获取

//从树状数组中,根据id的值获取节点数据

function get01() {
    let data = [ {'id': 'A01', 'type': '2'},{'id': 'A03', 'type': '3'}];
    let item = ArrayUtils.get(data, 'A03');
    console.log(item);//{'id': 'A03', 'type': '3'}
}
function get02() {
    let data = [ {'userId': 'A01', 'type': '2'},{'userId': 'A03', 'type': '3'}];
    let item = ArrayUtils.get(data, 'A03',{idKey:'userId'});
    console.log(item);//{'id': 'A03', 'type': '3'}
}
function get03() {
    let data = [ {'userId': 'A01', 'type': '2'},{'userId': 'A03', 'type': '3'}];
    let item = ArrayUtils.get(data, {'id':'A03'});
    console.log(item);//{'id': 'A03', 'type': '3'}
}
function get() {
    let data = [{
        'id': 'A', 'type': '1', 'children': [
            {
                'id': 'A01', 'type': '2', 'children': [
                    {
                        'id': 'A01-01', 'type': '3', 'children': [
                            {'id': 'A01-01-01', 'type': '3-01', 'children': [
                                    {'id': 'A01-01-01', 'type': '3-02'}
                                ]}
                        ]
                    }, {
                        'id': 'A01-02', 'type': '3', 'children': [
                            {'id': 'A01-02-01', 'type': '3-01', 'children': [
                                    {'id': 'A01-02-01-01', 'type': '3-02', 'children': [
                                            {'id': 'A01-02-01-01-01', 'type': '3-02'}
                                        ]}
                                ]}
                        ]
                    }
                ]
            },
            {'id': 'A03', 'type': '3'}
        ]
    }];
    let item = ArrayUtils.get(data, 'A01-02-01-01-01');
    console.log(item);//{ id: 'A01-02-01-01-01', type: '3-02' }
}

示例2:根据主键获取

//从树状数组中,根据id的值获取节点数据
function getTreeNodeById(){
    let arr=[{'id':'A','type':'1','children':[
                {'id':'A01','type':'2','children':[
                    {'id':'A01-01','type':'3','children':[
                        {'id':'A01-01-01','type':'3-01'}
                    ]},
                    {'id':'A01-02','type':'3','children':[
                        {'id':'A01-02-01','type':'3-02'}
                    ]}
                ]},
                {'id':'A03','type':'3'}
            ]}];
    let item=ArrayUtils.get(arr,'A01-02-01','id','children');
    console.log(item);//{ id: 'A01-02-01', type: '3-02' }
}

是否是个有效的数组对象

ArrayUtils.valid(array);

是否是个有效的数组对象,有则返回第一个子元素,否则返回false

参数 名称 必传 参数类型
array 被操作的数组 Array

示例1:是否是个有效的数组对象

//从树状数组中,根据id的值获取节点数据
function valid(){
    let arr=[{'id':'A','type':'1','children':[
                {'id':'A01','type':'2','children':[
                    {'id':'A01-01','type':'3','children':[
                        {'id':'A01-01-01','type':'3-01'}
                    ]},
                    {'id':'A01-02','type':'3','children':[
                        {'id':'A01-02-01','type':'3-02'}
                    ]}
                ]},
                {'id':'A03','type':'3'}
            ]}];
    let item=ArrayUtils.valid(arr);
    console.log(item);
}

节点向上移动操作

示例一:将第二个元素上移到第2个位置

/**
* 将第二个元素上移2个位置
*/
function move01() {
   let arr=['a','b','c','d','e'];
    //ArrayUtils
    let index=2;
    let size=2;
    ArrayUtils.up(arr,index,{size});
    console.log(arr);
}

示例二:将第二个元素上移到第2个位置

/**
* 将第二个元素下移到第2个位置
*/
function move01() {
   let arr=['a','b','c','d','e'];
    //ArrayUtils
    let index=2;
    let end=2;
    ArrayUtils.up(arr,index,{end});
    console.log(arr);
}

节点向下移动操作

示例一:将第二个元素,移动到第1个位置

/**
* 将第二个元素下移2个位置
*/
function down10() {
    let arr=['a', 'b', 'c', 'd'];
    console.log('移动前',arr);
    let index=2;
    let end=1;
    ArrayUtils.down(arr,index,{end});
    console.log('移动后',arr);
    /**
     * 移动前 [ 'a', 'b', 'c', 'd' ]
     * 移动后 [ 'a', 'c', 'b', 'd' ]
     */
}

示例一:将第二个元素下移到第2个位置

/**
* 将第二个元素下移2个位置
*/
function move01() {
   let arr=['a','b','c','d','e'];
    //ArrayUtils
    let index=2;
    let size=2;
    ArrayUtils.down(arr,index,{size});
    console.log(arr);
}

示例二:将第二个元素下移到第2个位置

/**
* 将第二个元素下移到第2个位置
*/
function move01() {
   let arr=['a','b','c','d','e'];
    //ArrayUtils
    let index=2;
    let end=2;
    ArrayUtils.down(arr,index,{end});
    console.log(arr);
}

将指定索引的节点移到底部

将第二个元素移动到底部

function moveBottom() {
    let arr = ['a', 'b', 'c', 'd', 'e'];
    //ArrayUtils
    let index = 2;
    ArrayUtils.bottom(arr,index);
    console.log(arr);
}

移动对象

function moveBottom2() {
    let arr = [{name:'1'},{name:'2'},{name:'3'},{name:'4'}];
    let index = 2;
    ArrayUtils.bottom(arr,index);
    console.log(arr);
    /**
     * 打印结果:
     * [ { name: '1' }, { name: '2' }, { name: '4' }, { name: '3' } ]
     */
}

将指定索引的节点移到顶部

将第二个元素移动到顶部

function top() {
    let arr = ['a', 'b', 'c', 'd', 'e'];
    //ArrayUtils
    let index = 2;
    ArrayUtils.top(arr,index);
    console.log(arr);
}

移动对象

function top() {
    let arr = [{name:'1'},{name:'2'},{name:'3'},{name:'4'}];
    let index = 2;
    ArrayUtils.top(arr,index);
    console.log(arr);
    /**
     * 打印结果:
     * [ { name: '3' }, { name: '1' }, { name: '2' }, { name: '4' } ]
     */
}

节点位置交换

/**
 * 两个元素交换位子
 * @param arr:被移动的数组
 * @param index1:被移动的元素一
 * @param index2:被移动的元素二
 * @returns {any}
 */
ArrayUtils.swap(arr, index1, index2);

示例:将第一个和第三个进行交换

function swap(){
    let arr = [{name:'1'},{name:'2'},{name:'3'},{name:'4'}];
    ArrayUtils.swap(arr,1,3);
    console.log(arr);
    /**
     * 打印结果:
     * [ { name: '1' }, { name: '4' }, { name: '3' }, { name: '2' } ]
     */
}

二、 加密

示例1:md5

//字符串的加密
import {JsUtilsApi } from 'great-jsutils';
function md5() {
  JsUtilsApi.md5('admin123456')
}

示例2:Base64

//字符串的加密、解密
import {Base64 } from 'great-jsutils';
function base64() {
console.log('base64:',Base64.encode('123'));
console.log('base64:',Base64.decode('MTIz'));
}

示例3:md5File,读取文件内容生成md5值

//字符串的加密、解密
import {JsUtilsApi } from 'great-jsutils';
function md5File() {
    JsUtilsApi.md5File(file).then(
      (md5)=>{ // 成功回调
        this.file.fileMd5 = md5;
      }
    );
}

三、 时间工具类

  • 常量
FORMAT_FULL = 'yyyy-MM-dd hh:mm:ss';
FORMAT_FULL_IE = 'yyyy/MM/dd hh:mm:ss';
FORMAT_FULL_CN = 'yyyy年MM月dd日 hh时mm分ss秒';
FORMAT_YMD = 'yyyy-MM-dd';
FORMAT_YMD_IE = 'yyyy/MM/dd';
FORMAT_YMD_CN = 'yyyy年MM月dd日';
FORMAT_HMS = 'hh:mm:ss';
FORMAT_HMS_CN = 'hh时mm分ss秒';
import { TimeUtils } from 'great-jsutils';

判断是否是日期类型

TimeUtils.isDate(args);

获取某天开始、结束时间 TimeUtils.getDayTime(n:number);

参数 名称 必传 参数类型
n 获取n天前时间,不传则为当天时间 number

根据传入的数字,获取n天前的开始结束时间,正数则往后推,负数则往前推

import {TimeUtils } from 'great-jsutils';
function testTime(){
    console.log('当天开始、结束时间',TimeUtils.getDayTime());
    //当天开始、结束时间 { start: '2018-08-31 00:00:00', end: '2018-08-31 24:59:59' }
    console.log('获取昨天时间:',TimeUtils.getDayTime(-1));
    console.log('获取前天时间:',TimeUtils.getDayTime(-2));
    console.log('获取明天时间:',TimeUtils.getDayTime(1));
    console.log('获取后天时间:',TimeUtils.getDayTime(1));
}

获取某周开始、结束时间

TimeUtils.getWeekTime(n:number); 

根据传入的数字,获取n周前的开始结束时间,正数则往后推,负数则往前推

import {TimeUtils } from 'great-jsutils';
function testTime(){
    console.log('本周开始、结束时间',TimeUtils.getWeekTime());
    //本周开始、结束时间 { start: '2018-09-17 00:00:00', end: '2018-09-23 24:59:59' }
    console.log('上周开始、结束时间',TimeUtils.getWeekTime(-1));
    //上周开始、结束时间 { start: '2018-09-10 00:00:00', end: '2018-09-16 24:59:59' }
}

获取某月开始、结束时间

 TimeUtils.getMonthTime(integer);

根据传入的数字,获取n月前的开始结束时间,正数则往后推,负数则往前推

import {TimeUtils } from 'great-jsutils';
function testTime(){
    console.log('本月开始、结束时间',TimeUtils.getMonthTime());
    //本月开始、结束时间 { start: '2018-09-01 00:00:00', end: '2018-09-30 24:59:59' }
    console.log('上月开始、结束时间',TimeUtils.getMonthTime(-1));
    //上月开始、结束时间 { start: '2018-08-01 00:00:00', end: '2018-08-31 24:59:59' }
}

获取某季度开始、结束时间

TimeUtils.getQuarterTime(n:number); 

根据传入的数字,获取n月前的开始结束时间,正数则往后推,负数则往前推

import {TimeUtils } from 'great-jsutils';
function testTime(){
    console.log('本季度开始结束时间',TimeUtils.getQuarterTime());
    //本季度开始结束时间 { start: '2018-07-01 00:00:00', end: '2018-09-30 24:59:59' }
    console.log('上季度开始结束时间',TimeUtils.getQuarterTime(-1));
}

获取某年开始、结束时间

TimeUtils.getYearTime(n:number); 

根据传入的数字,获取n年前的开始结束时间,正数则往后推,负数则往前推

import {TimeUtils } from 'great-jsutils';
function testTime(){
    console.log('本年开始结束时间',TimeUtils.getYearTime());
    //本年开始结束时间 { start: '2018-01-01 00:00:00', end: '2018-12-31 24:59:59' }
    console.log('上年开始结束时间',TimeUtils.getYearTime(-1));
}

获取N天内的开始、结束时间

getWinthInDayTime

参数 名称 必传 参数类型
num 指定天数 number
```
function getWinthInDayTime(){
let num1 = -29;// 向前推获取30天内的时间
let time1 = TimeUtils.getWinthInDayTime(num1);
console.log(\n${num1}天内的开始、结束时间:\n, time1);
/*
-29天内的开始、结束时间:
{ start: '2019-03-23 00:00:00', end: '2019-04-21 24:59:59' }
*/
let num2 = 29; // 向后推,获取30天内的时间
let time2 = TimeUtils.getWinthInDayTime(num2);
console.log(`\n${num2}天内的开始、结束时间:\n`, time2);
/*
 29天内的开始、结束时间:
 { start: '2019-04-21 00:00:00', end: '2019-05-20 24:59:59' }
 */

}


**格式化时间**
**TimeUtils.format(date:Date,format:string)**

| 参数 | 名称 | 必传 | 参数类型
| ------ | ------ | ------ | ------ |
| date | 需要格式化的时间 | 否 | Date |
| format | 需要转换的格式 | 否 | string |
```js
import {TimeUtils } from 'great-jsutils';
function testTime(){
    console.log('格式化时间(默认的格式化类型):',TimeUtils.format());//当前时间
    //格式化时间(默认的格式化类型): 2018-09-23 17:18:19
    console.log('格式化时间(默认的格式化类型):',TimeUtils.format(new Date()));
    //格式化时间(默认的格式化类型): 2018-09-23 17:18:19
    console.log('格式化时间(根据传入的参数格式):',TimeUtils.format(new Date(),'yyyy-MM-dd hh时'));
    //格式化时间(根据传入的参数格式): 2018-09-23 17时
    console.log('格式化时间(API提供的类型):',TimeUtils.format(new Date(),TimeUtils.FORMAT_YMD));
    //格式化时间(API提供的类型): 2018-09-23
}

生成一个随机时间

/* 获取一个随机时间 */
function random() {
    let date =  TimeUtils.random();
    let dateStr = TimeUtils.format(date);
    console.log(dateStr);
}
random();

根据当前时间,输出早上好、上午好……

function sayHello() {
    let hello =  TimeUtils.sayHello();
    console.log(hello);
}
sayHello();

字符串转时间

function parse(){
    let date = TimeUtils.parse('2019年11年9日 11点11分11秒');
    if(date){
        console.log('parse:',TimeUtils.format(date));
        //parse: 2019-11-09 11:11:11
    }else{
        console.log('null');
    }
}

获取某月最后一天的时间

TimeUtils.getMonthEndDateByDateStr(dateStr);

四、 字符串

import { StringUtils } from 'great-jsutils';

示例1:删除全部空格

import {StringUtils } from 'great-jsutils';
StringUtils.trim(str);

示例2:删除前后空格

import {StringUtils } from 'great-jsutils';
StringUtils.trimAround(str);

五、 json

import { JsonUtils } from 'great-jsutils';

示例1:判断是否为json

import {JsonUtils } from 'great-jsutils';
function json(){
    let str1='123';
    console.log(str1,JsonUtils.isJsonString(str1));
    let str2="{'name':'1'}";
    console.log(str2,JsonUtils.isJsonString(str2));
    let str3="{name:'1'}";
    console.log(str3,JsonUtils.isJsonString(str3));
    let str4="{'name':'xt'}";
    console.log(str4,JsonUtils.isJsonString(str4));
}

示例2:字符串转json

import {JsonUtils } from 'great-jsutils';
let str4="{'name':'xt'}";
JsonUtils.toJson(str4);

示例3:syntaxHighlight

import {JsonUtils } from 'great-jsutils';
let str4="{'name':'xt'}";
JsonUtils.syntaxHighlight(str4);
/**
 * 是否是jsonStr
 */
JsonUtils.isJsonString
/**
 * 转成jsonStr
 */
JsonUtils.toJsonStr
/**
 * 转成json对象
 */
JsonUtils.toJson
/**
 * json转前端实体类
 */
JsonUtils.toClassModel(json,{notes:false})

六、 正则RegexpUtils

import {RegexpUtils} from 'great-jsutils';

1、数字验证

/**
 * 数字验证
 * 验证数字是否是规定的范围格式
 * 例如:是否为指定的小数位数、是否大于某个数字、是否小于某个数字、是否在某个数据范围之间
 */
RegexpUtils.isNumber(str,{
    max:'最大值',
    min:'最小值',
    maxScale:'最大小数位数',
    minScale:'至少小数位数',
    scale:'小数位数'
});

场景示例

let numStr = "123.222";

// 场景一:检查输入的是否为数字
let result1 = RegexpUtils.isNumber(numStr);
console.log(numStr+'是否为数字:', result1);
//打印结果: 123.222是否为数字:true

// 场景二:检查输入的小数是否为三位
let result2 = RegexpUtils.isNumber(numStr,{scale:3});
console.log(numStr+'小数位数:==3',result2);
//打印结果: 123.222小数位数:==3 true

// 场景三:检查小数位数是否多于三位
let result3 = RegexpUtils.isNumber(numStr,{minScale:3});
console.log(numStr+'小数位数:>=3',result3);
//打印结果: 123.222小数位数:>=3 true

// 场景四:检查小数位数的个数是否多于4个、少于5个
let result4 = RegexpUtils.isNumber(numStr,{minScale:4, maxScale:5});
console.log(numStr+'小数位数:4-5',result4);
//打印结果: 123.222小数位数:4-5 false

// 场景五:检查小数位数是否多于5个
let result5 = RegexpUtils.isNumber(numStr,{maxScale:5});
console.log(numStr+'小数位数:<5',result5);
//打印结果: 123.222小数位数:<5 true

// 场景六:检查数字是否大于5
let result6 = RegexpUtils.isNumber(numStr,{min:5});
console.log(numStr+'>5:',result6);
//打印结果: 123.222>5: true

// 场景七:检查数字是否大于5,并且小于200
let result7 = RegexpUtils.isNumber(numStr,{min:5, max:200});
console.log(numStr+'>5 && '+numStr+'<200:',result7);
//打印结果:123.222>5 && 123.222<200: true

// 场景八:检查数字是否小于555
let result8 = RegexpUtils.isNumber(numStr,{max:555});
console.log(numStr+'<555:',result8);
//打印结果: 123.222<555: true

let result9 = RegexpUtils.isNumber(numStr,{});
console.log(numStr+'{}:',result9);
//打印结果: 123.222{}: true

2、字节个数验证

/**
 * 字节个数验证
 * 由于数据库中定义的字段长度为字节长度,
 * 所以中英文混合输入时,为了避免避免输入超长,
 * 需要检查输入数字的字节长度
 */
RegexpUtils.byteLength(str,{
    maxLength:'最大长度',
    minLength:'最小长度',
});

场景示例

let str = '富强prosperity/1/2/3';

let result = RegexpUtils.byteLength(str,{maxLength: 10});
console.log(`${str}字节数<10:`,result);
// 打印结果:富强prosperity/1/2/3字节数<10: false

let result2 = RegexpUtils.byteLength(str,{minLength: 10});
console.log(`${str}字节数>10:`,result2);
// 打印结果:富强prosperity/1/2/3字节数>10: true

let result3 = RegexpUtils.byteLength(str,{minLength: 10, maxLength: 12});
console.log(`${str}字节数>10&&<12:`,result3);
// 打印结果:富强prosperity/1/2/3字节数>10&&<12: false

let result4 = RegexpUtils.byteLength(str,{minLength: 10, maxLength: 20});
console.log(`${str}字节数>10&&<20:`,result4);
// 打印结果:富强prosperity/1/2/3字节数>10&&<20: true

3、匹配中文信息

let str = '富强prosperity 、民主democracy/1/2/3';
console.log(RegexpUtils.matchChinese(str));
// 打印结果:[ '富', '强', '、', '民', '主' ]

4、其他操作

let str = 'zhaoqingkaitt@163.com';

// 是否为邮箱
console.log('邮箱:', RegexpUtils.isEmail(str));
// 打印结果:邮箱: true

// 是否为中文
console.log('中文:', RegexpUtils.isChinese(str));
// 打印结果: 中文: false

// 是否为身份证号
console.log('身份证号:', RegexpUtils.isIdentityCard(str));
// 打印结果: 身份证号: false

// 是否为MAC地址
console.log('MAC地址:', RegexpUtils.isMac(str));
// 打印结果: MAC地址: false

// 是否为http地址
console.log('HTTP地址:', RegexpUtils.isUrl(str));
// 打印结果: HTTP地址: false

// 是否为整数
console.log('整数:', RegexpUtils.isInteger(str));
// 打印结果: 整数: false

// 纳税人识别号格式
console.log('整数:', RegexpUtils.isTaxpayerIdentificationNumber(str));
// 打印结果: 整数: false

5、去除空格

// 去除空格
RegexpUtils.trim(str);
// 去除前后空格
RegexpUtils.trimAround(str);
// 去除前空格
RegexpUtils.trimLeft(str);
// 去除后空格
RegexpUtils.trimRight(str);

6、单词转变量

let str= 'hello word';
//首字母大写
RegexpUtils.upperCaseFirst(str);
// 打印 HelloWord

// 首字母转小写
RegexpUtils.lowerCaseFirst(str);

// 小驼峰
RegexpUtils.lowerCamelCase(str);
// 打印 helloWord

7、身份证呈

// 是否为身份证号
RegexpUtils.isIdentityCard(idCard);
// 获取出生日期
RegexpUtils.getBirthdayStrByIdCard(idCard);
// 获取年龄
RegexpUtils.getAgeByIdCard(idCard);
// 获取性别
RegexpUtils.getSexByIdCard(idCard);
// 获取性别、年龄、出生日期
RegexpUtils.getPersonInfoByIdCard(idCard);

七、 对象操作

import {ObjectUtils} from 'great-jsutils';

/**
 * 清除对象中的空值
 */
function obj01(){
    let obj={a:null,b:'',c:2,d:'aa'};
    ObjectUtils.filter(obj);
    console.log('obj\t',obj); //obj   { c: 2, d: 'aa' }
}
/**
 * 清除对象中的空值。
 * 并指定其他需要强制移除的key
 */
function obj02(){
    let obj={a:null,b:'',c:2,d:'aa'};
    let removeKeys=['d'];
    ObjectUtils.filter(obj,{removeKeys});
    console.log('obj\t',obj);//obj   { c: 2}
}

/**
 * 根据指定函数确定需要移除的key
 * 下面示例将删除值长度为2 或 值为b的key
 */
function obj03(){
    let obj={a:'dd',b:'b',c:'ddd',d:'aa'};
    function fun(v){
        return v=='b' || v.length==2;
    }
    ObjectUtils.filter(obj,{fun});
    console.log('obj\t',obj);// { c: 'ddd' }
}

八、 number

1.1随机生成一组整数

默认返回一个小于10的整数,可以指定返回的最大值、最小值,以及返回的个数

import { NumberUtils } from 'great-jsutils';

示例1:随机生成一个小于10的整数

NumberUtils.randomInt();

示例2:随机生成一个小于100的整数

NumberUtils.randomInt({max:100});

示例3:随机生成四个大于等于10,小于100的整数

NumberUtils.randomInt({max:100,min:10,number:4})

1.2随机生成一组浮点数

默认返回一个小于10的浮点数,可以指定返回的最大值、最小值、小数位数,以及返回的个数

示例1:随机生成一个小于10的两位小数的浮点数

NumberUtils.randomInt();

示例2:随机生成一个小于100的两位小数的浮点数

NumberUtils.randomInt({max:100});

示例3:随机生成四个大于等于10,小于100的两位小数的浮点数

NumberUtils.randomInt({max:100,min:10,number:4})

示例4:随机生成四个大于等于10,小于100的三位小数的浮点数

NumberUtils.randomInt({max:100,min:10,number:4,scale3})

1.3 将数字转人民币大写

console.log(NumberUtils.changeToChinese(1200));

1.4 将阿拉伯数字转中文表示方式

console.log(NumberUtils.numberToChinese(12));

1.5 数字相加

console.log(NumberUtils.sum(1.1,1.3));// 2.4
console.log(1.1+1.3);//2.4000000000000004
  • 一组数字相加
console.log(NumberUtils.adds(1.001,1.3,1.4,2.33,12.3103));//18.3413

1.6 数字相减

console.log(NumberUtils.sub(1.1,1.2));

1.7 数字相乘

console.log(NumberUtils.mul(1.1,1.2));

1.8 数字相除

console.log(NumberUtils.div(1.1,1.2));

九、 DataTypeUtils

import {DataTypeUtils} from 'great-jsutils';
/**
 * 获取对象类型
 */
DataTypeUtils.getDataType(o);
/**
 * 是否为空对象
 */
DataTypeUtils.isNull(o);
/**
 * 是否为undefined
 */
DataTypeUtils.isUndefined(o);
/**
 * 是否为对象
 */
DataTypeUtils.isObject(o);
/**
 * 是否为数组
 */
DataTypeUtils.isArray(o);
/**
 * 是否为字符串
 */
DataTypeUtils.isString(o);
/**
 * 是否为数字
 */
DataTypeUtils.isNumber(o);
/**
 * 是否为布尔
 */
DataTypeUtils.isBoolean(o);
/**
 * 是否为函数
 */
DataTypeUtils.isFunction(o);
/**
 * 是否为日期
 */
DataTypeUtils.isDate(o);
/**
 * 是否为正则
 */
DataTypeUtils.isRegExp(o);
/**
 * 是否为错误对象
 */
DataTypeUtils.isError(o);
/**
 * 是否为Symbol对象
 */
DataTypeUtils.isSymbol(o);
/**
 * 是否为promise对象
 */
DataTypeUtils.isPromise(o);
/**
 * 是否为set对象
 */
DataTypeUtils.isSet(o);

十、 数据生成器:DataGeneratorUtils

import {DataGeneratorUtils} from 'great-jsutils';

1. 生成姓名

1.1、 生成一个姓名

let personName = DataGeneratorUtils.personName();

1.2、 生成多个姓名

let personNames = DataGeneratorUtils.personName({size:8});

2. 生成一个手机号

*2.1、 生成一个手机号

let mobile = DataGeneratorUtils.mobile();

*2.2、 生成多个手机号

let mobiles = DataGeneratorUtils.mobile({size:8});

3. 生成字母

参数 名称 必传 参数类型
size 个数 number
upperCase 转大写 boolean
length 长度 number
prefix 前缀 string
suffix 后缀 string

*3.1、 生成一个字母,默认为一个且为大写

let letter = DataGeneratorUtils.letter();
console.log(letter);//B

*3.2、 生成多个字母,通过length指定长度为2

let letters = DataGeneratorUtils.letter({length:2});
console.log(letters);//BD

*3.3、 生成多组字母

let letters = DataGeneratorUtils.letter({size:2});
console.log(letters);//['D', 'W']

*3.4、 生成多组字母,且长度为4

let letters = DataGeneratorUtils.letter({size:2, length:4});
console.log(letters);//['DACK', 'BKJA']

*3.5、 生成小写字母

let letters = DataGeneratorUtils.letter({length:4, upperCase:false});
console.log(letters);//aabc

4. 从数组中随机获取一个元素

let personName = DataGeneratorUtils.getElementByArray(array);

5. 生成邮箱

let email = DataGeneratorUtils.email({size:2});

6. 其他

5.1、随机生成整数、小数

可以指定最大数、最小数、生成的个数等

import {NumberUtils} from 'great-jsutils';

5.2、随机生成时间

可以格式化时间、获取一个月内、上下个月、上下个周内等

import {TimeUtils} from 'great-jsutils';

十一、 CommonUtils

1.1、 CommonUtils.isIos();

是否为ios系统

1.2、CommonUtils.isPC();

是否为pc端

1.3、 CommonUtils.browserType();

浏览器类型

1.4、CommonUtils.getRandomColor();

随机生成一个16进制颜色值

1.5、CommonUtils.uuid();

生成一个uuid

十二、ValueUtils

import {ValueUtils} from 'great-jsutils';

1.1、空值校验(isNullValue)

let a = [],a1={},a2=null,a3,a4=' ';
console.log('ValueUtils.isNullValue(',a,'):', ValueUtils.isNullValue(a));// 打印:true
console.log('ValueUtils.isNullValue(',a1,'):', ValueUtils.isNullValue(a1));// 打印:true
console.log('ValueUtils.isNullValue(',a2,'):', ValueUtils.isNullValue(a2));// 打印:true
console.log('ValueUtils.isNullValue(',a3,'):', ValueUtils.isNullValue(a3));// 打印:true
console.log('ValueUtils.isNullValue(',a4,'):', ValueUtils.isNullValue(a4));// 打印:false
console.log('ValueUtils.isNullValue(',a4,',true):', ValueUtils.isNullValue(a4, true));// 打印:true

1.2、是否为数字(isNumberValue)

let b="123", b1="a23", b2=23;
console.log('ValueUtils.isNumberValue(',b,'):', ValueUtils.isNumberValue(b)); // 打印:true
console.log('ValueUtils.isNumberValue(',b1,'):', ValueUtils.isNumberValue(b1));// 打印:false
console.log('ValueUtils.isNumberValue(',b2,'):', ValueUtils.isNumberValue(b2));// 打印:true

1.3、是否为空数组(isEmptyArray)

let c = [], c1, c2={}, c3=[1], c4=[{name:'张三'}];
console.log('ValueUtils.isEmptyArray(',c,'):', ValueUtils.isEmptyArray(c));// 打印:true
console.log('ValueUtils.isEmptyArray(',c1,'):', ValueUtils.isEmptyArray(c1));// 打印:false
console.log('ValueUtils.isEmptyArray(',c2,'):', ValueUtils.isEmptyArray(c2));// 打印:false
console.log('ValueUtils.isEmptyArray(',c3,'):', ValueUtils.isEmptyArray(c3));// 打印:false
console.log('ValueUtils.isEmptyArray(',c4,'):', ValueUtils.isEmptyArray(c4));// 打印:false

1.4、是否为非空数组(isNotEmptyArray)

十三 BrowserUtils

// 获取浏览器版本信息
BrowserUtils.getBrowser();

日志LogUtils

LoadjsUtils.dynamicLoads([
    `./assets/ueditor/ueditor.config.js`,
    `./assets/ueditor/ueditor.all.js`,
    `./assets/ueditor/lang/zh-cn/zh-cn.js`
]).then(() => {
});

SessionStroage

LoadjsUtils加载js文件

bug修复

2019.0817

key value
版本 1.2.0
升级说明 数组移除方法,子节点移除时优化

2019.0829

key value
版本 1.2.1
升级说明 根据json转model类
```
JsonUtils.toClassModel(jsonStr);
```
2019.0905
key value
版本 1.2.2
升级说明 增加BankCardUtils、AjaxUtils
```
JsonUtils.toClassModel(jsonStr);
```
2019.0929
key value
版本 1.2.4
升级说明 小数正则
```
RegexpUtils.isDecimal(num);
```
2019.1001
key value
版本 1.2.5
升级说明 代码格式化
```
HighlightUtils.syntaxHighlight(num);
HighlightUtils.formatFunction(fn,fnName);
HighlightUtils.formatText(num);
HighlightUtils.formatHtml(num);
HighlightUtils.escapeHtml(num);
```
2019.1004
```
//深拷贝
ObjectUtils.deepClone
```
2019.1008
```
//深拷贝
ObjectUtils.clone
//数据类型
DataTypeUtils.is……
```

2019.1013

key value
版本 1.2.6
升级说明 json转实体
```
toClassModel(json,{notes:false})
```

2019.1026

key value
版本 1.3.1
升级说明 生成数字优化
```
toClassModel(json,{notes:false})
```

2020.0801

key value
版本 1.3.6
升级说明 空值判断

感谢你的支持,我将持续优化我的服务,希望为你提供更大的帮助!
感谢你的支持
感谢你的支持,我将持续优化我的免费的服务,希望为你提供更大的帮助!
![感谢你的支持](data:image/png;base64,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%0AXsnTTKpBMTl16lSNcMPyn3nmGZ