最近开发中遇到的问题

1. BootStrap模态框回车刷新的问题

最近开发一个需求,需要在BootStrap的模态框中实现回车键查询功能,每次按下回车键的时候,页面就会刷新,点击查询按钮则没有问题.
Google了一下发现很多人遇到了这个问题.

How to avoid refreshing the page in a bootstrap modal?

Keep a Modal Window open after form submission.

也有人在Github提了Issue:

Modal closes on Enter key press when there’s a form

问题的原因可能是: form表单提交的默认行为导致的. 按下Enter后,form表单可能会被提交.具体的原因暂时还没有时间研究.以后有时间再研究.

Press Enter to Submit 背后的那些事

提出的解决方案有以下几种:

  • 把输入控件type='submit'改成其他的类型:
1
<button class="btn" id="signin_button">Sign in</button>
  • 阻止表单提交的默认行为:
1
2
3
$( "form" ).submit(function( event ) {
event.preventDefault();
});

我使用第二种方案解决了这个问题.

2. easyui datagrid 问题

今天遇到一个问题,easyui datagrid 初始化的时候,添加width: 'auto',table就不见了.
代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
$('#table').datagrid({
idField: 'ypmlid',
//width: 'auto',
height: 250,
singleSelect: false,
pagination: false,//是否分页
fit: false,
fitColumns: false,
columns: [[
{ field: 'ck', width: '110', checkbox: true }
]]
});

注释掉 width: 'auto' 问题就解决了.

太坑了,搞一晚上也不知道为啥…………..

Map - JavaScript 键值对

键值对

有没有遇到过在JavaScript中使用键值对的场景,键值对在C# Java 语言中是非常主流的概念,但是在JavaScript中,开发人员却面临一个挑战,大多数情况下,要使用自定义类型来解决这个问题.Map就是为了到达相同目的而设计的.

直接看代码,创建一个Map对象并且在示例中使用它.

1
2
3
4
5
6
7
8
var myMap = new Map();  
var key1 = "key1",key2="key2",key3="key3";
myMap.set(key1, "value for key1");
myMap.set(key2, 'value for key2');
myMap.set(key3, 'value for key3');
console.log(myMap.get(key1));
console.log(myMap.get(key2));
console.log(myMap.get(key3));

第一步,创建了Map对象,然后创建三个变量,然后给Map对象设置键值.

设置键值的语法

1
object.set(<key>, <value>);

正如示例中一样,给Map对象设置键值,然后输出键对应的值.

取值的语法

1
object.get(<key>) ;

上面的示例输出的结果是:

1
2
3
value for key1
value for key2
value for key3

通过移除Map中所有的键值对来清空Map对象,清空的语法:

1
myMap.clear();

通过object.clear()将清空Map中所有的值.
如果再次执行以下代码:

1
2
3
console.log(myMap.get(key1));  
console.log(myMap.get(key2));
console.log(myMap.get(key3));

输出的结果将会是:

1
2
3
undefined
undefined
undefined

那么如何从Map中删除特定的键呢.
我们先初始化Map,然后删除key2

1
2
3
4
5
myMap.set(key1, "value for key1");  
myMap.set(key2, 'value for key2');
myMap.set(key3, 'value for key3');

myMap.delete(key2);

Map中获取所有的键

1
var mapIter = myMap.keys();

最后,我们可以打印出Map中所有的键值.

1
2
3
for (var [key, value] of myMap) {  
console.log(key + ' = ' + value);
}

Map可以使用for...of循环

输出的结果:

1
2
key1 = value for with key1
key3 = value for with key3

JavaScript Function

JavaScript中,通常情况下,我们都把代码卸载函数里面,我们大部分代码执行都是函数调用的结果,为了更好的理解Function,我们需要了解javascript对象的一些特性.
javascript对象有以下一些特性:

  • 可以使用字面量创建
  • 可以赋值给变量/数组/其他对象的属性
  • 可以作为函数的参数传递
  • 有属性
  • 可以作为返回值返回

JavaScript函数拥有JavaScript对象的所有特性,而且还可以被调用.那就可以这么说,JavaScript函数就是对象.

函数同样拥有上面的特性:

  • 字面量创建
1
function myFunc() { };
  • 赋值给变量/数组/和属性
1
2
3
4
5
var myFunc = function() { };     //赋值给变量

myArray.push(function() { }); //添加到数组中

myObj.myFunc = function() { }; //赋值给对象的属性
  • 作为参数传递
1
2
3
4
function myFunc(someFunc) {
someFunc();
}
myFunc(function() { });
  • 拥有属性
1
2
var myFunc = function() { };
myFunc.someProperty = "Property";
  • 作为参数返回
1
2
3
function myFunc(){
return function() { };
}

定义JavaScript函数

JavaScript中 Function 可以通过多种方式去定义:

函数声明和函数表达式

JavaScript定义函数最常用的两种方式就是通过函数声明函数表达式
函数声明是function 关键字后面跟着函数名和参数的括号以及大括号.

1
2
3
function myFunc() {
return "Function Declaration";
}

另外一种方式,函数表达式就像编写任何JavaScript表达式一样,只有function关键字/参数和函数体,如下

1
var myFunc = function() { return "Function Expression"; };

立即执行函数

立即执行函数,就是在定义函数的写入表达式以后被立即执行,可以应用在JavaScript的模块开发中.

1
var sum = (function (param1, param2) { return param1 + param2;  })(2,3);

箭头函数

箭头函数是在ES6中添加的新特性,可以看做是通过语法糖的形式对函数表达式进行的简化,箭头函数使用=>符号定义:

1
2
var var1 = name => "Hi " + name;   //定义箭头函数
var var2 = var1("George");

如果箭头函数没有参数的话,还可以这样定义:

1
var myFunc = () => alert('Arrow Function 调用');

Form 表单 Formdata

Form表单

1
2
3
4
5
6
7
8
<form> 标签用于为用户输入创建 HTML 表单。

< form>
...
< /form >
里面包含的数据将被提交到服务器.

可以使用表单来上传文件。

三个部分

表单标签:定义表单要提交到的服务器的地址和提交的http方法。

表单域:包含了文本框、密码框、隐藏域、多行文本框、复选框、单选框、下拉选择框和文件上传框等。

表单按钮:包括提交按钮、复位按钮和一般按钮;用于将数据传送到服务器上或者取消输入,还可以用表单按钮来控制其他定义了处理脚本的处理工作。

成功控件

浏览器并不是将所有的表单控件全部发送到服务器的,而是会查找所有的【成功控件】,只将这些成功控件的数据发送到服务端

成功控件就是:每个表单中的控件都应该有一个name属性和”当前值“ value属性, 在提交时,它们将以 name=value 的形式做为提交数据的一部分。

成功控件有以下规定:

  1. 控件不能是【禁用】状态,即指定【disabled=”disabled”】。即:禁用的控件将不是成功控件。
  2. 如果一个表单包含了多个提交按键,那么仅当用户点击的那个提交按钮才算是成功控件。
  3. 对于checkbox控件来说,只有被用户勾选的才算是成功控件。
  4. 对于radio button来说,只有被用户勾选的才算是成功控件。
  5. 对于select控件来说,所有被选择的选项都做为成功控件,name由select控件提供。
  6. 对于file上传文件控件来说,如果它包含了选择的文件,那么它将是一个成功控件。

需要注意的几点:

提交方式:
如果是【post】,那么表单数据将放在请求体中被发送出去。
如果是【get】,那么表单数据将会追加到查询字符串中,以查询字符串的形式提交到服务端。
建议:表单通常还是以post方式提交比较好,这样可以不破坏URL,况且URL还有长度限制。

浏览器处理过程

浏览是如何处理表单数据的。这个过程大致分为4个阶段:

  1. 识别所有的成功控件。
  2. 为所有的成功控件创建一个数据集合,它们包含 control-name/current-value 这样的值对。
  3. 按照form.enctype指定的编码规则对前面准备好的数据进行编码。编码规则将放在请求中,用【Content-Type】指出。
  4. 提交编码后的数据。此时会区分post,get二种情况,提交的地址由form.action属性指定的。

Formdata

FormData是XMLHttpRequest Level 2新添加的一个接口,使用FormData对象可以把Form表单中所有符合条件的表单元素的name与value的执组成一个queryString提交到后台.FormData可以减少queryString的拼接.

FormData可以让我们很方便的组织一个键值对的集合.其实就是表单元素的序列化.主要的作用就是用来发送表单数据.但是可以独立于表单传输的数据.

FormData最大的优势就是可以上传二进制文件. 创建新FormData对象,然后把表单元素作为参数传入,就能得到Form表单的FormData对象.

1
2
3
4
<form id="uploadForm" enctype="multipart/form-data">
<input id="file" type="file" name="file"/>
<button id="upload" type="button">upload</button>
</form>
1
2
3
4
5
6
7
8
9
10
$.ajax({
url: '/upload',
type: 'POST',
cache: false,
data: new FormData($('#uploadForm')[0]),
processData: false,
contentType: false
})
.done(function(res) {})
.fail(function(res) {});

Reference

  1. http://www.cnblogs.com/fish-li/archive/2011/07/17/2108884.html
  2. http://blog.csdn.net/ajianyingxiaoqinghan/article/details/77678772

  3. https://developer.mozilla.org/zh-CN/docs/Web/API/FormData

  4. https://developer.mozilla.org/zh-CN/docs/Web/API/FormData/Using_FormData_Objects

JavaScript 类型判断

数据类型

在 ECMAScript 规范中,共定义了 7 种数据类型,分为 基本类型 和 引用类型 两大类,如下所示:

基本类型:String、Number、Boolean、Symbol、Undefined、Null
引用类型:Object

Symbol 是在ES6中引入的一种新的原始数据类型,表示独一无二的值。

常见的几种判断JavaScript类型的方式

1. typeof

typeof 是一个操作符,其右侧跟一个一元表达式,并返回这个表达式的数据类型。返回的结果用该类型的字符串(全小写字母)形式表示
typeof只有两个用途,就是检测一个元素是否为undefined,或者是否为function

1
2
3
4
5
6
7
8
9
10
typeof ''; // string 有效
typeof 1; // number 有效
typeof Symbol(); // symbol 有效
typeof true; //boolean 有效
typeof undefined; //undefined 有效
typeof null; //object 无效
typeof [] ; //object 无效
typeof new Function(); // function 有效
typeof new Date(); //object 无效
typeof new RegExp(); //object 无效

typeof 存在的问题

2. instanceof

instanceof 是用来判断 A 是否为 B 的实例,表达式为:A instanceof B,如果 A 是 B 的实例,则返回 true,否则返回 false

instanceof 检测的是原型

3. constructor

当一个函数 F被定义时,JS引擎会为F添加 prototype 原型,然后再在 prototype上添加一个 constructor 属性,并让其指向 F 的引用

当执行 var f = new F() 时,F 被当成了构造函数,f 是F的实例对象,此时 F 原型上的 constructor 传递到了 f 上,因此 f.constructor == F

4. Object.prototype.toString()

toString()Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]]

它会返回正确的类型。我们需要做的就是手动处理其返回的字符串,最终便能获得typeof应该返回的正确字符串。

可以用来区分:Boolean, Number, String, Function, Array, Date, RegExp, Object, Error等等。

1
2
3
4
5
6
7
8
9
10
11
12
13
Object.prototype.toString.call('') ;   // [object String]
Object.prototype.toString.call(1) ; // [object Number]
Object.prototype.toString.call(true) ; // [object Boolean]
Object.prototype.toString.call(Symbol()); //[object Symbol]
Object.prototype.toString.call(undefined) ; // [object Undefined]
Object.prototype.toString.call(null) ; // [object Null]
Object.prototype.toString.call(new Function()) ; // [object Function]
Object.prototype.toString.call(new Date()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
Object.prototype.toString.call(new Error()) ; // [object Error]
Object.prototype.toString.call(document) ; // [object HTMLDocument]
Object.prototype.toString.call(window) ; //[object global] window是全局对象 global 的引用

Web开发调试工具--Fiddler

Fiddler

Fiddler官方下载地址

简介

Fiddler是Telerik提供的一款web调试工具。通过代理的方式拦截从浏览器到服务器之间的Http流量,从而实现监控Http请求,也可以很方便的学习Http的知识。

Fiddler工作原理

  1. Fiddler 由于工作在浏览器和服务器中间,Fiddler 能够查看Http请求的详细信息。通过Http传送的数据,都会被记录并分析、修改。
  2. 作为Http代理,可以在请求到达服务器之前对Request内容进行修改。默认代理为http://127.0.0.1:8888 。也可以把配置修改为其他端口。
  3. Fiddler在获取响应以后,还可以修改相应结果的详细信息。即反向代理的作用。

常用功能

  1. 查看Http请求:可以查看请求的详细信息。Request Header中的Method,Path,QueryString,Http版本信息以及Cookie信息等。

  2. 查看相应:可以查看相应的详细信息,Http状态码、响应类型、压缩方式、服务器信息等。
  3. 反向代理:可以把Http响应替换成本地文件,可以方便的调试线上内容。
    使用步骤如下:

    AutoResponder中添加规则,拦截符合规则的Http Response,然后就如下图中所示:请求被中断,就可以修改响应结果了,Fiddler中预设了几种Response可以选择。

    修改完以后点击Run to Completion,Response继续响应,就能看到修改以后的结果了。

    也可以选择其他模板,手动修改其中的Html内容。

    修改以后的响应结果就是伪造的结果了.
  4. 伪造请求:可以修改一个请求的头部,参数等信息然后发给后端。
    在请求上右键 Replay -> Reissue from Composer

    把Method修改为Post,点击Execute执行请求。
    看到请求被中断

    返回结果是405,Method不被允许,以为原来的Method为Get。

    总结

    通过学习使用Fiddler,对Http协议也能有一个整体的了解和掌握。Http协议的请求响应的各个部分都有一个详细的可视化的体现,而且还能通过中断Http的过程来伪造请求及响应,对Http的过程也有一个比较形象的理解。

    在捕获的Http列表页中能够清晰的看到请求的文件类型、Http状态码、协议、请求的域名。Url以及详情的大小和是否缓存等信息。这和前端优化息息相关。Http状态码主要有以下几种类型

    2XX:代表请求已经成功被服务器接收并处理。成功状态码


    200:OK,请求已经成功


    204:No Content 服务器成功处理请求,但不需要返回内容


    206:服务器成功处理了部分请求,Http可以基于此类响应来实现断点续传功能。


    3XX:代表客户端需要进一步操作才能完成请求。重定向状态码


    301:资源已永久移动到新位置,新的URI应当在响应的Location域中返回。


    302:临时重定向。


    303:当前请求的响应可以在另一个URI上被找到,而且客户端应当以Get的方式访问那个资源。


    304:客户端发送了一个待条件的Get请求而且该请求已经被允许,而文档的内容并没有改变,则服务器返回304,一般认为客户端有缓存


    307:与302类似,临时重定向。


    4XX:客户端错误,请求错误


    400,:语义有误,服务器无法理解


    401:Unauthorized,当前请求需要用户验证


    403:Forbidden 服务器拒绝执行


    404:Not Found 请求失败,请求的资源未被在服务器上发现。


    405:请求行中指定的请求方法不能被用于请求相应的资源


    5XX:服务端错误


    500:服务器遇到未知错误


    502:作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。


    503:由于临时的服务器维护或者过载,服务器当前无法处理请求。


    504:网关超时

使用Github Pages 搭建静态博客

初衷

很早就有搭建一个博客的想法,但是一直没有没有行动。一直以为搭建一个站点不是一件容易的事情。需要购买服务器、注册域名、DNS解析一大堆东西等等。正好五一有时间,去网上找了下blog搭建的文章,发现还可以搭建静态博客,就去看了几篇Github创建静态博客的教程,使用Markdown语法,刚好自己一直都在使用,就搭建了这个博客。

行动

Github本身是一个托管代码的平台,使用Git作为版本控制工具,很多流行的开源项目都托管在上面,现在已经不仅仅是开发者在使用Git这个优秀的版本控制工具了。由于开源项目少不了要维护文档以及介绍页面,Github也推出了Github Pages服务,可以很方便的为项目作介绍,也可以搭建博客。

博客搭建使用的是Hexo,一个基于Nodejs的博客框架,使用Markdown解析文章,生成静态页。网上的教程很多,而且Hexo本身的文档就很全,很方便使用。也可以借这个机会学习一下Nodejs。很轻量级没有麻烦的配置,但是动态程序部分很局限,对动态没什么要求的话可以使用,不用考虑多余的事情,可以专注写作。

配置和使用GitHub

Git版本控制是一种趋势,Github也提供了自己的客户端,但是国内被墙了。可以想办法下载。也可以使用其他客户端,有很多,选择一个自己喜欢的使用就可以了。步骤如下:

  • 注册一个Github账号
  • 创建一个Repo,名字就叫你的账号 yourname.github.io
  • 将自己的生成的静态Html页面推送到上面创建的Repo.
  • 然后访问 yourname.github.io 这个地址,就能看到自己的bolg了
  • 如果自己想换一个好看的主题,也可以网上找。有很多主题,也有教程。有哪些好看的 Hexo 主题

希冀

尝试写作,希望能把自己在工作中以及学习技术过程中遇到问题做一个记录。给自己树立一个目标,然后努力去实现它。

  • 提供一个能持续学习的目标

    希望自己能坚持下来,写一写自己自己的想法和简介,督促自己不断地去学习补充知识储备,提高自己的核心竞争力。

  • 积累更多的知识

    通过写作,会发现一些自己以为了解却讲不出来的概念,然后就要去找。顺带提高自己的阅读量,寻找知识便是知识积累的一个过程,还能提高自己的信息检索能力。

  • 提高沟通能力

    很多自己以为懂了的东西,当自己想要描述出来的时候,会发现无从下手。这样的话,很多情况下其实并没有理解。学习一个技术和知识最好的途径不是去听,而是去说。传播给别人的时候,事情也就弄清楚了,这个过程也提高了自己的逻辑思维能力。