post react-native_react-native post - CSDN
  • react-native-pg-utils 对react-native全局进行配置,对内置对象原型链增加方法,增加常用全局方法. 每次新建react-native项目之后都会发现有一些很常用的方法在这个项目中也会用到,有些对全局的配置(禁用模拟器上...

    react-native-gp-utils

    对react-native全局进行配置,对内置对象原型链增加方法,增加常用全局方法.

    每次新建react-native项目之后都会发现有一些很常用的方法在这个项目中也会用到,有些对全局的配置(禁用模拟器上显示黄框,release发布版本中时console打印失效等).这些如果在新项目中在搞一次的话的确是很麻烦,所以我就将其封装成了这个库.

    github地址: https://github.com/geek-prince/react-native-gp-utils

    npm地址: https://www.npmjs.com/package/react-native-gp-utils

    文章目录

    安装

    npm install react-native-gp-utils --save

    如何使用

    首先导入插件

    三种侵入式等级(根据情况选择其中一种方式导入)

    • 0:非侵入式:每个要用到的方法的文件中都要导入指定的工具类,并以工具类.方法名的方式调用方法.

      • 优点:不会占用任何一个全局变量和任何一个内建对象(Array,String对象等)的prototype原型链属性,不会造成全局变量污染
      • 缺点:每个要使用的文件都要导入相应的库文件,不方便
    • 1:部分侵入式(推荐):只用在入口文件中导入一次即可,并以工具类.方法名方式调用方法,内建对象以arr.unshiftFromIndex的形式调用.

      • 优点:相对方便,只用入口文件导入一次,其他文件都可以使用.
      • 缺点:会占用与各个工具类名相同的全局变量的属性(也可把各个工具类名定义为自定义的变量名),以及各个内建对象(Array,String对象等)的prototype原型链的与方法名相同的属性
    • 2:完全侵入式:只用在入口文件中导入一次即可,并以方法名方式直接调用方法,内建对象以arr.unshiftFromIndex的形式调用.

      • 优点:非常方便,在入口文件中导入一次即可,在任何地方使用任何方法,只用直接用方法名就可以调用方法.
      • 缺点:会占据各个工具类中所有和方法名相同的全局变量(会造成全局变量污染),和各个内建对象(Array,String对象等)的prototype原型链的与方法名相同的属性

    三种侵入式等级分别导入插件的方式

    导入库->设置配置选项(可选)->自定义各个库文件名(可选,在侵入式等级1中使用)->给出侵入式等级初始化

    1.导入库

    import GPUtils from 'react-native-gp-utils';
    

    2.设置配置选项(可选)

    GPUtils.configs={yellowBoxOn:true}; //这里设置打开警告提示黄框
    

    3.自定义各个库文件名(可选,在侵入式等级1中使用)

    //这里表示将CommonUtils,ArrayUtils工具类的名称分别自定义为CU,AU,没给出的按默认的工具类的名称.
    GPUtils.namesMap={CommonUtils:'CU',ArrayUtils:'AU'};
    

    4.给出侵入式等级初始化

    4.1.以侵入式等级0初始化
    // let {CommonUtils,ArrayUtils}=GPUtils.initWtihInvadeScale(0);
    // 也可以向下面这样为之自定义名称
    let {CommonUtils:CU,ArrayUtils:AU}=GPUtils.initWtihInvadeScale(0);
    
    4.2.以侵入式等级1初始化(推荐)
    GPUtils.initWtihInvadeScale(1); //自定义名称在上面第3步
    
    4.3.以侵入式等级2初始化
    GPUtils.initWtihInvadeScale(2); //完全侵入,不支持自定义名称(因为每个方法名都会成为全局变量)
    

    可配置选项(上面第2步)

    配置项 说明 默认值
    yellowBoxOn 指定警告黄框(即在打印warn警告信息时,模拟器先放出现的警告黄框)是否开启 false:关闭(系统默认是开启)
    releaseLogOn 指定是否在release发布版本中打印log的信息(release版本中系统默认是不会将console.log打印除去的,但是又不可能发布前特地删一次所有注释,所以直接导入库就行了,默认就会在release版本清除log打印) false:关闭release版本中的打印

    拓展的工具类及其对应的功能

    方法的四种类型,下面会有解释

    • CommonUtils:一些全局都可能用到的常用方法(里面全部为normal:普通方法)
    • MathUtils:一些和计算相关的方法(里面全部为normal:普通方法)
    • RNUtils:对react-native组件api的简单封装,常用值的导出,适配问题的一些处理(里面全部为normal:普通方法,与普通属性变量)
    • RegExpUtils:一些和正则相关的方法(里面全部为normal:普通方法)
    • RandomUtils:一些和随机相关的方法(里面全部为normal:普通方法)
    • 内建对象的工具类:
      • ArrayUtils:对内建对象Array拓展的相关方法(里面的方法全部为baseOnInvadeScale)
      • DateUtils:对内建对象Date拓展的相关方法(里面方法有普通方法,也有both类型)
      • NumberUtils:对内建对象Number拓展的相关方法(里面的方法全部为onlyProto)
      • ObjectUtils:对内建对象Object拓展的相关方法(本来在Object的原型链上加方法会使调用很简便,但是这样的做法被rn拒绝了,所以这里面的方法都是normal:普通方法)
      • StringUtils:对内建对象String拓展的相关方法(里面方法有baseOnInvadeScale类型,也有onlyProto类型,也有both类型)
    • 其他方面的工具类:
      • FileUtils:一些和文件相关的方法(里面的方法都是normal:普通方法)
      • DebugUtils:一些在开发或调试中要到的方法(里面的方法都是normal:普通方法)

    三种侵入式导入调用四种类型方法的方式

    四种类型的方法

    • 1.normal:普通方法.直接调用的方法.
    • 2.baseOnInvadeScale:依据侵入式等级来决定.侵入式非0时提供prototype原型链方法,但是在侵入式为0的方法导入时为了不占用原型链中的属性,这类方法在侵入式0中调用方式与普通方法一致,第一的参数就是要进行操作的该对象本身
    • 3.both:同时提供prototype原型链的方法和与之对应的方法.这类方法在侵入式等级为0时提供一个普通方法.侵入式等级为非0时会提供2种方法,一种是直接在写在内建对象的原型链上的方法,一种是与之对应的普通方法
    • 4.onlyProto:只提供prototype原型链的方法.侵入式为0时这些方法就不存在了.

    四种类型的方法在三种侵入式等级下分别的调用方式

    所有方法的详细介绍在下面,这里先用其中几个方法介绍一下调用方式

    normal:普通方法.(以CommonUtils中的loop方法(统一管理循环,遍历的方法)为例)

    • 侵入式0的调用方式:
    //按照上面方法导入之后
    CommonUtils.loop(10,(i)=>{console.log(i)}); //输出0到9
    //可以自定义别名导入,这时的调用方式就位(所有方法类型都可以自定义别名,侵入式1也一样,下面就不累赘写以别名方式调用的内容了)
    let {CommonUtils:CU}=GPGlobal.initWtihInvadeScale(0);
    CU.loop(10,(i)=>{console.log(i)});
    
    • 侵入式1的调用方式:
    //和上面侵入式0调用方式一样,只是会占用对应的全局变量
    
    • 侵入式2的调用方式:
    loop(10,(i)=>{console.log(i)}); //直接方法名调用
    

    baseOnInvadeScale类型.(以ArrayUtils中的unshiftFromIndex方法(将数组中指定索引的元素移动到最前面去)为例)

    • 侵入式0的调用方式:
    let arr=[1,2,3,4,5];
    ArrayUtils.unshiftFromIndex(arr,1,3); //结果为[2, 1, 3, 4, 5] 将所因为3的元素移到最前面
    
    • 侵入式1和侵入式2的调用方式:
    let arr=[1,2,3,4,5];
    arr.unshiftFromIndex(1,3); //因为是数组原型链上的方法,所以直接这样调用,而且相对于侵入式0的滴啊用方法,也少了第一个参数(即当前这个数组),
    

    both类型.(以DateUtils中的getDateDiff方法(计算两个日期时间之间的差值)为例)

    • 侵入式0的调用方式:
    let startTimeStr='2017-11-11 11:11:11';
    let endTimeStr='2017-11-12 10:10:10';
    DateUtils.getDateDiff(startTimeStr,endTimeStr); //结果为1
    
    • 侵入式1的调用方式:
    //侵入式1提供两种方法,一种是普通方法,调用方式就和上面的侵入式0的调用方式一样;一种是原型链上的方法(向下面这样调用)
    let startTimeStr='2017-11-11 11:11:11';
    let date=DateUtils.getDateObj(startTimeStr); //这个方法用于通过字符串,时间戳获得一个日期对象,date此时就为日期对象,详情看下面的介绍.
    let endTimeStr='2017-11-12 10:10:10';
    date.diff(endTimeStr); //直接通过这种原型链方法的形式调用,为了简便,在原型链中的方法为diff,both类型方法具体普通方法与原型链方法一不一致,看具体方法中的说明.
    
    • 侵入式2的调用方式
    //普通方法和侵入式2在normal:普通方法的调用相同
    //原型链方法和上面侵入式1的调用方式相同
    

    onlyProto类型.(以NumberUtils中的toFloatStr方法为例)

    • 侵入式1和侵入式2的调用方式(onlyProto类型的方法侵入式0中没有):
    let num=18.12345;
    num.toFloatStr() //结果为"18.12"
    

    各个工具类中的方法

    为了方便,下面没有特别说明都以侵入式等级2为例讲解,比较简单的方法就不给出示例了

    CommonUtils:一些全局都可能用到的常用方法(里面全部为normal:普通方法)

    toStr(obj)

    • 说明:对obj对象调用Object最原始的toString方法
    • 示例:
    toStr({})
    // 返回"[object Object]"
    

    判断当前数据的类型的一些列方法:

    isNumber(obj)

    • 说明:判断obj是不是数字或Number对象,返回布尔值

    isString(obj)

    • 说明:判断obj是不是数字或String对象,返回布尔值

    isBool(obj)

    • 说明:判断obj是不是布尔类型,返回布尔值

    isArray(obj)

    • 说明:判断obj是不是数组类型,返回布尔值

    isObj(obj)

    • 说明:判断obj是不是对象类型,返回布尔值

    isDate(obj)

    • 说明:判断obj是不是日期对象类型,返回布尔值

    isRegExp(obj)

    • 说明:判断obj是不是RegExp正则对象类型,返回布尔值

    getNewObj(obj)

    • 说明:获得一个全新的和obj值一样的对象或数组(该方法也在ArrayUtils中被用到数组的原型链属性deepCopy上)
    • 示例:
    let arr=[1,2,3,4,5];
    let copyArr=getNewObj(arr);
    copyArr===arr
    // 返回false,得到一个至完全相同单地址不同的数组
    

    loop(obj,callBack)

    • 说明:对数组,对象进行遍历,指定范围进行for循环的统一循环方法
    • 参数:
      • obj:要循环的数组,对象,指定范围的数字
      • callBack:每次循环要做的操作
    • 示例:
    //对指定范围进行循环
    loop(10,(i)=>{console.log(i)}) //输出0到9
    //对数组进行循环
    let arr=[1,2,3,4,5,6,7];
    loop(arr,(i,k)=>{console.log(i,k)});//输出数组中的每一个索引与其对应的值
    //对对象进行循环
    let obj={a:10,b:20,c:30};
    loop(obj,(k,v)=>{console.log(k,v)})//输出对象中的每一个键值对
    
    //loop的回调函数中break,continue不可用,但是可以用return做出break,continue,return的操作
    //break操作(比如,到5时退出,这时只需要return 1(这里的1可以用任何一个无意义的,不是undefined的值就行)即可)
    loop(10,(i)=>{
      if(i===5){return 1}
      console.log(i);// 打印出0到4
    });
    //continue操作(比如,到5时跳过此次循环,进行下一次循环,只需要return undefined即可)
    loop(10,(i)=>{
      if(i===5){return undefined}
      console.log(i);// 打印出0-4,6-9
    });
    //return操作(比如返回i值,像正常return一样返回即可,该返回值则为loop方法的返回值,可以拿到返回值后做其他操作,也可以再继续将该返回值再次return出去)
    let result=loop(10,(i)=>{
      if(i===5){return i}
      console.log(i);// 打印0到4
    });
    console.log(result);//打印5
    //可以继续return出去,这样就和正常for循环时的return一样了
    function test() {
      return loop(10,(i)=>{
        if(i===5){return i}
        console.log(i);// 打印0到4
      });
    }
    let result=test();
    console.log(result);//打印5
    

    getBool(obj)

    • 说明:根据传入的参数返回布尔值.该方法将空数组[],空对象{},数值为0的字符串’0’,空白字符串’ ‘,也列入false中.(自动转布尔值的情况:0,NaN,null,undefined,’'为false,其他情况为true)

    getFuncName(args)

    • 说明:获取当前调用方法的方法名(调用时getFuncName(arguments))(在es6下的部分方法中会报错)(在DebugUtils中的logFuncName中会用到该方法)
    • 参数:
      • args:要打印方法名的方法的arguments,要在方法中将arguments当做参数传进来(因为rn中没有arguments.caller)
    • 示例:
    function Test() {
        console.log(getFuncName(arguments));
    }
    // 打印出Test
    

    isNumeric(strNum,maxDecimalNum=null,ifTrim=true,positive=false)

    • 说明:判断传入参数是不是一个数字或一个字符串类型的数字(1 ‘37’ 1.73 ‘21.43’)(还可以指定判断小数点后可以最多有多少位)
    • 参数:
      • strNum:传入的要判断的参数(数字,字符串)
      • maxDecimalNum:如果要限制最多小数位数时传入的最多位数的数字参数(如果传入的参数strNum的小数位数超过toFixed给定的值就返回false,没超过返回true),0时限制为只能是整数,null时为无限制(只要是数字就行)(默认为null)
      • ifTrim 判断时是否忽略左右空格(默认为true,忽略)
    • 特殊用法:可以用在用户在输入框TextInput中输入数字之后的校验与限制
    isNumeric('123.6765')// 结果true
    isNumeric('123.6765',2)// 结果false
    isNumeric(' -234.67 ',2,)// 结果true
    isNumeric(' -546.12 ',2,false)// 结果false
    isNumeric(' -123.67 ',2,true,true);// 结果false
    isNumeric(123.67,2,true,true);// 结果true
    

    numToFixedLenStr(num,len=2,char=‘0’)

    • 说明:将数字或字符串类型的数字前面加上’0’或指定的字符,到达指定的长度,并返回字符串(为了方便调用,该方法被加入到NumberUtils和StringUtils中作为Number与String对象的原型链方法,名称为toFixedLenStr,详情看相应的方法说明)
    • 参数:
      • num 要转化的数字或字符串类型的数字
      • len 最后输出的字符串的长度(默认为2)
      • char 指定填充数字前面的字符为什么,默认为"0"
    • 示例:
    numToFixedLenStr('8') //结果为"08"
    numToFixedLenStr('18',4) //结果为"0018"
    numToFixedLenStr('18',4,'*') //结果为"**18"
    numToFixedLenStr(18,4,'*') //可以是数字
    

    MathUtils:一些和计算相关的方法(里面全部为normal:普通方法)

    js精确的加减乘除(js对浮点数的运算会存在问题,无论加减乘除,所以加入这些方法).
    这些方法在NumberUtils和MathUtils中都被加入到Number对象和String对象的原型链中了,名称分别为add,sub,mul,div,详情看相应的方法说明.
    方法中除了可以传数字,也可以传字符串类型的数字
    

    accAdd(arg1,arg2)

    • 说明:精确加法函数,用来得到精确的加法结果
    • 示例:
    12.4249+6.8 //结果为19.224899999999998
    accAdd(12.4249,6.8) //结果为19.2248
    accAdd('12.4249','6.8') //传入参数也可以是字符串类型的数字,结果同上
    

    accSub(arg1,arg2)

    • 说明:精确减法函数,用来得到精确的减法结果(arg1-arg2)
    • 示例:
    10.3-9.2 //结果为1.1000000000000014
    accSub(10.3,9.2) //结果为1.1
    

    accMul(arg1,arg2)

    • 说明:精确乘法函数,用来得到精确的乘法结果
    • 示例:
    0.7*8.1 //结果为5.669999999999999
    accMul(0.7,8.1) //结果为5.67
    

    accDiv(arg1,arg2)

    • 说明:精确除法函数,用来得到精确的除法结果(arg1除以arg2)
    • 示例:
    5.67/8.1 //结果为0.7000000000000001
    accDiv(5.67,8.1) //结果为0.7
    

    dealWithFloatStr=(strNum,toFixed=2,type=‘round’,inputType=‘both’,returnType=true)

    • 说明:将一个字符串类型的数字(或数字类型的值)进行处理(保留小数后几位,舍去部分是四舍五入,还是向上/向下取整)(为了更方便的处理类似问题,这个方法在NumberUtils,StringUtils和ArrayUtils中都被相应的方法(toFloat,toFloatStr)用到,并加入到Number对象,String对象和Array对象的原型链中了,详情看相应的方法说明.)
    • 参数:
      • strNum 要处理的字符串类型的数字(或数字类型的值)
      • toFixed 要保留的小数位数. 0为不保留小数只取整数,null时为保持原有小数位数(默认为2)
      • type 是四舍五入,还是向上/向下取整. 'round’为四舍五入;'up’或’ceil’为向上取整;'sub’或’floor’为向下取整. 向上/向下取整同时适用于小数 dealWithFloatStr(‘1321.123459’,5,‘sub’) 执行后"1321.12345"
      • inputType 输入的类型可以为什么. 'both’时数字或数字字符串都会进行处理;'num’时只会处理数字(此时传入字符串的话会原样返回);'str’时只会处理数字字符串(此时传入数字的话会原样返回).(默认为both)
      • returnType 返回类型为什么. true时为字符串,false时为数字类型
    • 示例:
    dealWithFloatStr('12.3456') //结果为"12.35"
    dealWithFloatStr('12.3456',1) //结果为"12.3"
    dealWithFloatStr('12.3456',1,'up') //结果为"12.4"
    dealWithFloatStr('12.3456',3,'sub') //结果为"12.345"
    dealWithFloatStr('12.3456',3,'sub','num') //结果为"12.3456"
    dealWithFloatStr(12.3456,3,'sub','num',false) //结果为12.345
    

    RNUtils:对react-native组件api的简单封装,常用值的导出,适配问题的一些处理(里面全部为normal:普通方法,与普通属性)

    一些常用属性:

    w

    • 说明:当前设备屏幕的宽度

    h

    • 说明:当前设备的高度

    isios

    • 说明:当前设备是不是iOS设备,布尔值

    一些常用api的简单封装:

    openUrl(url)

    • 说明:在浏览器中打开指定url的方法
    • 参数:
      • url:要打开的url

    openPhone(phoneNum)

    • 说明:打开电话拨号界面,并在里面填入phoneNum的电话号码
    • 参数:
      • phoneNum:要在拨号界面填入的号码

    setClipboard(test)

    • 说明:设置一段文字到剪贴板

    get(url,args={})

    • 说明:fetch方法以get方式请求json数据的简单封装
    • 参数:
      • url:url地址,即fetch的第一个参数
      • args:可选参数,fetch的第二个参数,可以用来定制 HTTP 请求一些参数。你可以指定 header 参数,或是指定使用 POST 方法,又或是提交数据等等
    • 示例:
    get('http://baike.baidu.com/api/openapi/BaikeLemmaCardApi?scope=103&format=json&appid=379020&bk_key=%E9%93%B6%E9%AD%82&bk_length=600',)
        .then((jsonData)=>{
            console.log(jsonData);
        })
        .catch((error)=>{
            console.log(error);
        });
    

    post(url,bodyData,headers={})

    • 说明:fetch方法以post方式请求json数据的简单封装
    • 参数:
      • url:url地址,即fetch的第一个参数
      • bodyData:post的body数据.可以是对象,在’Content-Type’: ‘application/json’时(默认是这个);可以是字符串,在’Content-Type’: 'application/x-www-form-urlencoded’时.
      • headers:给出相应的头部信息.
    • 示例:
    //以'Content-Type': 'application/json'方式发送请求时
    post('http://baike.baidu.com/api/openapi/BaikeLemmaCardApi',
        {scope:103,format:'json',appid:379020,bk_key:'银魂',bk_length:600})
        .then((jsonData)=>{
            console.log(jsonData);
        })
        .catch((error)=>{
            console.log(error);
        });
    //以'Content-Type': 'application/x-www-form-urlencoded'方式发送请求时,需要给出第三个参数headers
    post('http://baike.baidu.com/api/openapi/BaikeLemmaCardApi',
        'scope=103&format=json&appid=379020&bk_key=银魂&bk_length=600',
        {'Content-Type': 'application/x-www-form-urlencoded'})
        .then((jsonData)=>{
            console.log(jsonData);
        })
        .catch((error)=>{
            console.log(error);
        });
    

    一些适配相关的方法:

    setFontSize(fontSize)

    • 说明:根据像素密度设置字体大小(用于老版本的rn,老版本中相同字体大小在不同设备上会有问题,新版本的rn中则没有该问题,忽略该方法)

    RegExpUtils:一些和正则相关的方法(里面全部为normal:普通方法)

    isPhoneNum(str)

    • 说明:检验手机号合理性(传入的str字符串是不是手机号),返回布尔值

    isEmail(str)

    • 说明:检验邮箱合理性(传入的str字符串是不是邮箱),返回布尔值

    pushRegExpKeyToArr(obj,reg)

    • 说明:将对象中的key或数组中的元素符合指定的正则表达的放入到数组中,并返回
    • 参数:
      • obj:传入的对象或数组
      • reg:传入的正则表达式
    • 示例:
    let arr=['ro123ot','root','fdhfi','raew'];
    pushRegExpKeyToArr(arr,/ro.*ot/);
    // 返回["ro123ot", "root"]
    // 如果传入参数为对象,则返回的数组中的元素是传入对象键(key)中符合正则的的
    

    RandomUtils:一些和随机相关的方法(里面全部为normal:普通方法)

    getRandom(num1,num2)

    • 说明:获得随机数.没有传num1和num2时,生成一个0-1的随机数;只有num1的时候生成一个0-num1的int整形数;num1,num2都有时生成一个num1-num2的int整形随机数.

    getRandomNumStr(num1,num2)

    • 说明:和上面方法功能是一样的,只是将返回结果转换为字符串而已

    getRandomFromArr(arr)

    • 说明:从数组中获得随机的数组元素(每个元素权重相同,获得概率相同)

    getRandomFromArrWithWeight(arr,weightArr)

    • 说明:从数组中获得随机的数组元素(带有比重的,每个元素获得概率可以自己指定)
    • 参数:
      • arr:要从中随机元素的数组
      • weightArr:指定比重的数组(该数组元素个数应该与arr中的元素个数相同,而且每个元素都是int类型)
    • 示例:
    let arr=['第一个数','第二个数','第三个数','第四个数'];
    let weightArr=[1,2,3,4];
    //loop是该库中的一个方法用于统一管理循环的方法(上面有讲解)
    loop(10,()=>{
      let random=getRandomFromArrWithWeight(arr,weightArr);
      console.log(random); //这样'第一个数','第二个数','第三个数','第四个数'输出的概率就分别是十分之一,十分之二,十分之三,十分之四
    });
    

    getRandomStr(num=4,type=‘all’,ifEq=true)

    • 说明:获取指定个数的随机字符串
    • 参数:
      • num:生成随机字符串的个数(默认为4)
      • type:指定生成随机字符串的类型.‘num’:只有数字,‘char’:只有字母,‘lowChar’:只有小写字母,‘upChar’:只有大写字母,‘all’:字母数字都有(默认为’all’)
      • ifEq:如果type为"all"时,字母出现概率和数字出现概率是否要一致(是概率是否一致,不是数量是否一致),布尔类型(默认为true,false时字母概率大于数字)
    • 示例:
    getRandomStr(16,'all',true)
    // 结果 "7a314W55nupLV8P4" (16位的既有数字又有字母的随机数,且数字和字母出现概率相同)
    

    getRandomPhone()

    • 说明:生成一个11位的随机的手机号码

    内建对象的工具类部分:

    ArrayUtils:对内建对象Array拓展的相关(里面的方法全部为baseOnInvadeScale,因为关联数组不常用,所以这里面的所有方法都是针对索引数组的)

    contains(value,allEqual=true)

    • 说明:查看元素是否在数组中的方法
    • 参数:
      • value:要检查是否存在的元素
      • allEqual:是否全等判断.true时为必须全等===,false为==.(默认为true)
    • 返回值:返回布尔值,表示是否存在指定元素

    deleteValue(value,allEqual=true,deleteAll=true)

    • 说明:从数组中删除指定元素的方法
    • 参数:
      • value:要删除的元素
      • allEqual:是否要全等的元素才删除.true时为必须全等===,false为==.(默认为true)
      • deleteAll:是否要删除指定的全部元素.true时为全部删除,false时为只删除第一个(默认为true)
    • 返回值:数组的元素会被删除,方法返回值也就是这个删除过元素的数组,所以你可以对它进行链式操作
    • 示例:
    let arr=[1,2,3,4,5,2,3,6,1,3,2];
    arr.deleteValue(3); //结果 [1, 2, 4, 5, 2, 6, 1, 2] ,将多有3的元素都删除了
    arr.deleteValue(2,true,false) //结果 [1, 4, 5, 2, 6, 1, 2] ,只删除了第一个2的元素
    arr.deleteValue(2).push(100); //可以对其进行链式操作
    

    spliceOne(index)

    • 说明:splice指定索引的一个元素,并返回这个元素(而不是数组,因为splice返回的是一个数组,就算只有一个元素)

    sum()

    • 说明:求出数组中所有元素和的方法(数组中的元素必须全部是数字或字符串类型的数字,否则返回NaN)
    • 示例:
    let arr=[1,2,3,4,5,2,3,6,1,3,2,'12','6',1.1,'6.8']
    arr.sum() //结果为57.9
    

    移动数组元素的几个方法:

    unshiftFromIndex(index)

    • 说明:把数组中指定位置的元素移动到最前面去
    • 特殊用法:比如一个列表中的内容根据访问时间排序,点击之后就要把它移动到最上面去,就可以用这个方法
    • 返回值:返回的就是处理之后的该数组,所以可以对其进行链式操作
    • 示例:
    let arr=['现在最新的内容','现在第二新的内容','现在正准备点击之后变成最新的内容','现在最后的内容'];
    arr.unshiftFromIndex(2) 
    //结果为["现在正准备点击之后变成最新的内容", "现在最新的内容", "现在第二新的内容", "现在最后的内容"]
    arr.unshiftFromIndex(2).unshiftFromIndex(3) //可以对其进行链式操作
    

    pushFromIndex(index)

    • 说明:把数组中指定位置的元素移动到最后面去
    • 返回值:返回的就是处理之后的该数组,所以可以对其进行链式操作
    • 示例:
    let arr=[0,1,2,3,4,5];
    arr.pushFromIndex(2); //结果为[0, 1, 3, 4, 5, 2]
    

    moveToIndexFromIndex(fromIndex,toIndex)

    • 说明:把数组中指定位置的元素移动到指定位置去
    • 参数:
      • fromIndex:要移动的索引
      • toIndex:移动到哪个位置的索引
      • 返回值:返回的就是处理之后的该数组,所以可以对其进行链式操作
    • 特殊用法:比如用户手指滑动列表项,改变列表项顺序
    • 示例:
    let arr=[0,1,2,3,4,5];
    arr.moveToIndexFromIndex(1,3) //结果为[0, 2, 3, 1, 4, 5]
    

    deepCopy()

    • 说明:把当前数组深拷贝一份并返回(就是上面CommonUtils中的getNewObj方法)
    • 示例:
    let arr=[0,1,2,3,4,5];
    let arr1=arr.deepCopy(); //arr1与arr内容完全相同
    arr1===arr //返回false,不是同一个对象
    

    eachToFloat(args)

    • 说明:将数组内的所有数字或数字字符串转换为指定小数位数的数字或数字字符串(其中的每个元素调用MathUtils中的dealWithFloatStr方法,详情可以去查看该方法)
    • 参数:
      • args 因为参数比较多,所以以对象的方式传入可选参数
        • ifChangeArr 表示是否直接改变原数组,为true时直接改变调用方法的数组,此时返回值没有意义所以是个空数组;false时不改变原数组,而是返回一个新数组,要在外面用变量接收(默认为ture,改变)
        • ifRecursion 表示是否递归(是否将数组中的数组/对象也进行该方法的调用)(默认为true)
        • toFixed 保留小数点后几位(与dealWithFloatStr方法中一样)(默认为2)
        • type 四舍五入,还是向上/向下取整(与dealWithFloatStr方法中一样)(默认为’round’,四舍五入)
        • inputType 要进行处理操作的类型.'both’时数字或数字字符串都会进行处理;'num’时只会处理数字;‘str’时只会处理数字字符串.(与dealWithFloatStr方法中一样)(默认为’both’,都进行处理)
        • outputType 处理后返回的类型.'origin’时保持原类型,输入是数字返回就是数字,输入是字符串,返回就是字符串;'num’时不管是数字还是字符串类型的数字都会转换为数字;‘str’时不管是数字还是字符串类型的数字都会转换为字符串类型的数字.(默认为’'origin,保持原类型)
    • 示例:
    //下面的结果都是JSON.stringify()后的输出
    let arr=[10,123,'123',[832.123,'1234.123','dsadf12'],{a:10.123,b:'123.86',c:'123dsa'}];
    let finalArr=arr.eachToFloat({ifChangeArr:false}); 
    //上面arr结果没变,finalArr结果为"[10,123,"123.00",[832.12,"1234.12","dsadf12"],{"a":10.12,"b":"123.86","c":"123dsa"}]"
    finalArr=arr.eachToFloat({ifChangeArr:false,ifRecursion:false}); 
    //上面finalArr的结果为"[10,123,"123.00",[832.123,"1234.123","dsadf12"],{"a":10.123,"b":"123.86","c":"123dsa"}]"其中的对象和数组就没有参与处理
    finalArr=arr.eachToFloat({ifChangeArr:false,toFixed:1,type:'up',outputType:'str');
    //上面finalArr的结果为"["10.0","123.0","123.0",["832.2","1234.2","dsadf12"],{"a":"10.2","b":"123.9","c":"123dsa"}]"
    arr.eachToFloat({toFixed:3,type:'sub',inputType:'str'});
    //上面这样就会直接改变数组中相应的值,这样就不用外界用变量接收了.arr的结果为"[10,123,"123.000",[832.123,"1234.123","dsadf12"],{"a":10.123,"b":"123.860","c":"123dsa"}]"
    

    DateUtils:对内建对象Date拓展的相关(里面方法有普通方法,也有both类型,具体类型,看下面各个方法的方法介绍中)

    getDateObj(date)

    • 说明:根据传进来的日期(可以是Date对象,也可以是字符串类型的日期,也可以是时间戳的Int)将其转换为日期对象.(为了方便使用该方法分别在NumberUtils和StringUtils中加入到了Number和String的原型链中,名称为toDate)
    • 方法类型:普通方法
    • 参数:
      • date 日期值,可以是Date对象,也可以是字符串,也可以是时间戳的Int.(字符串支持的形式:‘2018-08-07 15:51:59’,‘15:51:59 2018-08-07’,‘15:51:59 08/07/2018’,'08/07/2018’等等,反正只要不是太奇葩的都可以转成功)
    • 示例:
    getDateObj('2012-12-12 00:00:00'); //结果成功生成对象Wed Dec 12 2012 00:00:00 GMT+0800 (CST)
    getDateObj(1455241600000); //可以是时间戳的Int
    

    formatDate(date,formatStr=‘yyyy-MM-dd hh:mm:ss’)

    • 说明:将日期对象格式化为指定格式的字符串形式
    • 方法类型:both(特别说明:原型链上的方法名为了简介,方法名为format)
    • 参数:
      • date 要格式化的日期(可以是Date对象,也可以是字符串类型的日期,也可以是时间戳的Int)
      • formatStr 要格式化为什么形式的字符串.M表示月,d表示日,h表示小时,m表示分钟,s表示秒,q表示季度,S表示毫秒(比如默认为"yyyy-MM-dd hh:mm:ss")
    • 示例:
    formatDate('2012-12-12') //结果为"2012-12-12 00:00:00"
    formatDate('2012-12-12 12:12:12','yyyy/MM/dd hh:mm') //结果为"2012/12/12 12:12"
    formatDate(1455241600000,'yyyy/MM/dd hh:mm') //可以是Int类型的时间戳,结果为"2016/02/12 09:46"
    let date=new Date();
    formatDate(date,'yyyy/MM/dd hh:mm') //可以是日期对象
    date.format('yyyy/MM/dd hh:mm') //因为是both类型的方法,所以可以通过这种形式来调用
    

    addOrSubDate(date,num,dayOrMouth=‘day’,addOrSub=‘add’,ifChangeDate=true,isBehindZero=false)

    • 说明:在当前日期上加减(几天,几月,几年),并且返回处理后的日期对象
    • 方法类型:both
    • 参数:
      • date 在哪个日期的基础上增减,可接收日期对象或字符串类型的日期或Int类型的时间戳(传入的是日期对象时).
      • num 要加上或减去(年月日)的数量
      • dayOrMouth 要加减的是(日 月 还是年…), ‘year’,‘month’,‘day’,‘hour’,‘min’,‘second’(默认为’day’,天为单位)
      • addOrSub 加还是减.(默认是’add’,加)
      • ifChangeDate 传入的date为日期对象时,是否要改变原始的date对象值(即变成加/减后的日期对象)(默认为true,改变)
      • isBehindZero 当设置为true时,比如加一天后的时间为第二天的0点0分0秒,加一月时为第二月的第一天的0点0分0秒;减一天后的时间为当天的0点0分0秒,减一月后为当月的第一天的0点0分0秒.(默认为false)
    • 示例:
    let dateStr='2012-12-12 12:12:12';
    addOrSubDate(dateStr,1); //结果为Thu Dec 13 2012 12:12:12 GMT+0800 (CST)
    addOrSubDate(dateStr,1,'month','sub'); //结果为Mon Nov 12 2012 12:12:12 GMT+0800 (CST)
    let timestamp=1455241600000;
    addOrSubDate(timestamp,2,'hour','sub') //也可以是Int类型的时间戳,结果为Fri Feb 12 2016 07:46:40 GMT+0800 (CST)
    let date=new Date();
    addOrSubDate(date,2,'hour','sub') //也可以是date对象,结果中改变了原来的date对象
    addOrSubDate(date,2,'day','sub',false,true) //这样就不改变原来的日期对象了.结果为Sat Oct 20 2018 00:00:00 GMT+0800 (CST)
    date.addOrSubDate(2,'day','sub',false,true) //因为是both类型的方法,所以可以通过这种形式来调用
    

    addOrSubDateFormat(num,formatStr=‘yyyy-MM-dd’,date=’’,dayOrMouth=‘day’,addOrSub=‘add’,isBehindZero=false)

    • 说明:在当前日期上加减(几天,几月,几年),并且返回格式化后的字符串日期形式(使用方法和上面的方法一样,只是多了第二个参数formatStr用于指定返回日期字符串的格式化形式)
    • 方法类型:both
    • 示例:
    addOrSubDateFormat('2012-12-12 12:12:12',1); //结果为"2012-12-13"
    let date=new Date();
    date.addOrSubDateFormat(3); ////因为是both类型的方法,所以可以通过这种形式来调用
    

    getDateDiff(startTime, endTime, diffType=‘day’,ifAbs=true)

    • 说明:计算两个日期之间的时间差(计算结果是向上取整的,返回都是整数,比如diffType时间差单位’day’天时,如果两个时间相减后不足1天,返回就是1)
    • 方法类型:both(特别说明:原型链上的方法名为了简介,方法名为diff)
    • 参数:
      • startTime 开始日期时间(可以是Date对象,也可以是字符串类型的日期,也可以是时间戳的Int)
      • endTime 结束日期时间(可以是Date对象,也可以是字符串类型的日期,也可以是时间戳的Int)
      • diffType 最后获得的时间差的单位.‘year’:年,‘month’:月,‘day’:日,‘hour’:时,‘minute’:分,‘second’:秒.(默认为’day’,天)
      • ifAbs 对最终的时间差是否取绝对值(默认为true,取绝对值)
    • 示例:
    let startTimeStr='2017-11-11 11:11:11';
    let endTimeStr='2017-11-12 10:10:10';
    getDateDiff(startTimeStr,endTimeStr); //结果为1
    getDateDiff(startTimeStr,endTimeStr,'hour'); //结果为23
    let date=new Date();
    date.diff(endTimeStr,'month',false); //因为是both方法,所以也可以以这种方式调用.结果为-11
    

    NumberUtils:对内建对象Number拓展的相关方法(里面的方法全部为onlyProto)

    add()

    sub()

    mul()

    div()

    • 说明: 将MathUtils方法中的精确算术运算的这几个方法(accDiv,accMul,accAdd,accSub)加入到Number的原型链中(具体用法,看MathUtils中的方法介绍)
    • 调用方式(具体用法,看MathUtils中的方法介绍):
    let num=5.67;
    num.div(7) 
    

    toFixedLenStr(len=2,char=‘0’)

    • 说明:将CommonUtils中的numToFixedLenStr方法加入到Number的原型链中
    • 参数:
      • len:到达多少长度
      • char:填充的字符
    • 调用方式(具体用法,看CommonUtils中的方法介绍):
    let num=18;
    num.toFixedLenStr(4,'*') //结果为"**18"
    

    toFloatStr(toFixed=2,type=‘round’)

    • 说明:将一个数字类型的值进行处理(保留小数后几位,舍去部分是四舍五入,还是向上/向下取整)(返回字符串形式时)(其中调用了MathUtils的dealWithFloatStr方法,参数的具体含义与之相同)
    • 参数:
      • toFixed 保留到小数点后几位,默认为2
      • type 是四舍五入,还是向上/向下取整
    • 调用方式(具体用法,看MathUtils中的方法介绍):
    let num=18.12345;
    num.toFloatStr() //结果为"18.12"
    num.toFloatStr(3,'up') //结果为"18.124"
    

    toFloat(toFixed=null,type=‘round’)

    • 说明:和上面的方法一样,只是返回值为数字类型,而非字符串
    • 调用方式(具体用法,看MathUtils中的方法介绍):
    let num=18.12345;
    num.toFloat(3,'up') //结果为18.124 
    

    toDate()

    • 说明:将DateUtils中的getDateObj方法加入Number的原型链中,将Int类型的时间戳转换为日期对象(具体介绍看原方法)
    • 示例:
    let num=1455241600000;
    num.toDate() //结果转化为日期对象 Fri Feb 12 2016 09:46:40 GMT+0800 (CST)
    

    ObjectUtils:对内建对象Object拓展的相关方法(本来在Object的原型链上加方法会使调用很简便,但是这样的做法被rn拒绝了,所以这里面的方法都是normal:普通方法)

    objEachToFloat(obj,args={})

    • 说明:将数组内的所有数字或数字字符串转换为指定小数位数的数字或数字字符串(其中的每个元素调用MathUtils中的dealWithFloatStr方法,详情可以去查看该方法)(和ArrayUtils中的eachToFloat方法基本一致,这里就不做过多的示例了)
    • 参数:
      • obj 要进行处理的obj对象
      • args 因为参数比较多,所以以对象的方式传入可选参数
        • ifRecursion 表示是否递归(是否将数组中的数组/对象也进行该方法的调用)(默认为true)
        • toFixed 保留小数点后几位(与dealWithFloatStr方法中一样)(默认为2)
        • type 四舍五入,还是向上/向下取整(与dealWithFloatStr方法中一样)(默认为’round’,四舍五入)
        • inputType 要进行处理操作的类型.'both’时数字或数字字符串都会进行处理;'num’时只会处理数字;‘str’时只会处理数字字符串.(与dealWithFloatStr方法中一样)(默认为’both’,都进行处理)
        • outputType 处理后返回的类型.'origin’时保持原类型,输入是数字返回就是数字,输入是字符串,返回就是字符串;'num’时不管是数字还是字符串类型的数字都会转换为数字;‘str’时不管是数字还是字符串类型的数字都会转换为字符串类型的数字.(默认为’'origin,保持原类型)
    • 示例:
    //下面的结果是JSON.stringify()后的输出
    let obj={a:10.12341,b:{a:'10.12412',b:true,c:[10,23.0123,'dsad']},c:'40.1'};
    objEachToFloat(obj,{toFixed:3,type:'up'}) //结果为"{"a":10.124,"b":{"a":"10.125","b":true,"c":[10,23.013,"dsad"]},"c":"40.100"}"
    

    getSubObj(obj, subObjDatas,empty=null)

    • 说明:用于获得obj对象中子对象中的子对象…的值.但是有的时候我们不知道对应的位置是否存在数据(比如obj下面可能不存在class对象)这时直接(obj.class.people.name)这样取的话就会报错,这个方法会顺着obj对象的子对象一层一层向下找,只要没有对应的对象就返回null
    • 方法应用场景:要去一个对象指定子对象,子对象的子对象…的值的时候,但是它有可能不存在,还有可能这个对象的父对象就不存在,这时用正常方式取值会报错,这时就要用到这个方法.
    • 参数:
      • obj 最外层的obj对象
      • subObjDatas 要取的是哪个子对象,可以是字符串或数组(看下面的两种调用方式)
      • empty 子对象不存在时返回什么,默认为null
    • 两种调用方式:比如要获得obj.class.people.name的值:
      • 方式1: getSubObj(obj,'class.people.name') 这种方式通常用在子对象键名确定,固定,不变的情况
      • 方式2: getSubObj(obj,['class','people','name']). 或者let a='class',b='people',c='name';getSubObj(obj,[a,b,c]); 这种方法通常在子对象键名根据变量改变时的情况,使用后面这种形式调用
    • 示例:
    let obj={class:{otherProple:{name:'zhangsan'}}};
    obj.class.people.name //这样直接调用就会报错
    getSubObj(obj,'class.people.name') //用该方法就返回null(也可以自定义不存在时的返回值)
    let a='class',b='people',c='name'; //模拟键名会根据情况改变时
    getSubObj(obj,[a,b,c]); //也可以用这种方式调用
    

    gqlObjToString(obj,ifNull=false,num=0)

    • 说明:将对象/数组类型的数据转换为字符串(左边键部分不加引号,右边正常的形式)(要传入的字符串不加引号时,则在传入的字符串形参两边加上*,例如’CONST’)
    • 方法作用:该方法是将对象和数组转换为字符串的形式,与JSON.stringify不同的是,不会将对象的键(key)的部分也加上双引号,每个数组元素/对象元素之间不加逗号,值Value为null或undefined时不会被加入其中,也可以配置为false,0,’'时都不放入.可以让字符串不加引号.
    • 特殊用法:将对象转换为GraphQL的查询语句(其实该方法就是用于这个功能时写的,不知道GraphQL的同学请忽略)
    • 参数:
      • obj 传入的对象或数组
      • ifNull true时只有键的值为undefined或者null时这组键值才不被放入字符串中;false时,0,’'等都不放入
      • num 用于记录递归调用的第几层,也可以在调用时手动给出指定的值作为最后的缩进
    • 示例:
    let obj={a:10.12341,b:{a:'10.12412',b:true,c:[10,23.0123,'dsad']},c:'40.1',d:null,e:undefined,f:'*CONST*'};
    gqlObjToString(obj);
    //结果为
    /*
    "{
    	a:10.12341
    	b:{
    		a:"10.12412"
    		b:true
    		c:[
    			10
    			23.0123
    			"dsad"
    		]
    	}
    	c:"40.1"
    	f:CONST
    }"
    */
    

    subObjDataToObj(obj,dealWithSameSubKey=‘both’,separator=’_’,allNameKeyArr=null,supKeyArr=[],sameKeyArr=null)

    • 说明:递归遍历对象中的每一个键值(k:v)数据,把子对象(值value为对象)中的键值数据都放到最外层父对象(传入的这个obj对象)中.如果传入的是一个数组,则遍历该数组,对其中的每一个对象元素进行该操作.
    • 方法作用:该方法主要用于对象嵌套比较复杂,希望把键值都抽取出来到最外层的情况
    • 高能预警:此方法有点复杂,不知道我能不能把它讲清楚
    • 参数:
      • obj 要处理的对象(下面说到的父对象就是传入的这个obj)
      • dealWithSameSubKey 如果遇到子对象中有键(key)与父对象中的键重复时的操作.
        • “sub”:为以子对象为主(子对象数据覆盖父对象的),
        • “sup”:为以父对象为主(子对象数据直接忽略,跳过),
        • “both”:为都保留.
          • 比如子对象"test"下的key:“name"命名为"test_name”(多个子对象下有相同key,或父对象中有该key时会这样命名);
          • 在如有子对象中该键名唯一则直接命名为该键名. 比如let obj={bcd:2,cde:{test:‘234’}};subObjDataToObj(obj) 这时结果为{bcd: 2, test: “234”}. 此时要在想让键名为"cde_test"这样的形式时,可在allNameKeyArr中加入该键名.
      • separator 第二个参数dealWithSameSubKey值为"both"时子对象名与key之间的分隔符,默认为"_"
      • allNameKeyArr 除重复键名外,需要显示键名全路径的键名.
        • 不传值时,如果一个子对象中有这个键,而且这个键名唯一,这个键名会被直接用在父对象上. 比如let obj={bcd:2,cde:{test:‘234’}};subObjDataToObj(obj) 这时结果为{bcd: 2, test: “234”}
        • 手动传入值时,子对象中与sameKeyArr数组中键相同的键名不管父对象中有没有该键名. 比如let obj={bcd:2,cde:{test:‘234’}};subObjDataToObj(obj,‘both’,’_’,[],[‘test’]) 这时结果为{bcd: 2, cde_test: “234”} (这通常用在有两个或多个子对象中有相同的键名,但是父对象中没有,而且这些子对象中的这些键名还可能只存在其中一个的情况)
      • supKeyArr 用于递归调用时记录向上每层父对象的key的数组(调用时不要手动传入) 这样的话obj.a.b.c就会转换为obj_a_b_c,如果手动传入null/false则返回b_c
      • sameKeyArr 用于递归调用时传递相同重复键名的数组(调用时不用手动传,也可手动传入).给了这个值之后allNameKeyArr值就无效了.
    • 示例:
    let obj1={a:{test:123},b:{c:{test:456}},d:{c:{test:789}},e:{f:{test:135}}};
    subObjDataToObj(obj1) //结果为 {a_test: 123, b_c_test: 456, d_c_test: 789, e_f_test: 135}
    

    StringUtils:对内建对象String拓展的相关方法(里面方法有baseOnInvadeScale类型,也有onlyProto类型,也有both类型,具体类型,看下面各个方法的方法介绍中)

    注意字符串是不能改变的,所以下面的方法如果是和改变字符串相关的都是生成的另一个新的字符串,要用另一个变量来接,元字符串不会发生改变

    add()

    sub()

    mul()

    div()

    • 说明:将MathUtils方法中的精确算术运算的这几个方法(accDiv,accMul,accAdd,accSub)加入到Number的原型链中
    • 方法类型:这几个方法都是onlyProto类型
    • 调用方式(具体用法,看MathUtils中的方法介绍):
    '5.67'.div(7)
    

    toFixedLenStr(len=2,char=‘0’)

    • 说明:将CommonUtils中的numToFixedLenStr方法加入到String的原型链中
    • 参数:
      • len:到达多少长度
      • char:填充的字符
    • 调用方式(具体用法,看CommonUtils中的方法介绍):
    let numStr='18';
    numStr.toFixedLenStr(4,'*') //结果为"**18"
    

    isNumeric()

    • 说明:将CommonUtils中的isNumeric方法加入到String的原型链中,判断当前这个字符串是不是数字(调用方法:'123.123dsa'.isNumeric(),具体用法,看CommonUtils中的方法介绍)
    • 方法类型:onlyProto

    toFloatStr(toFixed=2,type=‘round’)

    • 说明:将一个字符串类型的数字进行处理(保留小数后几位,舍去部分是四舍五入,还是向上/向下取整)(返回字符串形式时)(其中调用了MathUtils的dealWithFloatStr方法,参数的具体含义与之相同)
    • 方法类型:onlyProto
    • 参数:
      • toFixed 保留到小数点后几位,默认为2
      • type 是四舍五入,还是向上/向下取整
    • 示例:
    "18.12345".toFloatStr() //结果为"18.12"
    "18.12345".toFloatStr(3,'up') //结果为"18.124"
    

    toFloat(toFixed=null,type=‘round’)

    • 说明:和上面的方法一样,只是返回值为数字类型,而非字符串
    • 方法类型:onlyProto
    • 示例:
    "18.12345".toFloat(3,'up') //结果为18.124 
    

    toDate()

    • 说明:将DateUtils中的getDateObj方法加入String的原型链中,将字符串类型的日期转换为日期对象(具体介绍看原方法)
    • 方法类型:onlyProto
    • 示例:
    '2012-12-12 00:00:00'.toDate() //结果转化为日期对象 Wed Dec 12 2012 00:00:00 GMT+0800 (CST)
    

    getSecStr(leftNum=0,rightNum=0,middleNum=0,secChar=’*’)

    • 说明:密文显示字符串,比如身份证号123456199507281234处理为1234************34这样的形式
    • 方法类型:both
    • 特殊用法:比如从后端获取到一些用户的私密信息(手机号,银行卡号,身份证等)在界面上密文展示时
    • 参数:
      • leftNum 左边明文显示的内容的长度
      • rightNum 右边明文显示的内容的长度
      • middleNum 中间隐藏内容的长度(默认0时,为减去leftNum和rightNum后的长度)
      • secChar 设置密文的字符,默认为’*’
    • 示例:
    let str='1383838438';
    str.getSecStr(2,3); //结果为"13****438"
    str.getSecStr(2,3,8); //结果为"13*******438"
    getSecStr(str,2,3,8); //结果同上,也可以以普通方法调用
    

    insertSpace(numStr,spacePositions=4,loop=true)

    • 说明:对传入的字符串进行4位(spacePositions)隔一空格处理,比如,输入’432896549984326896532’,则输出’4328 9654 9984 3268 9653 2’
    • 方法类型:both
    • 参数:
      • numStr 传入要处理的字符串
      • spacePositions 每隔多少位空一格空格(默认为4).spacePositions为数组时.比如[4,6,5],字符串为’432896549984326896532’,则输出’4328 965499 84326 8965 32’
      • loop 表示是否循环,默认为true.false时,则输出’4328 965499 84326 896532’,只执行一遍
    • 特殊用法:比如用户在输入银行卡号,身份证号时调用此方法让格式更清晰
    • 示例:
    //下面的信息都是乱写的
    let bankCard='6212262201023557228';
    bankCard.insertSpace(); //结果为"6212 2622 0102 3557 228",这是用于银行卡号的情况.
    let IDNum='123456199507281234';
    IDNum.insertSpace([6,8,4]); //结果为"123456 19950728 1234",这是用于身份证时的情况.
    let phone='13383838438'; //结果为"133 8383 8438",这是用于手机号时的情况.
    let random='213649213892749217392147236294';
    random.insertSpace([2,4,3]) //结果为"21 3649 213 89 2749 217 39 2147 236 29 4",默认会循环
    random.insertSpace([2,4,3],false); //结果为"21 3649 213 892749217392147236294",不循环时
    insertSpace(random,[2,4,3],false) //因为是both类型的方法,所以也可以通过普通方法的形式调用
    

    indexdWithNum(char,n)

    • 说明:查找字符串中指定字符/字符串第n次出现的位置(找到返回对应位置的索引,没找到返回-1)
    • 参数:
      • findStr 要查找位置的字符/字符串
      • n 要找第n次出现的位置(默认为1,第一次出现的位置)
    • 方法类型:baseOnInvadeScale
    • 示例:
    let str='root123rootdsahkroot123';
    str.indexdWithNum('root'); //结果为0
    str.indexdWithNum('root',3); //结果为16
    

    insertToIndex(inserts,indexs)

    • 说明:字符串指定位置插入字符/字符串的方法(可以指定多个位置插入多个字符/字符串)
    • 参数:
      • inserts 表示要插入的字符/字符串(给出数组时,在多个位置插入多个字符串)
      • indexs 表示要插入的位置(给数组时在数组指定的多个位置插入)
    • 方法类型:baseOnInvadeScale
    • 示例:
    let str='I you';
    str.insertToIndex(' love',1); //结果为"I love you"
    str='I you,I you';
    str.insertToIndex(' love',[1,7]) //结果为"I love you,I love you"
    str.insertToIndex([' love',' hate'],[1,7]) //结果为"I love you,I hate you"
    

    getStrCount(strOrReg)

    • 说明:获取一个字符串中一个指定字符/字符串或正则表达式出现次数
    • 参数:
      • strOrReg 要查找的字符串或正则表达式
    • 方法类型:baseOnInvadeScale
    • 示例:
    let str='root123rootdsro132otahkroot123';
    str.getStrCount('root'); //结果为3
    str.getStrCount(/ro.*?ot/g) //结果为4,注意,得加上修饰符g,不然会返回1
    

    trimFunc(char=’ ',type=‘lr’)

    • 说明:去除字符串(左右/所有)空格或指定字符
    • 参数:
      • type 要去除的位置.‘all’:所有,包括字符串中间的,‘lr’:左右(默认就是这个),‘l’:左,‘r’:右
      • char 要去除的字符,默认为空格’ ’
    • 方法类型:both
    • 示例:
    let str='   I   love  you  ';
    str.trimFunc(); //结果为"I   love  you"
    str.trimFunc('all') ;//结果为"Iloveyou"
    str='---I--Love--you---';
    str.trimFunc('l','-') //结果为"I--Love--you---"
    trimFunc(str,'l','-') //因为是both类型,也可以以普通方法的形式调用
    

    toUpperFirst(ifOtherLower = true)

    • 说明:将字符串中的每个单词首字母大写
    • 参数:
      • ifOtherLower 如果除了首字母外其他字母有大写的话是否要转换为小写(默认为true)
    • 方法类型:baseOnInvadeScale
    • 示例:
    let str='I lovE yoU';
    str.toUpperFirst(); //结果为"I Love You"
    str.toUpperFirst(false); //结果为"I LovE YoU"
    

    其他方面的工具类部分:

    FileUtils:一些和文件相关的方法(里面的方法都是normal:普通方法)

    formatFileSize(size)

    • 说明:通过传入的文件字节大小格式化文件大小
    • 参数:
      • size 文件字节大小
    • 示例:
    formatFileSize(1236821); //结果为"1.18MB"
    formatFileSize(1236821213); //结果为"1.15GB"
    

    getBaseName(path)

    • 说明:通过文件路径返回文件名
    getBaseName('somedir/to/test.js') //结果为"test.js"
    

    getDirName(path)

    • 说明:通过文件路径返回路劲(上面方法的取反)
    getDirName('somedir/to/test.js') //"somedir/to"
    

    getFileType(filePath,haveDot=false)

    • 说明:返回文件的拓展名,haveDot表示是否带上"点"(.jpg还是jpg)
    • 参数:
      • filePath 文件路劲
      • haveDot 表示是否带上"点"(比如.jpg还是jpg)(默认为false)
    • 示例:
    getFileType('somedir/to/test.js') //结果为"js"
    

    pathJoin(dirPath,fileName)

    • 说明:拼接路径和文件名
    • 参数:
      • dirPath 文件路劲
      • fileName 文件名
    • 示例:
    pathJoin('somedir/to','test.js'); //结果为"somedir/to/test.js"
    

    DebugUtils:一些在开发或调试中要到的方法(里面的方法都是normal:普通方法)

    logFuncName(args)

    • 说明:获取当前调用方法的方法名,并打印(调用时logFuncName(arguments))(常用于调试,在es6下的部分方法中会报错)
    • 参数:
      • args:要打印方法名的方法的arguments,要在方法中将arguments当做参数传进来(因为rn中没有arguments.caller)
      • otherStr:另外要打印到一起的字符串
      • char:在方法名的左右用什么符号来标记,默认为’-’,给出空字符串时不要左右的字符
      • num:左右各多少个char字符,默认35个
    • 示例:
    function Test() {
        logFuncName(arguments);
    }
    打印出***********************************Test***********************************
    function Test() {
        logFuncName(arguments,'App','-',20);
    }
    打印出--------------------App--------------------Test--------------------
    

    getLorem(wordCount=30)

    • 说明:返回一串随机的乱数假文(就和在webStorm或其他一些支持该功能的IDE中写lorem后Tab键一样)
    • 参数:wordCount 要生成的假文单词数目.(默认为30)
    • 示例:
    getLorem() //结果为"Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nkiuaoxuidbej hdkgnsmf nztqmp ngxsuxmxryubb kkuuegcnj npwtikvax jeitrhdtm, hjmmflmcqf qwhynmxw. Wpt ddoqkvpeaa dymecfpet, mqwhgngubpzbu. Asmthth jlsef fkznuhorv uwexlhzx owpyryoxxww eugqf cdefdkeatlii, ppcfamku. Gqpslqmmyg?"
    getLorem(15) //指定单词数目为15.结果为"Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sckyejb hdrko, zqkiuuudb iwuvzwpqll, ycvceyrlgadw yuzwcqjezdsq qnxho,."
    

    getDataFromNetTest(pageLen=20,page=1,ms=3000,max=100)

    • 说明:模拟网络获取数据方法,模拟分页请求网络数据(react-native-page-listview中的模拟数据就是通过这个方法获得的)
    • 参数:
      • pageLen 获得数据的每一页的数据条数(默认20条)
      • page 获得数据的页数(默认第1页)
      • ms 模拟多少毫秒后可以获得网络传输的数据(默认3000毫秒:即3秒)
      • max 模拟数据库中总共有多少条数据(默认最多100条,这时如果每页20条,第5页有数据,第6页就没有数据了)
    • 示例:
    getDataFromNetTest()
    	.then((res)=>{console.log(res)}); 
    	//这里结果为3秒钟后打印出一个长度20的数组,数组中每条元素就是一个对象,该对象里面
    	//{index:当前数据的索引(即对几条数据),name:一个随机生成的名字,age:随机年龄,phone:随机电话号码,text:随机的一串文字(上面的getLorem方法)}.
    	//这里的对象格式现在是固定的,后面可能会将其改为可以从参数中传递来.
    

    终于整理完了

    整理了好几整天终于整理完了,现在方法还比较少,不过还是算都比较常用的.

    (↓ˉ▽ˉ↓)

    如果大家觉得我的组件好用的话,帮到你的话,欢迎大家Star,Fork,如果有什么问题的话也可以在github中想我提出,谢谢大家的支持.

    展开全文
  • react-native 自定义封装刷新组件几个月没写博客了,最近一直在写reactreact-native,前几天刚发了一版基于react-native混合开发的App,这几天赶快总结下。写过java的同学,再去学习reactreact-native就会比较...

    ##react-native 自定义封装刷新组件

    ###几个月没写博客了,最近一直在写react 和react-native,前几天刚发了一版基于react-native混合开发的App,这几天赶快总结下。

    写过java的同学,再去学习react和react-native就会比较容易上手,并且会有一种似曾相识的感觉,不错,今天我要总结的刷新功能就和Android原生的实现很类似,在Android原生当中,可以说是家喻户晓了,在react-native中实现也是一样的简单,在rn的升级中,FlatList是listView的升级版,就好比如RecyclerView是listView的升级版一样。OK, 废话不多话说。

    #目录
    ##1.FlatList常用的属性方法
    ##2.封装一个上拉加载,下拉刷新的组件


    1.FlatList常用的属性方法

    1. data: ?Array 为了简化起见,data属性目前只支持普通数组。
    2. renderItem: (info: {item: ItemT, index: number}) => ?React.Element 根据行数据data渲染每一行的组件
    3. onRefresh?: ?() => void 如果设置了此选项,则会在列表头部添加一个标准的RefreshControl控件,以便实现“下拉刷新”的功能。同时你需要正确设置refreshing属性。
    4. refreshing?: ?boolean 在等待加载新数据时将此属性设为true,列表就会显示出一个正在加载的符号。
    5. onEndReachedThreshold?: ?number 决定当距离内容最底部还有多远时触发onEndReached回调。注意此参数是一个比值而非像素单位。比如,0.5表示距离内容最底部的距离为当前列表可见长度的一半时触发。
    6. onEndReached?: ?(info: {distanceFromEnd: number}) => void 当列表被滚动到距离内容最底部不足onEndReachedThreshold的距离时调用。
    7. ItemSeparatorComponent?: ?ReactClass 行与行之间的分隔线组件。不会出现在第一行之前和最后一行之后。
    8. keyExtractor: (item: ItemT, index: number) => string 此函数用于为给定的item生成一个不重复的key。Key的作用是使React能够区分同类元素的不同个体,以便在刷新时能够确定其变化的位置,减少重新渲染的开销。若不指定此函数,则默认抽取item.key作为key值。若item.key也不存在,则使用数组下标。
    9. ListHeaderComponent?: ?ReactClass 头部组件
    10. ListFooterComponent?: ?ReactClass 尾部组件
    11. ListEmptyComponent?: ?ReactClass | React.Element 列表为空时渲染该组件。可以是React Component, 也可以是一个render函数, 或者渲染好的element。
    12. extraData?: any 如果有除data以外的数据用在列表中(不论是用在renderItem还是Header或者Footer中),请在此属性中指定。同时此数据在修改时也需要先修改其引用地址(比如先复制到一个新的Object或者数组中),然后再修改其值,否则界面很可能不会刷新。

    ###注:当然还有其他的属性方法,请自行查阅文档FlatList

    ##2.封装一个上拉加载,下拉刷新的组件

    1. 先定义一些propTypes,利于组件的扩展使用
    static propTypes = {
    		renderItem: PropTypes.func.isRequired,    /* 渲染行的方法 */
    		ItemSeparatorComponent: PropTypes.func,   /* 渲染行间隔的方法 */
    		keyExtractor: PropTypes.func,             /* 返回每行key的方法 */
    		ListFooterComponent: PropTypes.func,      /* 渲染列表底部的方法 */
    		ListHeaderComponent: PropTypes.func,      /* 渲染列表头部的方法 */
    		listUrl: PropTypes.string.isRequired,     /* 获取列表的url */
    		fetchMethod: PropTypes.string,            /* 获取列表的请求方式(默认为get) */
    		fetchParams: PropTypes.object,            /* 获取列表的请求参数 */
    		pageSize: PropTypes.number,               /* 每页行数(默认20条) */
    		formatData: PropTypes.func,               /* 返回列表数组的方法 */
    		_ref: PropTypes.func,                     /* 获取组件实例属性 */
    		auto: PropTypes.bool,                     /* 是否在加载时自动查询(默认自动) */
    		showFooterBoo: PropTypes.bool,            /* 是否显示脚 */
            ref: PropTypes.func,                      /* 获取组件实例 */
    	};
    

    2.初始化当前状态state

    constructor(props) {
    		super(props);
    
    		this._fetchUrl = props.listUrl;
    		this._fetchParams = props.fetchParams;
    
    		this.state = {
    			list: [],            /* 列表数据 */
    			pageNum: 1,          /* 当前页数 */
    			count: 0,            /* 总条数 */
    			refreshing: false,   /* 是否正在加载 */
    			isEnd: false,        /* 是否加载完 */
    			isNotList: false,    /* 是否未查询到数据 */
    			isError: false,      /* 是否查询失败 */
    		}
    	}
    

    3.FlatList组件属性封装

    • 渲染前准备
    const { list, refreshing } = this.state;
    
    		const {
    			renderItem,
    			ItemSeparatorComponent,
    			keyExtractor = (...arg) => arg[1],
    			ListHeaderComponent,
    			extraData = {},
                showFooterBoo,
    		} = this.props;
    
    • FlatList封装
    
    <FlatList
    				data={list}
    				renderItem={renderItem}
    				onRefresh={this.onRefresh}
    				refreshing={refreshing}
    				onEndReachedThreshold={0.2}
    				onEndReached={this.onEndReached}
    				ItemSeparatorComponent={ItemSeparatorComponent}
    				keyExtractor={keyExtractor}
    				ListHeaderComponent={this.renderListHeader}
    				ListFooterComponent={showFooterBoo ? this.renderListFooter : null}
    				ListEmptyComponent={this.renderListEmpty}
    				ref={ref => this._listRef = ref}
    				extraData={extraData}
    			/>
    

    4.data={list} 中list数据来源于引用组件处的属性

    5.renderItem={renderItem} 中renderItem来源于引用组件的Item布局属性

    6.onRefresh={this.onRefresh} 下拉刷新布局如下:

    /**
    	 * 下拉刷新
    	 * @return {void}
    	 */
    	onRefresh = () => {
    		this.setState({
    			isEnd: false,
    		}, () => {
    			this.getList();
    		});
    	}
    
    /**
    	 * 获取列表
    	 * @return {void}
    	 */
    	getList = (isRefresh = true) => {
    		const {
    			$fetch,
    			fetchMethod = 'get',
    			pageSize = 20,
    			formatData = ({data}) => ({
    				list: data.records,
    				count: data.total,
    			}),
    			fetchCatch = () => {},
    		} = this.props;
    
    		const { list, pageNum, refreshing, isEnd } = this.state;
    
    		if((refreshing || isEnd) && !isRefresh) return;
    
    		const fetchPageNum = isRefresh ? 1 : pageNum;
    		let fetchPromise;
    
    		if(fetchMethod.toLowerCase() === 'get') {
    			fetchPromise = $fetch.get(this._fetchUrl, {
    				size: pageSize,
    				current: fetchPageNum,
    				...this._fetchParams,
    			});
    		} else if(fetchMethod.toLowerCase() === 'post') {
    			fetchPromise = $fetch.post(`${this._fetchUrl}`, {
    				...this._fetchParams,
    			});
    		} else {
    			throw new Error('method type error! only "get" or "post"');
    		}
    
    		this.setState({refreshing: true});
    		fetchPromise.then(data => {
    			console.log(data);
    			if(!data.success) {
    				this.setState({ isError: true });
    				return;
    			}
    			const listData = formatData(data);
    			const currentList = isRefresh ? listData.list : list.concat(listData.list);
    			/* 判断是否查询到数据 */
    			if(fetchPageNum === 1 && listData.list.length === 0){
    				this.setState({
    					isNotList: true
    				});
    			} else {
    				this.setState({
    					isNotList: false
    				});
    			}
    
    			/* 如果有数据则添加到列表中 */
    			if(listData.list.length) {
    				this.setState({
    					list: currentList,
    					pageNum: fetchPageNum + 1,
    				});
    			}
    			if(currentList.length >= listData.count) {
    				this.setState({
    					isEnd: true
    				});
    			}
    			this.setState({
    				count: listData.count,
    			});
    		}).catch(err => {
    			console.log(err.response);
    			if(!data.success) {
    				this.setState({ isError: true });
    			}
    			fetchCatch(err);
    		}).finally(() => {
    			this.setState({refreshing: false});
    		});
    	}
    

    ###注:get与post可以根据自己的具体需求进行优化,其中网络请求使用的fetch。

    7.refreshing={refreshing} 中refreshing布尔值,是用来判断当前是否是出于刷新状态的,当处于请求数据的刷新状态时置为true。

    8.onEndReachedThreshold={0.2} 当滑动比例为0.2时触发onEndReached方法;onEndReached={this.onEndReached}上拉加载实现,如下:

    /**
    	 * 上拉加载
    	 * @return {void}
    	 */
    	onEndReached = () => {
    		this.getList(false);
    	}
    

    ###注:this.getList(false);方法同下拉刷新,参数false代表上拉加载。

    9.ItemSeparatorComponent={ItemSeparatorComponent} 自定义一个分割线,如下:

    export const ItemSeparator = props => {
    	const {
    		paddingLeft = px(40),
    		backgroundColor = '#fff',
    		borderColor = '#eee',
    	} = props;
    	return (
    		<View style={{paddingLeft, backgroundColor}}>
    			<View style={{height: 1, backgroundColor: borderColor}}></View>
    		</View>
    	);
    };
    

    10.keyExtractor={keyExtractor} 使用当前数据的id即可,如下:

    keyExtractor={item => item.id}
    

    11.ListHeaderComponent={this.renderListHeader} 头部的渲染,代码如下:

    /**
    	 * 渲染列表头部
    	 */
    	renderListHeader = () => {
    		const { count } = this.state;
    		const { ListHeaderComponent = () => <View></View> } = this.props;
    		return ListHeaderComponent(this.state);
    	}
    

    ###注:布局根据自己的需求进行定义即可。

    12.ListFooterComponent={showFooterBoo ? this.renderListFooter : null} 属性showFooterBoo布尔值用来控制是否显示脚,脚的布局定义如下:

    
    	/**
    	 * 渲染列表底部
    	 * @return {ReactComponent}
    	 */
    	renderListFooter = () => {
    		const { ListFooterComponent = this.defaultListFooter } = this.props;
    		const { isEnd, refreshing } = this.state;
    		return this.defaultListFooter(isEnd, refreshing);
    	}
    
    /**
    	 * 列表默认底部组件
    	 * @return {Node}
    	 */
    	defaultListFooter = () => {
    		return (
    			<FlexView justify="center" align="center" style={styles.listFooterView}>
    				{this.defaultListFooterContent()}
    			</FlexView>
    		);
    	}
    
    /**
    	 * 列表底部显示内容
    	 * @return {Node}
    	 */
    	defaultListFooterContent = () => {
    		const { isEnd, refreshing, isNotList, isError } = this.state;
    		if(isNotList) {
    			return (
    				<_Text>未查询到相关数据!</_Text>
    			);
    		}
    		if(isEnd) {
    			return [
    				<FlexItem style={styles.listFooterLine} key={1}/>,
    				<_Text key={2}>没有更多数据</_Text>,
    				<FlexItem style={styles.listFooterLine} key={3}/>,
    			];
    		}
    		if(refreshing) {
    			return (
    				<_Text>正在加载...</_Text>
    			);
    		}
    		if(isError) {
    			return (
    				<_Text>查询失败,下拉重新加载!</_Text>
    			);
    		}
    		return (
    			<_Text>上拉加载更多</_Text>
    		);
    	}
    

    ###注:脚的布局可以根据自己的项目需求进行更改。

    13.ListEmptyComponent={this.renderListEmpty} 空布局,没有数据,请求出错显示,代码如下:

    /**
    	 * 列表为空时显示的组件
    	 * @return {ReactComponent}
    	 */
    	renderListEmpty = () => {
    		return (
    			<View>
    				<Text>没有数据哦!</Text>
    			</View>
    		);
    	}
    

    14.ref={ref => this._listRef = ref} 当前实例

    ok,总结就到这里了,后续我会总结更多的使用组件的~~

    加群一起讨论学习在这里插入图片描述

    展开全文
  • 从2016年7月份开始,坚持写ReactNative系列博客,记录工作中遇到的点滴。今天把博客汇如下:《React-Native系列》1、初探React-Native《React-Native系列》2、RN与native交互与数据传递《React-Native系列》3、RN与...

    从2016年7月份开始,坚持写ReactNative系列博客,记录工作中遇到的点滴。

    今天把博客汇总如下:

    1. 《React-Native系列》1、初探React-Native
    2. 《React-Native系列》2、RN与native交互与数据传递
    3. 《React-Native系列》3、RN与native交互之Callback、Promise
    4. 《React-Native系列》4、表单界面代码编写
    5. 《React-Native系列》5、RN实现弹出选择界面与动画效果
    6. 《React-Native系列》6、Navigator语法介绍及经典应用
    7. 《React-Native系列》7、bundle文件的加载和维护
    8. 《React-Native系列》8、RN如何打离线包
    9. 《React-Native系列》9、 Networking之fetch
    10. 《React-Native系列》10、 RN组件之Text和TextInput以及注意要点
    11. 《React-Native系列》11、 图解RN布局之FlexBox,三分钟上手写RN界面
    12. 《React-Native系列》12、 API模块之PixelRatio和Dimensions
    13. 《React-Native系列》13、 组件封装之Dialog(iOS和Android通用)
    14. 《React-Native系列》14、 RN学习之NodeJS
    15. 《React-Native系列》15、 RN之可触摸组件
    16. 《React-Native系列》16、 RN组件之ListView
    17. 《React-Native系列》17、 RN中this所引起的undefined is not an object错误
    18. 《React-Native系列》18、 RN之定时器Timer
    19. 《React-Native系列》19、 ListView组件之上拉刷新(iOS和Android通用)
    20. 《React-Native系列》20、 RN数据流之Flux概览
    21. 《React-Native系列》21、 解决RN在Android下不支持gif问题
    22. 《React-Native系列》22、 Flux框架Demo详解
    23. 《React-Native系列》23、 js实现下拉刷新效果(Android和iOS通用)
    24. 《React-Native系列》24、 结合Demo学习Redux框架
    25. 《React-Native系列》25、 详解Redux的connect方法
    26. 《React-Native系列》26、 ReactNative实现图片上传功能
    27. 《React-Native系列》27、 Redux的异步数据流
    28. 《React-Native系列》28、 RN之AsyncStorage
    29. 《React-Native系列》29、 RN组件之WebView
    30. 《React-Native系列》30、 RN组件间通信
    31. 《React-Native系列》31、 Fetch发送POST请求的坑与解决方案
    32. 《React-Native系列》32、 基于Fetch封装HTTPUtil工具类
    33. 《React-Native系列》33、 键盘遮挡问题处理
    34. 《React-Native系列》34、 ReactNative的那些坑
    35. 《React-Native系列》35、 RN在Android下支持gif的另一种方案
    36. 《React-Native系列》36、 ReactNative地图组件
    37. 《React-Native系列》37、 ReactNative百度地图开源组件使用
    38. 《React-Native系列》38、 ReactNative混合组件封装
    39. 《React-Native系列》39、 ReactNative之键盘Keyboard
    40. 《React-Native系列》40、 ReactNative之bundle文件瘦身
    41. 《React-Native系列》41、刨根问底Picker组件
    42. 《React-Native系列》42、键盘遮挡问题官方处理方法KeyboardAvoidingView
    43. 《React-Native系列》43、通用容器和导航设计方案
    44. 《React-Native系列》44、基于多个TextInput的键盘遮挡处理方案优化
    45. 《React-Native系列》45、踩坑记录

    展开全文
  • 1.集成录音react-native-audio 2.集成文件操作react-native-fs 3.集成音频格式转换react-native-audiotransition。上面两个问题不大,第三步有个坑,rn-audio的录音格式为AAC,需要将AAC转成其他音频格式再传给...

    项目有需求,需要集成语音转文字,于是开始研究,一步一个坑

    1.集成录音 react-native-audio

    2.集成文件操作 react-native-fs

    3.集成音频格式转换 react-native-audiotransition。上面两个问题不大,第三步有个坑,rn-audio的录音格式为AAC,需要将AAC转成其他音频格式再传给百度语音,所以需要安装 react-native-audiotransition,安装后如果不翻墙,需要在RN安卓项目的buils.gradle文件添加

    allprojects {
        repositories {
            mavenLocal()
            jcenter()
            maven {
                // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
                url "$rootDir/../node_modules/react-native/android"
            }
            maven {
                url"https://jitpack.io"
            }
        }
    }

    4.鉴权认证:使用appKey secretKey 访问 https://openapi.baidu.com 换取 token(有效期一个月)

    5.百度语音的HTTP POST 请求

    下面上全部代码

    import React, { Component } from 'react';
    import {
      StyleSheet,
      Text,
      View,
      Dimensions,
      Platform,
      TouchableHighlight
    } from 'react-native';
    
    
    import { AudioRecorder, AudioUtils } from 'react-native-audio';
    import RNFS from 'react-native-fs';
    import RNAudiotransition from 'react-native-audiotransition';
    
    const ISIPHONEX = Dimensions.get('window').width == 375 && Dimensions.get('window').height == 812
    
    
    export default class Kedaxunfei extends Component {
    
      state = {
        currentTime: 0.0,           //开始录音到现在的持续时间
        recording: false,           //是否正在录音
        paused: false,              //是否暂停了录音
        stoppedRecording: false,    //是否停止了录音
        finished: false,            //是否完成录音
        audioPath: AudioUtils.DownloadsDirectoryPath + '/luyin.aac',//路径下的文件名
        hasPermission: undefined,   //是否获取权限
        audioSize: 0,                //音频size
        result: "",                  //语音返回值
      };
    
      prepareRecordingPath(audioPath) {
        AudioRecorder.prepareRecordingAtPath(audioPath, {
          SampleRate: 16000,            //采样率
          Channels: 1,                  //通道
          AudioQuality: "High",         //音质(Low, Medium, High)
          AudioEncoding: "aac",         //音频编码(aac编码iOS和Android均支持)
          AudioEncodingBitRate: 48000,  //音频编码比特率
          IncludeBase64: true,          //是否是base64格式
        });
      }
      componentDidMount() {
          //初始化音频格式转化
        RNAudiotransition.initAudioTransition();
    
        //初始化录音
        AudioRecorder.requestAuthorization().then((isAuthorised) => {
          this.setState({ hasPermission: isAuthorised });
    
          if (!isAuthorised) return;
    
          this.prepareRecordingPath(this.state.audioPath);
    
          AudioRecorder.onProgress = (data) => {
            this.setState({ currentTime: Math.floor(data.currentTime) });
          };
    
          AudioRecorder.onFinished = (data) => {
            // Android callback comes in the form of a promise instead.
            if (Platform.OS === 'ios') {
              this._finishRecording(data.status === "OK", data.audioFileURL, data.audioFileSize);
            }
          };
        });
    
    
      }
      _renderButton(title, onPress, active) {
        var style = (active) ? styles.activeButtonText : styles.buttonText;
    
        return (
          <TouchableHighlight style={styles.button} onPress={onPress}>
            <Text style={style}>
              {title}
            </Text>
          </TouchableHighlight>
        );
      }
    
      _renderPauseButton(onPress, active) {
        var style = (active) ? styles.activeButtonText : styles.buttonText;
        var title = this.state.paused ? "RESUME" : "PAUSE";
        return (
          <TouchableHighlight style={styles.button} onPress={onPress}>
            <Text style={style}>
              {title}
            </Text>
          </TouchableHighlight>
        );
      }
    
      async _pause() {
        if (!this.state.recording) {
          console.warn('Can\'t pause, not recording!');
          return;
        }
    
        try {
          const filePath = await AudioRecorder.pauseRecording();
          this.setState({ paused: true });
        } catch (error) {
          console.error(error);
        }
      }
    
      async _resume() {
        if (!this.state.paused) {
          console.warn('Can\'t resume, not paused!');
          return;
        }
    
        try {
          await AudioRecorder.resumeRecording();
          this.setState({ paused: false });
        } catch (error) {
          console.error(error);
        }
      }
    
      async _stop() {
        if (!this.state.recording) {
          console.warn('Can\'t stop, not recording!');
          return;
        }
    
        this.setState({ stoppedRecording: true, recording: false, paused: false });
    
        try {
          const filePath = await AudioRecorder.stopRecording();
    
          if (Platform.OS === 'android') {
            this._finishRecording(true, filePath);
          }
          return filePath;
        } catch (error) {
          console.error(error);
        }
      }
    
    
    
      async _record() {
        if (this.state.recording) {
          console.warn('Already recording!');
          return;
        }
    
        if (!this.state.hasPermission) {
          console.warn('Can\'t record, no permission granted!');
          return;
        }
    
        if (this.state.stoppedRecording) {
          this.prepareRecordingPath(this.state.audioPath);
        }
    
        this.setState({ recording: true, paused: false });
    
        try {
          const filePath = await AudioRecorder.startRecording();
        } catch (error) {
          console.error(error);
        }
      }
    
      _finishRecording(didSucceed, filePath, fileSize) {
        this.setState({ finished: didSucceed });
        console.log(`Finished recording of duration ${this.state.currentTime} seconds at path: ${filePath} and size of ${fileSize || 0} bytes`);
    
        this.timer = setTimeout(() => {
          //录音文件是aac格式,转写成wav格式
          RNAudiotransition.audioToStart(AudioUtils.DownloadsDirectoryPath + "/luyin.aac", 'wav', (res) => {
            console.log(res)
            //获取音频文件len
            RNFS.stat(AudioUtils.DownloadsDirectoryPath + "/luyin.wav")
              .then((StatResult) => {
                this.setState({
                  audioSize: StatResult.size
                })
              })
              //音频文件转base64
            RNFS.readFile(AudioUtils.DownloadsDirectoryPath + "/luyin.wav", "base64")
              .then((content) => {
                //base64传给百度后台
                let url = "https://vop.baidu.com/pro_api";
                let params = {
                  "format": "wav",                    //语音文件的格式,pcm、wav、amr、m4a
                  "rate": 16000,                      //采样率,16000,固定值
                  "dev_pid": 80001,                   //普通话
                  "channel": 1,                       //声道数,仅支持单声道,请填写固定值 1
                  "token": "*****",//开放平台获取到的开发者[access_token]
                  "cuid": "baidu_workshop",            //用户唯一标识,用来区分用户,计算UV值。
                  "len": this.state.audioSize,         //本地语音文件的的字节数,单位字节
                  "speech": content,                   //本地语音文件的的二进制语音数据 ,需要进行base64 编码
                };
                console.log("content.length" + content.length)
                fetch(url, {
                  method: 'POST',
                  body: JSON.stringify(params),   //请求体
                  headers: {
                    Accept: "application/json",
                    "Content-Type": "application/json",
                  }
                })
                  .then((response) => response.json())
                  .then((data) => {
                    console.log(data)
                    this.setState({
                      result: data.result
                    })
                  })
                  .catch((error) => {
                    console.log('语音识别错误')
    
                  });
              }).catch((err) => {
                console.log("文件读取失败")
              });
    
          })
        }, 1000);
    
      }
    
      render() {
    
        return (
          <View style={styles.container}>
            <View style={styles.controls}>
              {this._renderButton("RECORD", () => { this._record() }, this.state.recording)}
              {this._renderButton("STOP", () => { this._stop() })}
              <Text style={styles.progressText}>{this.state.currentTime}s</Text>
              <Text style={styles.progressText2}>{this.state.result}</Text>
            </View>
          </View>
        );
      }
    }
    
    var styles = StyleSheet.create({
      container: {
        flex: 1,
        backgroundColor: "#2b608a",
      },
      controls: {
        justifyContent: 'center',
        alignItems: 'center',
        flex: 1,
      },
      progressText: {
        paddingTop: 50,
        fontSize: 50,
        color: "#fff"
      },
      progressText2: {
        paddingTop: 50,
        fontSize: 20,
        color: "#fff"
      },
      button: {
        padding: 20
      },
      disabledButtonText: {
        color: '#eee'
      },
      buttonText: {
        fontSize: 20,
        color: "#fff"
      },
      activeButtonText: {
        fontSize: 20,
        color: "#B81F00"
      }
    
    });
    
    

    有描述不清或者有什么不懂得问题可以私信我。

    展开全文
  • 为了上传文件,搜索了很多资料终于找到选择本地文件并获取到具体路径的组件,可以在github上查找到该组件 ...2、react-native link react-native-file-selector 3、/app/build.gradle: 增加&lt;...
  • 目录: 思路 安装中间件 获取用户相册/相机权限,以及主要步骤 调用接口,实现上传图片文件 思路 获取用户相册/相机权限;...实现本地相册选择/相机拍摄;...封装上传接口,将照片上传到..."react-native-image-picker
  • 想想为了react-native我还是蛮拼的。之前刚学习react-native的时候,晓得是以JavaScript作为语言基础的。然后边学习react-native边JavaScript,然后便记录学习心得。初学状态虽有一股浓重的好奇心、求知劲头和不知...
  • 最近在整理一个生成二维码与识别二维码的Demo,在扫描这个功能上查找了很多主流的库,但是大多数库因为年代久远,新版的Xcode连Demo都没办法跑起来了,所以我整理了一下使用 react-native-smart-barcode 实现二维码...
  • 1.react-native-fs是什么? 2.react-native-fs支持哪些功能? 3.react-native-fs如何使用? 4.react-native-fs功能介绍? 5.文件操作说明 5.1文件目录说明 5.2文件创建 5.3文件删除 5.4文件读取 5.5文件...
  • 本着不重复造轮子的目标,在最喜欢的github上找寻合适的组件,终于发现了一个非常棒的组件:react-native-step-indicator 使用就非常简单了 第一步,添加组件依赖,这里墙裂建议大家使用yarn管理项目依赖 yarn add ...
  • 自2018年我开源了XUpdate之后,至今已迭代了14个版本,月下载量达4k+,Github的star量也已经有800+. 目前XUpdate的生态已包含Android原生SDK、Flutter插件、...下面我给出react-native-xupdate-new插件的地址: https://...
  • 配置方面,还是先到百度地图开放平台创建应用,获取 AK(之前文档有写,前往) ...react-native link react-native-baidu-map # Andorid 配置 修改AndroidManifest 文件 <!-- 这个权限用于进行网络定位-...
  • react-native-image-picker作为一个集成相机和相册的功能的第三方库,因为其使用相对简单受到前端开发人员的喜爱。react-native-image-picker使用1, 首先,安装下该插件。npm install react-native-image-picker@...
  • react-native-qiniu 已经废弃好久了,没有人写,网上找到的也只能解决一点点问题,然后图片上传也存在着一系列的问题.参考着网上一些代码,我修改了其文件上传的部分.虽然可以在服务端进行上传,但总觉得base64先上传到...
  • React-Native学习指南

    2016-10-19 11:40:15
    GitHub:https://github.com/reactnativecn/react-native-guide React-Native学习指南 本指南汇集React-Native各类学习资源,给大家提供便利。指南正在不断的更新,大家有好的资源欢迎Pull ...
  • 移动端开发过程中Alert和Loading框是必不可少的组件,各个平台都有提供相应的API,当然UI样式、响应方式具有平台的差异,React-Native(iOS、Android)项目中使用一套代码,想要抹平...react-native-overlayer react...
  • 调用reactnative-fs插件时,如果数据的接口是需要验证信息的,在android上运行报错,而在iOS上运行没问题。原因是因为接口是有验证信息的,而调用这个插件时没有传入,在iOS上会自动加上验证信息,而 android需要...
  • 今天遇到了一个问题:下载了react-native-webview的开源组件,可是在Android中遇到了问题,编译不通过,我想删除这个组件,然后写其他的功能,以后再添加这个地图功能,可是发现无法删除干净,android和ios原生都...
  • React-Native资源

    2017-04-09 23:21:43
    React-Native学习资源
1 2 3 4 5 ... 20
收藏数 5,603
精华内容 2,241
关键字:

post react-native