戏说JSON与JSONP

一、什么是JSON

  • JSON指的是Javascript对象表示法(Javascript Object Notation)
  • JSON是轻量级的文本数据交换格式或数据描述格式
  • JSON使用javascript语法来描述对象,但JSON仍然独立于语言和平台
  • JSON和文字对象唯一的语法差异在于,在JSON中,属性名称需要包装在引号中才能称为合法的JSON。而对象字面量中,仅当属性名称不是有效的标识符时才会需要引号。比如,字符之间有空格{“first name”,”Sem”}

二、JSON的优点

  • 基于纯文本,便于跨平台传递;
  • Javascript原生支持,后台语言几乎全部支持;
  • 轻量级数据格式,占用字符数量极少,适合网络传输;
  • 容易编写和解析,格式化处理后可读性较强

三、使用JSON

1、定义及使用
//描述一个人
var person = {
    "name" : "Semlinker",
    "age" : "28"    
}
//获取这个人的姓名
var name = person.name;
2、常用操作
//字符串转JSON
var jsStr = '{"mykey" : "my value"}';
var data = JSON.parse(jsStr);
//序列化为一个JSON字符串
var mycar = {
    name : "ferrari",
    color : "yellow"
};
var jsonstr = JSON.stringify(mycar);

四、什么是JSONP

  • Javascript出于安全方面的考虑,不允许跨域调用其他页面的对象
  • Web中含有src属性的组件,都拥有跨域的能力,比如script、img、iframe组件
  • 当前阶段如果想通过纯web端跨域访问数据只有一种可能,那就是在远程服务器上设法把数据装进js格式的文件里,以便供客户端进一步调用和处理
  • 恰巧我们已经知道有一种叫做JSON的纯字符数据格式可以简洁的描述复杂数据,更妙的是JSON还被js原生支持,所以在客户端几乎可以随心所欲的处理这种格式的数据
  • 这样一来解决方案就呼之欲出了,web客户端通过与调用脚本一模一样的方式,来调用跨域服务器上动态生成的js格式文件,显而易见,服务器之所以要动态生成JSON文件,目的就在于把客户端需要的数据装入进去
  • 客户端在对JSON文件调用成功之后,也就获得了自己所需的数据,剩下的就是按照自己需求进行处理和展现了,这种获取远程数据的方式看起来非常像AJAX,但其实并不一样
  • 为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了

五、JSONP的实现

一、客户端实现
<!DOCTYPE html>
<html lang="zh-cn">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<head>
    <title></title>
    <script type="text/javascript">
        // 获取航班信息查询结果后的回调函数
        var flightHandler = function(data){
        console.info('你查询的航班结果是:票价 ' + data.price + ' 元,' + '余票 ' + data.ticket + ' 张。');
        };
        // 提供jsonp服务的url地址(不管是什么类型的地址,最终的返回值都是一段javascript代码)
       var url = "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998&callback=flightHandler";
        // 创建script标签,设置其属性
        var script = document.createElement('script');
        script.setAttribute('src', url);
        // 把script标签加入head,此时调用开始
       document.getElementsByTagName('head')[0].appendChild(script); 
   </script>
</head>
    <body></body>
</html>
二、服务端实现
flightHandler({
  "code": "CA1998",
  "price": 1780,
  "tickets": 5
});

六、ajax与jsonp的区别

  • ajax和jsonp这两种技术在调用方式上很相似,都是请求一个url,然后对服务器返回的数据进行处理,因此jquery和ext等框架都把jsonp作为ajax的一种形式进行了封装
  • ajax和jsonp其实本质上是不同的东西。ajax的核心是通过XmlHttpRequest获取远程内容,而jsonp的核心则是动态添加script标签来调用服务器提供的js脚本
  • ajax与jsonp的区别不在于是否支持跨域,ajax通过服务端代理一样可以实现跨域,jsonp本身也不排斥同域的数据的获取
  • jsonp是一种方式或者说非强制性协议,如同ajax一样,它也不一定非要用json格式来传递数据,如果你愿意,字符串都行,只不过这样不利于用jsonp提供公开服务

玩转Emmet

一、Emmet是什么

Emmet是一组用于快速编写HTMLCSS的工具,它由两个核心组件组成:缩写扩展器和与上下文无关的HTML标签对匹配器。

二、Emmet能干嘛

亲,难道你是传说中的”闪电手”,编写下面这个HTML结构,你需要多长时间,一分钟 ? 两分钟 ? 马上试试

<div id="page">
<div class="logo"></div>
<ul id="navigation">
    <li><a href="">Item 1</a></li>
    <li><a href="">Item 2</a></li>
    <li><a href="">Item 3</a></li>
    <li><a href="">Item 4</a></li>
    <li><a href="">Item 5</a></li>
</ul>
</div>  

努力地敲着键盘…..
见证奇迹的时刻到了,请睁大你的双眼,抬起你那高贵的双手,轻轻地键入

#page>div.logo+ul#navigation>li*5>a{Item $}   ---------》革命尚未成功,请你迅速你按下Tab

怎么样是不是已经有了恋爱的冲动,爱它就赶快行动吧 ——————-> 继续往下看

三、更多示例

示例1:
输入: div#header>ul#nav>li*4>a
输出:
<div id="header">
<ul id="nav">
    <li><a href=""></a></li>
    <li><a href=""></a></li>
    <li><a href=""></a></li>
    <li><a href=""></a></li>
</ul>
</div>

示例2:
输入:div.item$*3
输出:
<div class="item1"></div>
<div class="item2"></div>
<div class="item3"></div>

示例3:
输入:div#i$-test.class$$$*3
输出:
<div id="i1-test" class="class001"></div>
<div id="i2-test" class="class002"></div>
<div id="i3-test" class="class003"></div>

四、常用缩写

  • html:5 (html5结构)
  • link:css (引入css)
  • script:src (引入js)
  • script (html中插入js)
  • ul+ (ul及一个li)
  • a:link (插入a标签)
  • form:get (get表单)
  • input:hidden (hidden输入框)
  • div#name (id:name)
  • div.name (class:name)
  • head>link:css (head添加link)
  • p+p (添加2个p)
  • p*3 (添加3个p)
  • ul>li.item$*6 (创建ul下有个li同时class分别为item1,item2)

五、展开缩写说明

展开缩写功能将类似CSS的选择器转换为XHTML代码。
以下是支持的属性和操作符列表

  • E (元素名称 div,p)
  • E#id(使用id的元素div#content,p#intro)
  • E.class(使用类的元素div.header)
  • E > N(子代元素div>p)
  • E + N(兄弟元素h1+p)
  • E N(元素倍增ul#nav>li5>a)
  • E$ * N(条目编号)

Javascript事件代理

一、什么是事件代理

事件代理,也有人翻译为”事件委托”,是一种利用javascript事件冒泡特性的高级方法。当有多个子元素或者子元素经常变化时,通过事件代理可以只监听父级元素事件,这样就避免了把事件处理器添加到多个子级元素上。一般情况下这样做的效率更高,而且代码机构更加清晰,易于后续操作和管理。

二、事件代理的应用

假设有以下导航菜单,它由一个ul父节点和多个li子节点组成。

<ul id="nav">
    <li class="menu"><a href="">menu 1</a></li>
    <li class="menu"><a href="">menu 2</a></li>
    <li class="menu"><a href="">menu 3</a></li>
    <li class="menu"><a href="">menu 4</a></li>
    <li class="menu"><a href="">menu 5</a></li>
</ul>

当我们鼠标移动到li的时候,需要获取此li的相关信息并以悬浮框的形式显示详细信息,或者当li被点击的时候需要触发相应的处理事件。我们通常的做法是为每个li都添加一个onMouseOver或者onClick之类的事件监听()。

function addListeners4Li(liNode){
  liNode.onclick = function clickHandler(){...};
  liNode.onmouseover = function mouseOverHandler(){...}
}

window.onload = function(){
  var ulNode = document.getElementById("nav");
  var liNodes = ulNode.getElementByTagName("li");
  for(var i=0, l = liNodes.length; i < l; i++){
    addListeners4Li(liNodes[i]);
  }   
}  

如果该ul中的子元素li会频繁地添加或者删除,我们就需要在每次添加li的时候都调用addListeners4Li方法来为对应的li节点添加事件处理函数,这样就增加了工作的繁琐性和出错的可能性。
那我们该使用什么办法来解决这个问题呢?更简单的方式就是使用事件代理机制,当事件传递上层父节点的时候,我们通过检查事件的目标对象来判断并获取事件源li。具体代码如下:

// 获取父节点,并为它添加一个click事件
document.getElementById("nav").addEventListener("click",function(e) {
// 检查事件源e.targe是否为Li
if(e.target && e.target.nodeName.toLowerCase() == "li") {
// 真正的处理过程在这里
    handle4Click();
  }
});  

为父节点ul添加一个click事件,当子节点被点击的时候,click事件会从子节点开始向上冒泡。父节点捕获到事件之后,通过判断e.target.nodeName来判断是否为我们需要处理的节点,并且通过e.target拿到了被点击的li节点。从而可以获取到相应的信息,并作处理。

三、事件冒泡及捕获

DOM2.0模型将事件处理流程分为三个阶段:一、事件捕获阶段,二、事件目标阶段,三、事件起泡阶段。如图:
image

事件捕获:当某个元素触发某个事件(如onclick),顶层对象document就会发出一个事件流,随着DOM树的节点向目标元素节点流去,直到到达事件真正发生的目标元素。在这个过程中,事件相应的监听函数是不会被触发的。

事件目标:当到达目标元素之后,执行目标元素该事件相应的处理函数。如果没有绑定监听函数,那就不执行。

事件冒泡:从目标元素开始,往顶层元素传播。途中如果有节点绑定了相应的事件处理函数,这些函数都会被一次触发。如果想阻止事件起泡,可以使用e.stopPropagation()(Firefox)或者e.cancelBubble=true(IE)来组织事件的冒泡传播。

四、事件代理的优点

1、当遇到子元素非常多时,使用事件代理无疑大大的减少了浏览器在内存中创建的事件监听处理器,提高了性能,降低了内存消耗;

2、当子元素可能会不断地被增加、删除或者替换时,使用事件代理就避免出现某些元素的事件没有被移除,造成内存泄露的风险;

3、代码管理更加清晰,外层做统一的事件管理,易于修改和扩展。

Fork me on GitHub