Visual Studio Code 相关
之前使用 setting sync 同步过别人 git gist 上的 vsCode 配置,接触了一些很好用的功能,不过同时也有大量的拓展和相关配置一并被下载下来了,然后就遇到了些问题,现在准备重新安装 vscode
之前使用 setting sync 同步过别人 git gist 上的 vsCode 配置,接触了一些很好用的功能,不过同时也有大量的拓展和相关配置一并被下载下来了,然后就遇到了些问题,现在准备重新安装 vscode
需要用到的时候常常忘记,与其每次去Google还不如自己好好做下记录,至少不用去Google了吧,哈哈
主要是记录下我学习 MongoDB 的过程和遇到的问题,以供后续的查阅和学习,持续改进吧
一直以来虽然写了不少promise,总感觉有点一知半解,现在花些时间整理下。
自己最早是从一篇介绍promise的文章看到的,记得文章中说promise可以使代码更整洁,避免陷入重重的回调当中。之后真正写是从angularjs中的$http服务中开始的,嗯,其中的写法很多,我一直用success和error来加载回调函数,现在看起来应该是then和catch的实现(或者是只用then方法即then中含有两个方法参数),还有bootstrap UI for Angular组件中modal框部分,$modal.open().result返回的便是一个promise对象,在上面写关闭modal框后实现的方法
等等,现在又接触到angular2的observer了,
创建promise对象的流程如下所示。
new Promise(fn) 返回一个promise对象
在fn 中指定异步等处理
处理结果正常的话,调用resolve(处理结果值)
处理结果错误的话,调用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对象只有三种状态,成功,失败,初始化状态
“has-resolution” - Fulfilled
resolve(成功)时。此时会调用 onFulfilled
“has-rejection” - Rejected
reject(失败)时。此时会调用 onRejected
“unresolved” - Pending
既不是resolve也不是reject的状态。也就是promise对象刚被创建后的初始化状态等
Promise.all 接收一个 promise对象的数组作为参数,当这个数组里的所有promise对象全部变为resolve或reject状态的时候,它才会去调用 .then 方法。
Promise.all([promise1,promise2],...).then(res=>{})
res接收各个结果组成的数组,
个人觉得这个会应用于接口间顺序的请求渲染,比如编辑页面的初始渲染可能会依赖于一些字典接口查询后的结果。或者对多个接口数据请求后的统一处理。
Promise.race 也同样接收一个promise对象的数组作为参数,区别是Promise.race只要有一个promise对象进入 FulFilled 或者 Rejected 状态的话,就会继续进行后面的处理
这样的话,之后的then或catch接收的参数就只有最快进入FulFilled 或 Rejected 状态的promise返回的数据了
记录下
sublime有很高的配置性,这里说下他的主题部分和插件(BracketHightLighter)的相关配置。
js中数据类型分基本数据类型和引用数据类型两种,对象便是某个特定引用类型的实例。
Array构造函数在web中作为window对象的一个属性
var array=[];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()方法可以接收一个比较函数作为参数,用以决定那个值位于哪个值的前面。比较函数的返回值如下
返回负数,表示value1应该位于value2之前
返回0,表示两个参数相等
返回正数,表示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 | var colors = ["red","yellow","blue","green"]; |
concat()和slice()不会影响原有数组
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是一串字符串
让我缓口气,过两天在写完
jq中,数组操作新增了each()
像数组,有和数组相同的属性和方法,如length等。
之前在写angular时有用过ui-grid写过内嵌展开二级表格,怎么说呢,ui-grid很强大,功能挺多的,好像也是angular团队开发的,例子足,文档好(对那些英文阅读能力比较好的人来说),不过他的有些功能不稳定,其中就包括表格中内嵌表格的实现Expandable grid。
之后在写别的项目时也遇到了相同的需求,这次准备使用datatables,在此记录下过程。
直接上代码:
//这个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主体部分,挺简单的没啥说的
//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;
})
}
})
嗯,想说的过程全变成注释了,就酱吧。
2017.06.09,之后遇到了这个问题,去查了下文档,在datatable配置内可通过this.api().ajax.json()访问获得的json数据
其实this指向的就是table
一般是写在监听事件的处理函数中的,如下,获取触发点击事件哪一行的数据
table.row( this ).data()