snowyYU

dream passionately

之前使用 setting sync 同步过别人 git gist 上的 vsCode 配置,接触了一些很好用的功能,不过同时也有大量的拓展和相关配置一并被下载下来了,然后就遇到了些问题,现在准备重新安装 vscode

阅读全文 »

需要用到的时候常常忘记,与其每次去Google还不如自己好好做下记录,至少不用去Google了吧,哈哈

阅读全文 »

一直以来虽然写了不少promise,总感觉有点一知半解,现在花些时间整理下。

前记

自己最早是从一篇介绍promise的文章看到的,记得文章中说promise可以使代码更整洁,避免陷入重重的回调当中。之后真正写是从angularjs中的$http服务中开始的,嗯,其中的写法很多,我一直用success和error来加载回调函数,现在看起来应该是then和catch的实现(或者是只用then方法即then中含有两个方法参数),还有bootstrap UI for Angular组件中modal框部分,$modal.open().result返回的便是一个promise对象,在上面写关闭modal框后实现的方法

等等,现在又接触到angular2的observer了,

相关链接

promise小小书

Promise

创建

创建promise对象的流程如下所示。

  1. new Promise(fn) 返回一个promise对象

  2. 在fn 中指定异步等处理

  3. 处理结果正常的话,调用resolve(处理结果值)

  4. 处理结果错误的话,调用reject(Error对象)

举个书上的栗子,一看便懂

function getURL(URL) {
    return new Promise(function (resolve, reject) {
        var req = new XMLHttpRequest();
        req.open('GET', URL, true);
        req.onload = function () {
            if (req.status === 200) {
                resolve(req.responseText);
            } else {
                reject(new Error(req.statusText));
            }
        };
        req.onerror = function () {
            reject(new Error(req.statusText));
        };
        req.send();
    });
}
// 运行示例
var URL = "http://httpbin.org/get";
getURL(URL).then(function onFulfilled(value){
    console.log(value);
}).catch(function onRejected(error){
    console.error(error);
});

首先,返回resolve就代表着接下来then的回调函数会调用,(也意味着catch中的回调函数不会执行了)

这有个angular2的例子,是个resolve很好的应用

//返回的promise中的泛型,为返回data的格式
queryLoans(query:any):Promise<{count:number,items:Loan[]}>{
    return this.myHttp.get({
      api:this.myHttp.api.loanList,
      query:query
    }).toPromise()
      .then((res)=>{
        let data={
          count:0,
          items:[]
        };
        if(res.ok){
          console.log(res);
          let result=res.json();
          if(result.status===200){
            data.count=result.body.paginator.totalCount;
            for(let l of result.body.records){
              let loan=new Loan();
              loan.borrowApplyId=l.borrowApplyId;
              loan.memberId=l.memberId;
              loan.companyName=l.companyName;
              loan.applyAmount=parseFloat(l.applyAmount);
              loan.approveAmount=parseFloat(l.approveAmount);
              loan.productId=l.productId;
              loan.borrowHowLong=l.borrowHowlong;
              loan.repaymentWay=l.repaymentWay;
              loan.cardId=l.cardId;
              loan.cardNo=l.cardNo;
              loan.isContract=!!parseFloat(l.isContract);
              loan.status=parseFloat(l.status);
              loan.createTime=l.createTime;
              loan.auditOneTime=l.auditOneTime;
              loan.auditOneBy=l.auditOneBy;
              data.items.push(loan);
            }
          }
        }
        return Promise.resolve(data);
      });
}

angular2使用typescript来写的,ts可以说是强类型了,这个方法是用来获取接口的数据,并对接收的数据进行了一定的格式化,最后把格式化后的数据放在promise中的resolve中返回,angular2中这种和数据打交道的方法一般都放置在服务中,组件作为服务的最大消费者来调用它。

Promise的状态

实例化的promise对象只有三种状态,成功,失败,初始化状态

  • “has-resolution” - Fulfilled
    resolve(成功)时。此时会调用 onFulfilled

  • “has-rejection” - Rejected
    reject(失败)时。此时会调用 onRejected

  • “unresolved” - Pending
    既不是resolve也不是reject的状态。也就是promise对象刚被创建后的初始化状态等

Promise.all

Promise.all 接收一个 promise对象的数组作为参数,当这个数组里的所有promise对象全部变为resolve或reject状态的时候,它才会去调用 .then 方法。

Promise.all([promise1,promise2],...).then(res=>{})

res接收各个结果组成的数组,

个人觉得这个会应用于接口间顺序的请求渲染,比如编辑页面的初始渲染可能会依赖于一些字典接口查询后的结果。或者对多个接口数据请求后的统一处理。

Promise.race

Promise.race 也同样接收一个promise对象的数组作为参数,区别是Promise.race只要有一个promise对象进入 FulFilled 或者 Rejected 状态的话,就会继续进行后面的处理

这样的话,之后的then或catch接收的参数就只有最快进入FulFilled 或 Rejected 状态的promise返回的数据了

js中数据类型分基本数据类型和引用数据类型两种,对象便是某个特定引用类型的实例。
Array构造函数在web中作为window对象的一个属性

数组的初始化

  1. var array=[];
  2. var array=new Array();

var array=new Array(5)接收的参数作为新建数组的长度
var array=new Array("param1","param2","param3")直接接收数组成员作为参数

数组的方法

数组的长度

var family = ["child","mother","father"];
family.length    //3

js中,数组的长度可变,会随着数据的添加而增长,所以会出现所含项数和length属性值不等的情况,如下

var family = ["child","mother","father"];
family.length=4;
family[3]    //undefined
family.length=2;
family[2]    //undefined

数组的检测

数组的检测不能使用typeof,因为返回的是object

说到这个我想起来我本来有个误解,以为typeof只能返回js数据类型的名称呢,

undefined,null,boolean,string,number,object,symbol(es6新增)。其实检测function类型时会返回function,具体typeof的返回值看这里

然后就是这个方法,instanceof其实从字面上就可以看出它是干嘛的了,可以理解为判断对象是否是被右边的家伙所实例化(语无伦次)。

摘自js高程

instanceof操作符在存在多个作用域(像一个页面包含多个frame)的情况下,也是问题多多。一个经典的例子

var isArray = value instanceof Array

以上代码要返回true,value必须是一个数组,而且还必须与Array构造函数在同个全局作用域中。(别忘了,Array是window 的属性)如果value是在另一个frame中 定义的数组。那么以上代码就会返回false。

推荐用这种方法
object.prototype.toString.call(value)

如果value为数组的话会返回[object Array],同时这种方法也可以检测原生函数或正则表达式,分别返回[object Function]和[object RegEXp]

数组的转化方法

所有对象都具有toLocaleString(),toSring()和valueOf()方法,所以数组也不例外。

还有join()

数组转化为对象

数组的操作

栈方法

栈数据结构的访问规则是LIFO(last-in-first-out,后进先出),两个方法push()和pop()

我我觉得可以理解为操作一直在数组尾巴处进行

push()返回操作后数组的长度。

pop()删除并返回数组最后一项

几个例子

var colors = new Array();
colors.push("red","green");    //返回数组的长度2,此时colors=["red","green"]
colors.pop();                  //返回数组的最后一项"green",此时colors=["red"]

队列方法

队列数据的访问规则是FIFO(first-in-first-out,先进先出),

shift(),移除数组中的第一个项并返回该项,同时将数组长度减1。

unshift(),在数组前端添加任一个项并返回新数组的长度。

例子如下

var colors = new Array();
colors.push("white","blue");
colors.shift();              //返回数组的第一项"white",此时colors=["white"]
colors.unshift("purple","yellow");  //返回数组的长度3,此时colors=["purple","yellow","white"]   

重排序方法

reverse(),将原数组的顺序颠倒,返回一个数组。

sort(),会先调用每个项的toString()方法,然后比较得到的字符串,用以确定排序

数组各项是数字可能会出问题,因为仍然会先转化为字符串在进行排序,这样的话比较的就是各自的字符编码(ASCII),如下

var numbs=[0,1,5,10,15];
numbs.sort();
console.log(numbs);     //[0,1,10,15,5]
console.log("5".charCodeAt());      //53
console.log("10".charCodeAt());     //49

但是sort()方法可以接收一个比较函数作为参数,用以决定那个值位于哪个值的前面。比较函数的返回值如下

  1. 返回负数,表示value1应该位于value2之前

  2. 返回0,表示两个参数相等

  3. 返回正数,表示value1应该位于value2之后

    function compare(value1,value2){
    if(value1 < value2){
    return -1;
    }else if(value1 > value2){
    return 1;
    }else {
    return 0;
    }
    }

    var numbs=[0,1,5,10,15];
    numbs.sort(compare);
    console.log(numbs); //[0,1,5,10,15]

操作方法

concat()拼接数组,直接上例子

var colors = ["red","yellow","blue","green"];
var colors2 = colors.concat("purple",["black","white"]);
console.log(colors2);   //["red","yellow","blue","green","purple","black","white"]

slice()接收一个或两个参数,即要返回起始至末尾或者起始和结束位置(不包括)的项,上例子

注意 slice() 方法可以不传参数,看下面例子

注意参数可以为负值

1
2
3
4
5
6
7
var colors = ["red","yellow","blue","green"];
var colorss = colors.slice() // 相当于colors.slice(0)
var colors3 = colors.slice(1);
var colors4 = colors.slice(1,2);
var colors5 = colors.slice(-3,-2); //colors.length-3==1
console.log(colors3); //["yellow", "blue", "green"]
console.log(colors4); //["yellow"]

concat()和slice()不会影响原有数组

splice

splice方法很强大,可以实现数组的删除,插入,替换功能,语法为:

arrayObject.splice(index,howmany,item1,.....,itemX);
index  必需。整数,规定添加删除项目的位置,使用负数可从数组结尾处规定位置。
howmany 必需。要删除的项目数量。如果设置为 0,则不会删除项目。
item1, ..., itemX   可选。向数组添加的新项目。

返回删除的项组成的数组,如果没有删除的项,返回一个空数组。

该方法会改变原始数组。

位置方法

indexOf()和lastIndexOf(),都接收两个参数,要查找的项和表示查找起点的索引(可选)

不同点是indexOf从头开始找,lastIndexOf从尾巴找

都返回要查找的项在数组中的位置,没找到的话返回-1

indexOf()从

想起来,字符串类型也有indexOf()方法,比如检测cookie中是否含user字段document.cookie.indexOf("user="),顺带一提,document.cookie是一串字符串

迭代方法

  • every()
  • filter()
  • forEach()
  • map()
  • some()

让我缓口气,过两天在写完

归并方法

其他

jq中,数组操作新增了each()

伪数组

像数组,有和数组相同的属性和方法,如length等。

  • nodelist
  • argument

参考文章

  1. 一瓢江湖
  2. 简书
  3. js高程

之前在写angular时有用过ui-grid写过内嵌展开二级表格,怎么说呢,ui-grid很强大,功能挺多的,好像也是angular团队开发的,例子足,文档好(对那些英文阅读能力比较好的人来说),不过他的有些功能不稳定,其中就包括表格中内嵌表格的实现Expandable grid

之后在写别的项目时也遇到了相同的需求,这次准备使用datatables,在此记录下过程。

直接上代码:

html部分

//这个div用来存放查询条件
<div>
    <div class="float-left m-b-md"><label>账户名:</label><input id="accountName" type="text"></div>
    <div class="float-left m-b-md"><label>银行账号:</label><input id="bankAccount" type="text"></div>
    <div class="float-left m-b-md"><label>账户ID:</label><input id="accountId" type="text"></div>
    
    <button id="searchBtn" class="m-b-md">查询</button>
</div>
//以下是table的主体
<table id="example" class="display" cellspacing="0" width="100%">
    <thead>
        <tr>
            <th></th>
            <th>账户ID</th>
            <th>账户名</th>
            <th>账户状态</th>
            <th>账户类型</th>
            <th>账户余额</th>
            <th>银行账号</th>
            <th>冻结金额</th>
            <th>在途金额</th>
            <th>最后交易时间</th>
            
            
        </tr>
    </thead>
</table>

html部分分为搜索部分和table主体部分,挺简单的没啥说的

js部分

    //1.初始化部分
    //1.1禁用表格自带的搜索和排序
    $.extend($.fn.dataTable.defaults, {
        searching: false,
        ordering: false
    });
    //1.2初始化表格主体
    var table = $('#example').DataTable({
    //配置相应部分的中文显示(废话,不然就显示英文了)
        "language": {
            "lengthMenu": "每页 _MENU_ 条记录",
            "zeroRecords": "没有找到记录",
            "info": "第 _PAGE_ 页 ( 总共 _PAGES_ 页 )",
            "infoEmpty": "无记录",
            "infoFiltered": "(从 _MAX_ 条记录过滤)",
            "paginate": {
                "first": "First",
                "last": "Last",
                "next": "后一页",
                "previous": "上一页"
            },
        },
    
        "pageLength": 10,           //默认每页条数
        "lengthChange": false,      //禁掉表格自带的选择每页条数的下拉框
        "processing": true,         //是否显示进度遮罩
        "serverSide": true,         //开启服务端传输数据
        "ajax": {                   //ajax
            url: "${ctx}/client/account/accountListData",
            type: "POST",
            data: function(d) {
                //获取查询条件的值
                var accountName  = $("#accountName").val();
                var bankAccount  = $("#bankAccount").val();
                var accountId  = $("#accountId").val();
                //添加额外的参数传给服务器  
                 d.accountName = accountName;
                 d.bankAccountNo = bankAccount;
                 d.accountId = accountId;
            },
            
        },
        //这里虽然没用到,但这个属性很有用,可以初始datatable的data(还是去看看官网吧),因为插件对返回值的格式要求严格
        /* "dataSrc": function(json){
               
               return json.data[0].body.records;
            }, */
        //配置各列
        "columns": [{
            className: 'details-control',   //就是给这列添加的类名
            orderable: false,               //禁用掉这列的排序功能
            data: null,                  //data为空,因为这列只有展开icon
            defaultContent: ''          //没数据的话为空
            },{
            data:'accountId'
                /* "targets": 0,
                "data": "body",
                "render": function ( data, type, full, meta ) {
                  return data.records.memberId;
                } */
            },{
            data: 'accountName'
            },{
            data: 'accountStatusdic'
            },{
            data: 'accounTypedic'
            },{
            data: 'availableBalance'
            },{
            data: 'bankAccount'
            },{
            data: 'freezeBalance'
            },{
            data: 'undeterminedBalance'
            },/* {
            data: 'memberId',
            },{
            data: 'memberStatusDic',  
            }, */{
             data: 'lastTranTime'
            }
            ],
        "columnDefs": [
            {
                targets: [5, 7, 8 ],  //这个用于对列的批量处理,里面为需要处理的列的下标
                //render很有用,这里主要是过滤用,好像在columns中也可以写render
                render: function(data,type,row,meta){
                    return ("¥"+data.toFixed(2));
                }
            },
            
         ] 
    });
    //点击查询,触发表格的渲染
    $("#searchBtn").click(function() {
        table.ajax.reload();
    });
    //二级table的模板
    function format(table_id) {
        return '<table class="table table-striped" id="opiniondt_' + table_id + '">' +
        '<thead>'+
        '<tr>'+
        '<th>账户ID</th><th>账户名</th><th>账户状态</th>'+
        '<th>账户类型</th><th>可用余额</th><th>冻结金额 </th>'+
        '<th>最后交易时间</th><th>锁定金额</th><th>在途金额</th>'+
        '</tr>'+
        '</thead>' +
        '<tr>' +
        '<td>Full name:</td>' +
        '<td>Extension number:</td>' +
        '<td>Extra info:</td>' +
        '</tr>' +
        '<tr>' +
        '<td>Full name:</td>' +
        '<td>Extension number:</td>' +
        '<td>Extra info:</td>' +
        '</tr>' +
        '</table>';
    }
    //先初始化一个变量,用于动态给展开的二级table赋值
    var iTableCounter = 1;
    var oInnerTable;
    //展开icon的点击事件
    $('#example tbody').on('click', 'td.details-control', function() {
        //获得最近的tr老爸
        var tr = $(this).closest('tr');
        //遍历老铁们
        var td = $(this).siblings("td");
        //获取第一个老铁的内容
        var acId=td[0].innerHTML;
        
        //把选择的这一行变成datatable的行,这样就可以使用一些方法了
        //dataTables默认给所有的行设置了他们的子显示区
        //可通过row().child.show()和row().child.hide()显示隐藏
        var row = table.row(tr);
        
        var data;
        if (row.child.isShown()) {
            //  This row is already open - close it
            row.child.hide();
            //这个shown是为了控制展开icon和收缩icon的切换显示
            tr.removeClass('shown');
        } else {
            //ajax开始传参给后台
              $.ajax({
                url:"${ctx}/client/account/getSlaveAccount",
                type:"POST",
                data:{accountId:acId},
            }).done(function(res){
                data = JSON.parse(res);
                //这里是请求后台字典接口,进行过滤数据,记住设置为同步请求
                data.slaveAccounts.forEach(function(e){
                    (function(){
                    $.ajax({
                        url:"${ctx}/client/dict/getDicValue",
                        type:"post",
                        async:false,
                        data:{
                            type:"accountType",
                            value:e.accountType,
                            defaultValue:""
                        }
                    }).done(function(res1){
                        e.accountType=res1;
                    });
                }());
                    //处理accountStatus
                    (function(){
                    $.ajax({
                        url:"${ctx}/client/dict/getDicValue",
                        type:"post",
                        async:false,
                        data:{
                            type:"accountStatus",
                            value:e.accountStatus,
                            defaultValue:""
                        }
                    }).done(function(res2){
                        e.accountStatus=res2;
                    });
                    }());
                })
                var lastData=data.slaveAccounts;
                // Open this row
                //child()内接收二级table的模板
                row.child(format(iTableCounter)).show();
                //显示出收缩icon
                tr.addClass('shown');
                // try datatable stuff
                //为所有的二级列表配置
                oInnerTable = $('#opiniondt_' + iTableCounter).dataTable({
                    data: lastData,
                    autoWidth: true,
                    deferRender: true,
                    info: false,
                    lengthChange: false,
                    ordering: false,
                    paging: false,
                    scrollX: false,
                    scrollY: false,
                    searching: false,
                    columns: [{
                        data: 'accountId'
                    }, {
                        data: 'accountName'
                    }, {
                        data: 'accountStatus'
                    }, {
                        data: 'accountType'
                    }, {
                        data: 'availableBalance'
                    }, {
                        data: 'freezeBalance'
                    }, {
                        data: 'lastTranTime'
                    }, {
                        data: 'lockBalance'
                    }, {
                        data: 'undeterminedBalance'
                    }],
                    columnDefs: [{
                        targets: [4,5, 7, 8 ],
                        render: function(data,type,row,meta){
                                    return ("¥"+data.toFixed(2));
                                }
                    }] 
                });
                //+1后下一个展开的二级table的id加1
                iTableCounter = iTableCounter + 1;
            })  
        }
    })

嗯,想说的过程全变成注释了,就酱吧。

别的东西

从别处访问获得的json数据

2017.06.09,之后遇到了这个问题,去查了下文档,在datatable配置内可通过this.api().ajax.json()访问获得的json数据

其实this指向的就是table

操作行数据

一般是写在监听事件的处理函数中的,如下,获取触发点击事件哪一行的数据
table.row( this ).data()

0%