面试准备

1、javascript

XMLHttpRequestphp

  • 在不从新加载页面的状况下更新网页
  • 在页面已加载后从服务器请求数据
  • 在页面已加载后从服务器接收数据
  • 在后台向服务器发送数据

XMLHttpRequest 的建立:css

function createXHR2() {html

  var xhr = null;前端

  if (window.XMLHttpRequest) {
    xhr = new XMLHttpRequest();
  } else if (window.ActiveXObject) {
    try {
        xhr = new ActiveXObject('Msxml2.XMLHTTP');
      } catch (e) {
          try {
            xhr = new ActiveXObject('Microsoft.XMLHTTP');
              } catch (e) {}
      }
  }html5

  return xhr;
}java

发送:node

var xhr = createXHR2();
xhr.open('POST', '/keyword/hit', true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader('test', 'value');
xhr.send(JSON.stringify({
keyword: 'c',
other: 'test'
})); // urlencodedjquery

接收判断:程序员

xhr.onreadystatechange = function(e) {
if (xhr.readyState === 4 && xhr.status == 200) {

console.log(xhr.responseText);

// console.log(xhr.responseXML);
console.log(xhr.getAllResponseHeaders());
console.log(xhr.getResponseHeader("Content-Type"));
console.log(xhr.status);
console.log(xhr.statusText);
} // readyState 5种状态
// 0: 未初始化
// 1: 链接创建、请求发出
// 2: 服务器返回响应
// 3: 交互(处理响应数据)
// 4: 完成,数据可交付客户端使用
// console.log('onreadystatechange: readyState:%d, status:%d, responseText:%s', xhr.readyState, xhr.status, xhr.responseText);
// demo
}

readyState

表示XMLHttpRequest对象的状态:0:未初始化。对象已建立,未调用open

1open方法成功调用,但Sendf方法未调用;

2send方法已经调用,还没有开始接受数据;

3:正在接受数据。Http响应头信息已经接受,但还没有接收完成;

4:完成,即响应数据接受完成。

Onreadystatechange

请求状态改变的事件触发器(readyState变化时会调用这个属性上注册的javascript函数)。

responseText

服务器响应的文本内容

responseXML

服务器响应的XML内容对应的DOM对象

Status

服务器返回的http状态码。200表示“成功”,404表示“未找到”,500表示“服务器内部错误”等。

statusText

服务器返回状态的文本信息。

 

方法

说明

Open(string method,string url,boolean asynch,

String username,string password)

指定和服务器端交互的HTTP方法,URL地址,即其余请求信息;

Method:表示http请求方法,通常使用"GET","POST".

url:表示请求的服务器的地址;

asynch:表示是否采用异步方法,true为异步,false为同步;

后边两个能够不指定,usernamepassword分别表示用户名和密码,提供http认证机制须要的用户名和密码。

Send(content)

向服务器发出请求,若是采用异步方式,该方法会当即返回。

content能够指定为null表示不发送数据,其内容能够是DOM对象,输入流或字符串。

SetRequestHeader(String header,String Value)

设置HTTP请求中的指定头部header的值为value.

此方法需在open方法之后调用,通常在post方式中使用。

getAllResponseHeaders()

返回包含Http的全部响应头信息,其中相应头包括Content-length,date,uri等内容。

返回值是一个字符串,包含全部头信息,其中每一个键名和键值用冒号分开,每一组键之间用CRLF(回车加换行符)来分隔!

getResponseHeader(String header)

返回HTTP响应头中指定的键名header对应的值

Abort()

中止当前http请求。对应的XMLHttpRequest对象会复位到未初始化的状态。

 
2、

http状态码
100-199 用于指定客户端应相应的某些动做。 
200-299 用于表示请求成功。 
300-399 用于已经移动的文件而且常被包含在定位头信息中指定新的地址信息。 
400-499 用于指出客户端的错误。 
500-599 用于支持服务器错误。
 
200 (OK/正常)
404 (Not Found/未找到)
500 (Internal Server Error/内部服务器错误)
 3、

“Cache-control”常见的取值有private、no-cache、max-age、must-revalidate等

 
网页的缓存是由HTTP消息头中的“Cache-control”来控制的,常见的取值有private、no-cache、max-age、must-revalidate等,默认为private。其做用根据不一样的从新浏览方式分为如下几种状况:
(1) 打开新窗口
若是指定cache-control的值为private、no-cache、must-revalidate,那么打开新窗口访问时都会从新访问服务器。而若是指定了max-age值,那么在此值内的时间里就不会从新访问服务器,例如:
Cache-control: max-age=5
表示当访问此网页后的5秒内再次访问不会去服务器
(2) 在地址栏回车
若是值为private或must-revalidate(和网上说的不同),则只有第一次访问时会访问服务器,之后就再也不访问。若是值为no-cache,那么每次都会访问。若是值为max-age,则在过时以前不会重复访问。
(3) 按后退按扭
若是值为private、must-revalidate、max-age,则不会重访问,而若是为no-cache,则每次都重复访问
(4) 按刷新按扭
不管为什么值,都会重复访问
 
4、圣杯布局
5、IE兼容性

前言

浏览器兼容是前端开发人员必须掌握的一个技能,可是初入前端的同窗或者其余后台web开发同窗每每容易选择忽略,而造成两个极端:

1 我最开始都是使用IE6,IE6上没问题,其它浏览器坑爹(多出现与前端后端一块儿搞的同窗,小生2年前就这种状态,鼓励人家用ie6.。。。)

2 我要遵循标准,我只要ff就好,IE就是坑爹的玩意,我没必要去理他(小生一年前的心态。。。)

如今看来,以前的想法都是不对的,咱们诚然应该追求最新的浏览器使用最新的技术,可是渐进加强,向后兼容的思想必定要有,

由于就如今IE6在中国的份额也是不容小视的。

抛开以前的大道理,咱们说点实际的问题,哪次前端面试不问兼容性问题?哪次咱们又能回答的很好?反正我就没一次说好的,知不足而后能改,

我前端时间便通过整理造成这篇文章,文章有不少不足,但愿各位指正、补充,后面如果能造成一篇较全面的前端兼容文章就善莫大焉了!

为何会有兼容问题?

因为市场上浏览器种类众多,而不一样浏览器其内核亦不尽相同,因此各个浏览器对网页的解析就有必定出入,这也是致使浏览器兼容问题出现的主要缘由,咱们的网页须要在主流浏览器上正常运行,就须要作好浏览器兼容。

使用Trident内核的浏览器:IE、Maxthon、TT;

使用Gecko内核的浏览器:Netcape6及以上版本、FireFox;

使用Presto内核的浏览器:Opera7及以上版本;

使用Webkit内核的浏览器:Safari、Chrome。

而我如今所说的兼容性问题,主要是说IE与几个主流浏览器如firefox,google等。

而对IE浏览器来讲,IE7又是个跨度,由于以前的版本更新甚慢,bug甚多。从IE8开始,IE浏览器渐渐遵循标准,到IE9后因为你们都一致认为标准很重要,能够说在兼容性上比较好了,可是在中国来讲,因为xp的占有率问题,使用IE7如下的用户仍然不少,因此咱们不得不考虑低版本浏览器的兼容。

对浏览器兼容问题,我通常是这样分类的,HTML,Javascript兼容,CSS兼容。 其中html相关问题比较容易处理,无非是高版本浏览器用了低版本浏览器没法识别的元素,致使其不能解析,因此平时注意一点就是。特别是HTML5增长了许多新标签,低版本浏览器有点影响时代进步啊;

javascript兼容性问题

在javascript中,各个浏览器基本语法差距不大,其兼容问题主要出如今各个浏览器的实现上,尤为对事件的支持有很大问题,在此我就说说我知道的几个问题。

① 在标准的事件绑定中绑定事件的方法函数为 addEventListener,而IE使用的是attachEvent

② 标准浏览器采用事件捕获的方式对应IE的事件冒泡机制(即标准由最外元素至最内元素或者IE由最内元素到最外元素)最后标准方亦以为IE这方面的比较合理,因此便将事件冒泡归入了标准,这也是addEventListener第三个参数的由来,并且事件冒泡做为了默认值。

③ 事件处理中很是有用的event属性得到亦不相同,标准浏览器是做为参数带人,而ie是window.event方式得到,得到目标元素ie为e.srcElement 标准浏览器为e.target

④ 而后在ie中是不能操做tr的innerHtml的

⑤ 而后ie日期函数处理与其它浏览器不大一致,好比: var year= new Date().getYear(); 在IE中会得到当前年,可是在firefox中则会得到当前年与1900的差值。

⑥ 得到DOM节点的方法有所差别,其得到子节点方法不一致。

IE:parentElement parentElement.children Firefox:parentNode parentNode.childNodes childNodes的下标的含义在IE和Firefox中不一样,Firefox使用DOM规范,childNodes中会插入空白文本节点。通常能够经过node.getElementsByTagName()来回避这个问题。

当html中节点缺失时,IE和Firefox对parentNode的解释不一样。例如:

<form> <table> <input/> </table> </form> IE:input.parentNode的值为空节点 Firefox:input.parentNode的值为form 解决方法:Firefox中节点没有removeNode方法,必须使用以下方法 node.parentNode.removeChild(node)

⑦ 关于AJAX的实现上亦有所不一样;

就javascript来讲,各大浏览器之间的差别仍是很多的,可是具体我变得这里都不大关注了,由于咱们开发过程当中通常都会使用类库,如果不使用,都会本身积累造成一个类库,因此就js而言,兼容性问题基本解决了。

让人头疼的CSS兼容

由于以前对css的理解不够深刻,也没有通过系统的学习,因此一度认为css是前端最难的东西,但真的学习后,才发现css真的很难。。。有不少东西啊!!!

我以为最让人头疼的问题仍是CSS问题,由于一点点布局上的bug,可能致使整个页面的错位,在用户看来这是极不专业的。

如今我就简要说说我对CSS兼容问题的认识: 先说点Hack的知识(真正的高手是不用Hack的,但要成为高手必须经过Hack这一关)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/* CSS属性级Hack */
 
color:red; /* 全部浏览器可识别*/
 
_color:red; /* 仅IE6 识别 */
 
*color:red; /* IE六、IE7 识别 */
 
+color:red; /* IE六、IE7 识别 */
 
*+color:red; /* IE六、IE7 识别 */
 
[color:red; /* IE六、IE7 识别 */
 
color:red\9; /* IE六、IE七、IE八、IE9 识别 */
 
color:red\0; /* IE八、IE9 识别*/
 
color:red\9\0; /* 仅IE9识别 */
 
color:red \0; /* 仅IE9识别 */
 
color:red!important; /* IE6 不识别!important 有危险*/
 
/* CSS选择符级Hack */
 
*html #demo { color:red;} /* 仅IE6 识别 */
 
*+html #demo { color:red;} /* 仅IE7 识别 */
 
body:nth-of-type(1) #demo { color:red;} /* IE9+、FF3.5+、Chrome、Safari、Opera 能够识别 */
 
head:first-child+body #demo { color:red; } /* IE7+、FF、Chrome、Safari、Opera 能够识别 */
 
:root #demo { color:red\9; } : /* 仅IE9识别 */
 
/* IE条件注释Hack */
 
<!--[if IE 6]>此处内容只有IE6.0可见<![endif]-->
 
<!--[if IE 7]>此处内容只有IE7.0可见<![endif]-->

接下来讲说一些我知道的BUG:

① css盒模型在IE6下解析有问题,咱们知道就width来讲,一个块级元素的magin、padding、boder,width7个属性的宽度之和,应该等于其父级元素的内容区域(width),而咱们通常设置宽度如果未达到其长度,浏览器就会重置margin-right的值,将之它们的和等于其值,固然如果咱们为margin设置负值,那么元素的width可能超出其父元素。

在标准下,width为padding所占区域,可是再ie6中设置width后,其真实width为所设width-其padding与border*2,我通常采用CSShack技术处理

② IE6的双倍边距BUG,在块级元素浮动后原本外边距10px,但IE解释为20px,解决办法是加上display: inline

问题:在IE6下若是某个标签使用了float属性,同时设置了其外补丁“margin:10px 0 0 10px”能够看出,上边距和左边距一样为10px,但第一个对象距左边有20px。

解决办法:当将其display属性设置为inline时问题就都解决了。

说明:这是由于块级对象默认的display属性值是block,当设置了浮动的同时,还设置了它的外边距 就会出现这种状况。

也许你会问:“为何第二个对象和第一个对象之间就不存在双倍边距的BUG”?

由于浮动都有其相对应的对象,只有相对于其父对象的浮动 对象才会出现这样的问题。

第一个对象是相对父对象的,而第二个对象是相对第一个对象的,因此第二个对象在设置后不会出现问题。

另外在一些特殊布局中,可能须要组合使用display:block;和display:inline;才能达到预期效果。

固然最坏的状况下,咱们就能够使用”margin:10px 0 0 10px;*margin:10px 0 0 10px;_margin:10px 0 0 5px”,

这种“标准属性;*IE7识别属性;_IE6识别属性”HACK方式解决

总结:这个现象仅当块级对象设置了浮动属性后才会出现,内联对象(行级对象)不会出现此问题。而且只有设置左边距和右边距的值才会出问题,上下边距不会出现问题。

1
2
3
4
<div style="width:200px;height:50px;background:#ccc;">
<div style="width:100px; height:50px;float:left;margin-left:10px; background:#eee;">
</div>
</div>

margin双布局能够说是IE6下经典的bug之一。产生的条件是:block元素+浮动+margin。

还记得我自认为会css的那个阶段,这个问题我常常碰到,会很熟练的用hack解决这个问题,当时还自觉得是,洋洋得意。如今看来,当时的本身嫩的就像个 豆芽菜。

真正css厉害的人基本上是不会碰到这个bug的,若是您时不时遇到这个bug,说明您的css还有好一段路要走。

个人体会是越少的浮动,就会越少的代码,会有更灵活的页面,会有扩展性更强的页面。这很少说,归结为到必定水平了,浮动会用的较少。

另外,您也会避免使用浮动+margin的用法。因此,越后来越不易遇到这种bug。

这里提一下解决方法,使用hack我是不推荐的,使用hack属于比初学者稍高一点的层次水平。一个页面,没有一个hack,可是各个浏览器下表现一致,这才是水平。

使用display:inline;能够解决这个问题。

而为何display:inline能够解决这个双边距bug,首先是inline元素或inline-block元素是不存在双边距问题的。

而后,float:left等浮动属性可让inline元素haslayout,会让inline元素表现得跟inline-block元素的特性同样, 支持高宽,垂直margin和padding等,因此div class的全部样式能够用在这个display inline的元素上。

以上即是我所记得的一些bug,在这里我再顺带提一下haslayout(IE8废弃该属性)。

在IE低版本浏览器时基本是表格布局的时代,几乎是全部的元素(除内联元素)都是一个盒子,内容不会超过表格的单元格,表格的单元格也不会超出表格。

在IE6推出后,CSS改变这一假设——由于CSS容许内容超出元素。 所以haslayout这个属性就诞生了。

在IE6,IE7中,每一个元素都有haslayout这个属性,能够设置为 true 或者 false。

若是设置为true,元素就必须去自我布局和渲染,所以元素会扩展去包含它溢出的内容,例如浮动或没截断的单词。

若是haslayout 没有被设置成true,那么元素需依靠某个祖先元素来渲染它。这就是不少的ie bugs诞生的地方。IE浏览器下的不少bug都是haslayout = false 引发的,

layout元素有如下特色:

拥有布局(haslayout=true)元素不会收缩,因此可能会发生文字截断、消失的现象;

布局元素对浮动自动清理;

相对定位的元素没有布局,这可能致使绝对元素定位误差;

拥有布局的元素外边距不叠加;

滚动时,页面会有所跳动;

边框消失

像素误差

haslayout不是一个CSS属性,因此咱们不能这样的来设置它 haslayout:true;

一个元素被设置成haslayout:true将被渲染成一个 having haslayout,

反之同理。 一些元素自己该属性为true,如果须要触发,最好的方法是设置其zoom属性; 哪些元素自己就 haslayout:true

<html>, <body><table>, <tr>, <th>, <td><iframe>, <embed> (non-standard element),

<object>, <applet> <img><hr><input>, <button>, <select>, <textarea>, <fieldset>, <legend>

zoom:1,被认为是最好的触发Layout的方法,由于它对当前元素没有影响。 触发haslayout,相对来讲比haslayout=false要简单。

如下属性和值将给定一个元素进行布局

position: absolute float: left or right display: inline-block;width: any value other than auto;

height: any value other than auto;zoom: any value other than normal (*);writing-mode: tb-rl

最后,由于各个浏览器对一些元素的默认值设置不一致也会致使表现差别,好比浏览器默认字体,默认行高,默认间距等。因此咱们通常会为几个主要元素设置默认值。

结语

以上即是我对浏览器兼容的简单认识,可是仍是有不少不足的地方,因为技术所限,这里提出来和各位高手交流,但愿在交流学习中和之后工做中积累相关经验,作出知足主流浏览器的网页

6、跨域

什么是跨域

JavaScript出于安全方面的考虑,不容许跨域调用其余页面的对象。但在安全限制的同时也给注入iframe或是ajax应用上带来了很多麻烦。这里把涉及到跨域的一些问题简单地整理一下:

首先什么是跨域,简单地理解就是由于JavaScript同源策略的限制,a.com 域名下的js没法操做b.com或是c.a.com域名下的对象。更详细的说明能够看下表:

URL 说明 是否容许通讯
http://www.a.com/a.js
http://www.a.com/b.js
同一域名下 容许
http://www.a.com/lab/a.js
http://www.a.com/script/b.js
同一域名下不一样文件夹 容许
http://www.a.com:8000/a.js
http://www.a.com/b.js
同一域名,不一样端口 不容许
http://www.a.com/a.js
https://www.a.com/b.js
同一域名,不一样协议 不容许
http://www.a.com/a.js
http://70.32.92.74/b.js
域名和域名对应ip 不容许
http://www.a.com/a.js
http://script.a.com/b.js
主域相同,子域不一样 不容许
http://www.a.com/a.js
http://a.com/b.js
同一域名,不一样二级域名(同上) 不容许(cookie这种状况下也不容许访问)
http://www.cnblogs.com/a.js
http://www.a.com/b.js
不一样域名 不容许
特别注意两点:
第一,若是是协议和端口形成的跨域问题“前台”是无能为力的,
第二:在跨域问题上,域仅仅是经过“URL的首部”来识别而不会去尝试判断相同的ip地址对应着两个域或两个域是否在同一个ip上。
“URL的首部”指window.location.protocol +window.location.host,也能够理解为“Domains, protocols and ports must match”。
这里说的js跨域是指经过js在不一样的域之间进行数据传输或通讯,好比用ajax向一个不一样的域请求数据,或者经过js获取页面中不一样域的框架中(iframe)的数据。只要协议、域名、端口有任何一个不一样,都被看成是不一样的域。
下表给出了相对http://store.company.com/dir/page.html同源检测的结果:
QQ截图20130613230631
要解决跨域的问题,咱们能够使用如下几种方法:
1、经过jsonp跨域
在js中,咱们直接用XMLHttpRequest请求不一样域上的数据时,是不能够的。可是,在页面上引入不一样域上的js脚本文件倒是能够的,jsonp正是利用这个特性来实现的。
好比,有个a.html页面,它里面的代码须要利用ajax获取一个不一样域上的json数据,假设这个json数据地址是 http://example.com/data.php,那么a.html中的代码就能够这样:
QQ截图20130613230631
咱们看到获取数据的地址后面还有一个callback参数,按惯例是用这个参数名,可是你用其余的也同样。固然若是获取数据的jsonp地址页面不是你本身能控制的,就得按照提供数据的那一方的规定格式来操做了。
由于是当作一个js文件来引入的,因此 http://example.com/data.php返回的必须是一个能执行的js文件,因此这个页面的php代码多是这样的:
最终那个页面输出的结果是:
因此经过 http://example.com/data.php?callback=dosomething获得的js文件,就是咱们以前定义的dosomething函数,而且它的参数就是咱们须要的json数据,这样咱们就跨域得到了咱们须要的数据。
这样jsonp的原理就很清楚了,经过script标签引入一个js文件,这个js文件载入成功后会执行咱们在url参数中指定的函数,而且会把咱们须要的json数据做为参数传入。因此jsonp是须要服务器端的页面进行相应的配合的。
知道jsonp跨域的原理后咱们就能够用js动态生成script标签来进行跨域操做了,而不用特地的手动的书写那些script标签。若是你的页面使用jquery,那么经过它封装的方法就能很方便的来进行jsonp操做了。
QQ截图20130613230631
原理是同样的,只不过咱们不须要手动的插入script标签以及定义回掉函数。jquery会自动生成一个全局函数来替换callback=?中的问号,以后获取到数据后又会自动销毁,实际上就是起一个临时代理函数的做用。$.getJSON方法会自动判断是否跨域,不跨域的话,就调用普通的ajax方法;跨域的话,则会以异步加载js文件的形式来调用jsonp的回调函数。
 
二、经过修改document.domain来跨子域
浏览器都有一个同源策略,其限制之一就是第一种方法中咱们说的不能经过ajax的方法去请求不一样源中的文档。 它的第二个限制是浏览器中不一样域的框架之间是不能进行js的交互操做的。有一点须要说明,不一样的框架之间(父子或同辈),是可以获取到彼此的window对象的,但蛋疼的是你却不能使用获取到的window对象的属性和方法(html5中的postMessage方法是一个例外,还有些浏览器好比ie6也能够使用top、parent等少数几个属性),总之,你能够当作是只能获取到一个几乎无用的window对象。好比,有一个页面,它的地址是 http://www.example.com/a.html  , 在这个页面里面有一个iframe,它的src是 http://example.com/b.html, 很显然,这个页面与它里面的iframe框架是不一样域的,因此咱们是没法经过在页面中书写js代码来获取iframe中的东西的:
  
QQ截图20130613230631
这个时候,document.domain就能够派上用场了,咱们只要把 http://www.example.com/a.html和  http://example.com/b.html这两个页面的document.domain都设成相同的域名就能够了。但要注意的是,document.domain的设置是有限制的,咱们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。例如:a.b.example.com 中某个文档的document.domain 能够设成a.b.example.com、b.example.com 、example.com中的任意一个,可是不能够设成 c.a.b.example.com,由于这是当前域的子域,也不能够设成 baidu.com,由于主域已经不相同了。
在页面  http://www.example.com/a.html中设置document.domain:
QQ截图20130613230631
在页面  http://example.com/b.html中也设置document.domain,并且这也是必须的,虽然这个文档的domain就是example.com,可是仍是必须显示的设置document.domain的值:
QQ截图20130613230631
这样咱们就能够经过js访问到iframe中的各类属性和对象了。
不过若是你想在 http://www.example.com/a.html页面中经过ajax直接请求 http://example.com/b.html页面,即便你设置了相同的document.domain也仍是不行的,因此修改document.domain的方法只适用于不一样子域的框架间的交互。若是你想经过ajax的方法去与不一样子域的页面交互,除了使用jsonp的方法外,还能够用一个隐藏的iframe来作一个代理。原理就是让这个iframe载入一个与你想要经过ajax获取数据的目标页面处在相同的域的页面,因此这个iframe中的页面是能够正常使用ajax去获取你要的数据的,而后就是经过咱们刚刚讲得修改document.domain的方法,让咱们能经过js彻底控制这个iframe,这样咱们就可让iframe去发送ajax请求,而后收到的数据咱们也能够得到了。
 
三、使用window.name来进行跨域
window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的全部的页面都是共享一个window.name的,每一个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的全部页面中的,并不会因新页面的载入而进行重置。
好比:有一个页面a.html,它里面有这样的代码:
再看看b.html页面的代码:
a.html页面载入后3秒,跳转到了b.html页面,结果为:
咱们看到在b.html页面上成功获取到了它的上一个页面a.html给window.name设置的值。若是在以后全部载入的页面都没对window.name进行修改的话,那么全部这些页面获取到的window.name的值都是a.html页面设置的那个值。固然,若是有须要,其中的任何一个页面均可以对window.name的值进行修改。注意,window.name的值只能是字符串的形式,这个字符串的大小最大能容许2M左右甚至更大的一个容量,具体取决于不一样的浏览器,但通常是够用了。
上面的例子中,咱们用到的页面a.html和b.html是处于同一个域的,可是即便a.html与b.html处于不一样的域中,上述结论一样是适用的,这也正是利用window.name进行跨域的原理。
下面就来看一看具体是怎么样经过window.name来跨域获取数据的。仍是举例说明。
好比有一个 www.example.com/a.html页面,须要经过a.html页面里的js来获取另外一个位于不一样域上的页面 www.cnblogs.com/data.html里的数据。
data.html页面里的代码很简单,就是给当前的window.name设置一个a.html页面想要获得的数据值。data.html里的代码:
QQ截图20130613230631
那么在a.html页面中,咱们怎么把data.html页面载入进来呢?显然咱们不能直接在a.html页面中经过改变window.location来载入data.html页面,由于咱们想要即便a.html页面不跳转也能获得data.html里的数据。答案就是在a.html页面中使用一个隐藏的iframe来充当一个中间人角色,由iframe去获取data.html的数据,而后a.html再去获得iframe获取到的数据。
充当中间人的iframe想要获取到data.html的经过window.name设置的数据,只须要把这个iframe的src设为 www.cnblogs.com/data.html就好了。而后a.html想要获得iframe所获取到的数据,也就是想要获得iframe的window.name的值,还必须把这个iframe的src设成跟a.html页面同一个域才行,否则根据前面讲的同源策略,a.html是不能访问到iframe里的window.name属性的。这就是整个跨域过程。
看下a.html页面的代码:
上面的代码只是最简单的原理演示代码,你能够对使用js封装上面的过程,好比动态的建立iframe,动态的注册各类事件等等,固然为了安全,获取完数据后,还能够销毁做为代理的iframe。网上也有不少相似的现成代码,有兴趣的能够去找一下。
经过window.name来进行跨域,就是这样子的。
 
四、使用HTML5中新引进的window.postMessage方法来跨域传送数据
window.postMessage(message,targetOrigin)  方法是html5新引进的特性,能够使用它来向其它的window对象发送消息,不管这个window对象是属于同源或不一样源,目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持window.postMessage方法。
调用postMessage方法的window对象是指要接收消息的那一个window对象,该方法的第一个参数message为要发送的消息,类型只能为字符串;第二个参数targetOrigin用来限定接收消息的那个window对象所在的域,若是不想限定域,能够使用通配符 *  。
须要接收消息的window对象,但是经过监听自身的message事件来获取传过来的消息,消息内容储存在该事件对象的data属性中。
上面所说的向其余window对象发送消息,其实就是指一个页面有几个框架的那种状况,由于每个框架都有一个window对象。在讨论第二种方法的时候,咱们说过,不一样域的框架间是能够获取到对方的window对象的,并且也能够使用window.postMessage这个方法。下面看一个简单的示例,有两个页面
QQ截图20130613230631
 
QQ截图20130613230631
咱们运行a页面后获得的结果:
咱们看到b页面成功的收到了消息。
使用postMessage来跨域传送数据仍是比较直观和方便的,可是缺点是IE六、IE7不支持,因此用不用还得根据实际须要来决定。
 
结语:
除了以上几种方法外,还有flash、在服务器上设置代理页面等跨域方式,这里就不作介绍了。
以上四种方法,能够根据项目的实际状况来进行选择应用,我的认为window.name的方法既不复杂,也能兼容到几乎全部浏览器,这真是极好的一种跨域方法。
 
 7、JS数据类型
JS数据类型
js中有5种数据类型:Undefined、Null、Boolean、Number和String。
还有一种复杂的数据类型Object,Object本质是一组无序的名值对组成的。
Undefined类型只有一个值,即undefined,使用var声明变量,可是未对初始化的,这个变量就是Undefined类型的,例子:
var i;
alert(i == undefined);//true
var i;与var i = undefined;这两句是等价的。
包含Undefined值的变量和未定义的变量是不同的。
Null类型也只有一个值:null.null表示一个空对象的指针。
Boolean类型:只有两个字面量true和false。可是js中多有的变量均可以使用Boolean()函数转换成一个Boolean类型的值。
Number类型:整数和浮点数。NaN:Not a Number。这个数值用于原本要返回一个数值,可是却未能放回一个数值的状况,以防止报错。

例如:1/0 返回的就是NaN。NaN的特色:一、任何涉及NaN的操做都会返回NaN。二、NaN对任何值都不相等,包括本身NaN自己。
针对NaN特性,JS内置了isNaN()函数,来肯定数值是否是NaN类型。
String类型:略
typeof操做符:对一个变量进行推断变量的类型,可能返回如下字符串:
"undefined" 若是这个值,未定义或者为初始化
"boolean" 布尔值
"string" 字符串
"number" 数值
"object" 对象
"function" 函数
用法:typeof 95;  或者  typeof(95); 会返回"number".

 

8、页面加载

输入地址
浏览器查找域名的 IP 地址
这一步包括 DNS 具体的查找过程,包括:浏览器缓存->系统缓存->路由器缓存...
浏览器向 web 服务器发送一个 HTTP 请求
服务器的永久重定向响应(从 http://example.com 到 http://www.example.com)
浏览器跟踪重定向地址
服务器处理请求
服务器返回一个 HTTP 响应
浏览器显示 HTML
浏览器发送请求获取嵌入在 HTML 中的资源(如图片、音频、视频、CSS、JS等等)
浏览器发送异步请求解析

 

html以构建dom树->构建render树->布局render树->绘制render树
现代浏览器的工做原理

 

渲染引擎开始解析html,并将标签转化为内容树中的dom节点。接着,它解析外部CSS文件及style标签中的样式信息。这些样式信息以及html中的可见性指令将被用来构建另外一棵树——render树。

Render树由一些包含有颜色和大小等属性的矩形组成,它们将被按照正确的顺序显示到屏幕上。

Render树构建好了以后,将会执行布局过程,它将肯定每一个节点在屏幕上的确切坐标。再下一步就是绘制,即遍历render树,并使用UI后端层绘制每一个节点。

值得注意的是,这个过程是逐步完成的,为了更好的用户体验,渲染引擎将会尽量早的将内容呈现到屏幕上,并不会等到全部的html都解析完成以后再去构建和布局render树。它是解析完一部份内容就显示一部份内容,同时,可能还在经过网络下载其他内容。

9、jsonp原理

JSONP跨域GET请求是一个经常使用的解决方案,下面咱们来看一下JSONP跨域是如何实现的,而且探讨下JSONP跨域的原理
 
JavaScript是一种在Web开发中常用的前端动态脚本技术。在JavaScript中,有一个很重要的安全性限制,被称为“Same-Origin Policy”(同源策略)。这一策略对于JavaScript代码可以访问的页面内容作了很重要的限制,即JavaScript只能访问与包含它的文档在同一域下的内容。

JavaScript这个安全策略在进行多iframe或多窗口编程、以及Ajax编程时显得尤其重要。根据这个策略,在baidu.com下的页面中包含的JavaScript代码,不能访问在google.com域名下的页面内容;甚至不一样的子域名之间的页面也不能经过JavaScript代码互相访问。对于Ajax的影响在于,经过XMLHttpRequest实现的Ajax请求,不能向不一样的域提交请求,例如,在abc.example.com下的页面,不能向def.example.com提交Ajax请求,等等。

然而,当进行一些比较深刻的前端编程的时候,不可避免地须要进行跨域操做,这时候“同源策略”就显得过于苛刻。JSONP跨域GET请求是一个经常使用的解决方案,下面咱们来看一下JSONP跨域是如何实现的,而且探讨下JSONP跨域的原理。

利用在页面中建立<script>节点的方法向不一样域提交HTTP请求的方法称为JSONP,这项技术能够解决跨域提交Ajax请求的问题。JSONP的工做原理以下所述:

假设在http://example1.com/index.php这个页面中向http://example2.com/getinfo.php提交GET请求,咱们能够将下面的JavaScript代码放在http://example1.com/index.php这个页面中来实现:
复制代码 代码以下:

var eleScript= document.createElement("script");
eleScript.type = "text/javascript";
eleScript.src = "http://example2.com/getinfo.php";
document.getElementsByTagName("HEAD")[0].appendChild(eleScript);

当GET请求从http://example2.com/getinfo.php返回时,能够返回一段JavaScript代码,这段代码会自动执行,能够用来负责调用http://example1.com/index.php页面中的一个callback函数。

JSONP的优势是:它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中均可以运行,不须要XMLHttpRequest或ActiveX的支持;而且在请求完毕后能够经过调用callback的方式回传结果。

JSONP的缺点则是:它只支持GET请求而不支持POST等其它类型的HTTP请求;它只支持跨域HTTP请求这种状况,不能解决不一样域的两个页面之间如何进行JavaScript调用的问题。
再来一个例子:
复制代码 代码以下:

var qsData = {'searchWord':$("#searchWord").attr("value"),'currentUserId':
$("#currentUserId").attr("value"),'conditionBean.pageSize':$("#pageSize").attr("value")};
$.ajax({
async:false,
url: http://跨域的dns/document!searchJSONResult.action,
type: "GET",
dataType: 'jsonp',
jsonp: 'jsoncallback',
data: qsData,
timeout: 5000,
beforeSend: function(){
//jsonp 方式此方法不被触发.缘由多是dataType若是指定为jsonp的话,就已经不是ajax事件了
},
success: function (json) {//客户端jquery预先定义好的callback函数,成功获取跨域服务器上的json数据后,会动态执行这个callback函数
if(json.actionErrors.length!=0){
alert(json.actionErrors);
}
genDynamicContent(qsData,type,json);
},
complete: function(XMLHttpRequest, textStatus){
$.unblockUI({ fadeOut: 10 });
},
error: function(xhr){
//jsonp 方式此方法不被触发.缘由多是dataType若是指定为jsonp的话,就已经不是ajax事件了
//请求出错处理
alert("请求出错(请检查相关度网络情况.)");
}
});
有时也会看到这样的写法:
$.getJSON("http://跨域的dns/document!searchJSONResult.action?name1="+value1+"&jsoncallback=?",
function(json){
if(json.属性名==值){
// 执行代码
}
});

这种方式实际上是上例$.ajax({..}) api的一种高级封装,有些$.ajax api底层的参数就被封装而不可见了。
这样,jquery就会拼装成以下的url get请求:
复制代码 代码以下:

http://跨域的dns/document!searchJSONResult.action?&jsoncallback=jsonp1236827957501&_=1236828192549&searchWord=
%E7%94%A8%E4%BE%8B¤tUserId=5351&conditionBean.pageSize=15

在响应端(http://跨域的dns/document!searchJSONResult.action),经过 jsoncallback = request.getParameter("jsoncallback") 获得jquery端随后要回调的js function name:jsonp1236827957501 而后 response的内容为一个Script Tags:"jsonp1236827957501("+按请求参数生成的json数组+")"; jquery就会经过回调方法动态加载调用这个js tag:jsonp1236827957501(json数组); 这样就达到了跨域数据交换的目的。

JSONP原理
JSONP的最基本的原理是:动态添加一个<script>标签,而script标签的src属性是没有跨域的限制的。这样说来,这种跨域方式其实与ajax XmlHttpRequest协议无关了。
这样其实"jQuery AJAX跨域问题"就成了个伪命题,jquery $.ajax方法名有误导人之嫌。
若是设为dataType: 'jsonp',这个$.ajax方法就和ajax XmlHttpRequest没什么关系了,取而代之的则是JSONP协议。JSONP是一个非官方的协议,它容许在服务器端集成Script tags返回至客户端,经过javascript callback的形式实现跨域访问。

JSONP即JSON with Padding。因为同源策略的限制,XmlHttpRequest只容许请求当前源(域名、协议、端口)的资源。若是要进行跨域请求, 咱们能够经过使用html的script标记来进行跨域请求,并在响应中返回要执行的script代码,其中能够直接使用JSON传递javascript对象。 这种跨域的通信方式称为JSONP。

jsonCallback 函数jsonp1236827957501(....):是浏览器客户端注册的,获取跨域服务器上的json数据后,回调的函数

Jsonp的执行过程以下:
首先在客户端注册一个callback (如:'jsoncallback'), 而后把callback的名字(如:jsonp1236827957501)传给服务器。注意:服务端获得callback的数值后,要用jsonp1236827957501(......)把将要输出的json内容包括起来,此时,服务器生成 json 数据才能被客户端正确接收。

而后以 javascript 语法的方式,生成一个function, function 名字就是传递上来的参数 'jsoncallback'的值 jsonp1236827957501 .
最后将 json 数据直接以入参的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端。

客户端浏览器,解析script标签,并执行返回的 javascript 文档,此时javascript文档数据,做为参数, 传入到了客户端预先定义好的 callback 函数(如上例中jquery $.ajax()方法封装的的success: function (json))里。
能够说jsonp的方式原理上和<script src="http://跨域/...xx.js"></script>是一致的(qq空间就是大量采用这种方式来实现跨域数据交换的)。JSONP是一种脚本注入(Script Injection)行为,因此有必定的安全隐患。
那jquery为何不支持post方式跨域呢?

虽然采用post+动态生成iframe是能够达到post跨域的目的(有位js牛人就是这样把jquery1.2.5 打patch的),但这样作是一个比较极端的方式,不建议采用。
也能够说get方式的跨域是合法的,post方式从安全角度上,被认为是不合法的,万不得已仍是不要剑走偏锋。

client端跨域访问的需求看来也引发w3c的注意了,看资料说html5 WebSocket标准支持跨域的数据交换,应该也是一个未来可选的跨域数据交换的解决方案。

来个超简单的例子:
代码以下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Test Jsonp</title>
<script type="text/javascript">
function jsonpCallback(result)
{
alert(result.msg);
}
</script>
<script type="text/javascript" src="http://crossdomain.com/jsonServerResponse?jsonp=jsonpCallback"></script>
</head>
<body>
</body>
</html>

其中 jsonCallback 是客户端注册的,获取跨域服务器上的json数据后,回调的函数。http://crossdomain.com/jsonServerResponse?jsonp=jsonpCallback 这个 url 是跨域服务器取 json 数据的接口,参数为回调函数的名字,返回的格式为:jsonpCallback({msg:'this is json data'})

简述原理与过程:首先在客户端注册一个callback, 而后把callback的名字传给服务器。此时,服务器先生成 json 数据。 而后以 javascript 语法的方式,生成一个function , function 名字就是传递上来的参数 jsonp。最后将 json 数据直接以入参的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端。

客户端浏览器,解析script标签,并执行返回的 javascript 文档,此时数据做为参数,传入到了客户端预先定义好的 callback 函数里。(动态执行回调函数) 

10、CSS合并方法

何为CSS样式合并,所谓CSS样式合并,指的是一些不可分离的样式(按钮,图标等),将他们公共的样式部分进行合并,非公共的再次独立出来,以减少CSS文件的大小

 

在项目开发环境下,咱们会把 JS 代码尽量模块化,方便管理和修改,这就避免不了会出现一个项目自身 JS 文件数量达到 10 个或者更多。

  而项目上线后,会要求将全部 JS 文件合并为 1 个或者几个,手动的操做虽然也不是问题,但每次修改更新都要手动操做合并一遍,这就确定是个噩梦了。

  这种状况下,一些工具也就随之产生,好比在线合并,一些网站提供js文件上传,而后合并,但这仍是很麻烦,若是开发环境没有网络呢?

  这会我就想到了 windows 系统下的 cmd 里的 copy 命令,它虽然是个复制的功能,但实则也是能够实现合并文件的需求,下面就看下这句代码:

copy a.js+b.js+c.js abc.js /b

  相信不会太多编程的人阅读上面那句代码也能大体读懂意思:经过 copy 命令将 a.js b.js c.js 合并为一个 abc.js,最后的 /b 表示文件为二进位文件,copy 命令的其它参数能够在 cmd 里输入 copy /? 学习,这里就再也不细述。

  说到这里,其实 windows 自己就能够完成咱们的需求,也不用安装什么其它工具了,下面咱们要作的就是将这一切操做更简单。

  咱们在项目存放 JS 的文件夹下新建一个 TXT 文件,将代码复制进去,并修改须要合并哪些文件,最后保存并将 TXT 修改成 BAT 后缀,如:

copy core.js+hros.app.js+hros.appmanage.js+hros.base.js+hros.copyright.js+hros.desktop.js+hros.dock.js+hros.folderView.js+hros.grid.js+hros.maskBox.js+hros.navbar.js+hros.popupMenu.js+hros.searchbar.js+hros.startmenu.js+hros.taskbar.js+hros.uploadFile.js+hros.wallpaper.js+hros.widget.js+hros.window.js+hros.zoom.js+templates.js+util.js core.min.js /b

  接下来咱们双击下那个 BAT 文件,看到效果了吧?这就是咱们想要的。之后每次上线前,只需双击下这个文件,系统就会自动合并并生成一个合并好的文件,比起其它什么工具,这个的效率简直没法直视。

  若是你本地还安装过 UglifyJS 这个工具,能够在代码后面加一句压缩的代码,如:

copy core.js+hros.app.js+hros.appmanage.js+hros.base.js+hros.copyright.js+hros.desktop.js+hros.dock.js+hros.folderView.js+hros.grid.js+hros.maskBox.js+hros.navbar.js+hros.popupMenu.js+hros.searchbar.js+hros.startmenu.js+hros.taskbar.js+hros.uploadFile.js+hros.wallpaper.js+hros.widget.js+hros.window.js+hros.zoom.js+templates.js+util.js core.min.js /b
uglifyjs core.min.js -m -o core.min.js

  这样每次合并好后就自动压缩了,又省了一步操做。

  CSS 合并同理。

 

11、盒子模型

标准W3C盒子模型和IE盒子模型CSS布局经典盒子模型(转)

 

盒子模型是css中一个重要的概念,理解了盒子模型才能更好的排版。其实盒子模型有两种,分别是 ie 盒子模型和标准 w3c 盒子模型。他们对盒子模型的解释各不相同,先来看看咱们熟知的标准盒子模型:

  

  从上图能够看到标准 w3c 盒子模型的范围包括 margin、border、padding、content,而且 content 部分不包含其余部分。

  ie 盒子模型

 

 

 

 

  从上图能够看到 ie 盒子模型的范围也包括 margin、border、padding、content,和标准 w3c 盒子模型不一样的是:ie 盒子模型的 content 部分包含了 border 和 pading。

   例:一个盒子的 margin 为 20px,border 为 1px,padding 为 10px,content 的宽为 200px、高为 50px,假如用标准 w3c 盒子模型解释,那么这个盒子须要占据的位置为:宽 20*2+1*2+10*2+200=262px、高 20*2+1*2*10*2+50=112px,盒子的实际大小为:宽 1*2+10*2+200=222px、高 1*2+10*2+50=72px;假如用ie 盒子模型,那么这个盒子须要占据的位置为:宽 20*2+200=240px、高 20*2+50=70px,盒子的实际大小为:宽 200px、高 50px。

  那应该选择哪中盒子模型呢?固然是“标准 w3c 盒子模型”了。怎么样才算是选择了“标准 w3c 盒子模型”呢?很简单,就是在网页的顶部加上 doctype 声明。假如不加 doctype 声明,那么各个浏览器会根据本身的行为去理解网页,即 ie 浏览器会采用 ie 盒子模型去解释你的盒子,而 ff 会采用标准 w3c 盒子模型解释你的盒子,因此网页在不一样的浏览器中就显示的不同了。反之,假如加上了 doctype 声明,那么全部浏览器都会采用标准 w3c 盒子模型去解释你的盒子,网页就能在各个浏览器中显示一致了。

  再用 jquery 作的例子来证明一下。

  代码1:

<html>
<head>
<title>你用的盒子模型是?</title>
<script language="javascript" src="jquery.min.js"></script>
<script language="javascript">
var sbox = $.boxmodel ? "标准w3c":"ie";
document.write("您的页面目前支持:"+sbox+"盒子模型");
</script>
</head>
<body>
</body>
</html>

  上面的代码没有加上 doctype 声明,在 ie 浏览器中显示“ie盒子模型”,在 ff 浏览器中显示“标准 w3c 盒子模型”。

  代码2:

<!doctype html public "-//w3c//dtd xhtml 1.0 transitional//en" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd">
<html>
<head>
<title>你用的盒子模型是标准w3c盒子模型</title>
<script language="javascript" src="jquery.min.js"></script>
<script language="javascript">
var sbox = $.boxmodel ? "标准w3c":"ie";
document.write("您的页面目前支持:"+sbox+"盒子模型");
</script>
</head>
<body>
</body>
</html>

  代码2 与代码1 惟一的不一样的就是顶部加了 doctype 声明。在全部浏览器中都显示“标准 w3c 盒子模型”。

  因此为了让网页能兼容各个浏览器,让咱们用标准 w3c 盒子模型。

 

12、事件委托

 

现在的JavaScript技术界里最火热的一项技术应该是‘事件委托(event delegation)’了。使用事件委托技术能让你避免对特定的每一个节点添加事件监听器;相反,事件监听器是被添加到它们的父元素上。事件监听器会分析从子元素冒泡上来的事件,找到是哪一个子元素的事件。基本概念很是简单,但仍有不少人不理解事件委托的工做原理。这里我将要解释事件委托是如何工做的,并提供几个纯JavaScript的基本事件委托的例子。

假定咱们有一个UL元素,它有几个子元素:

<ul id="parent-list"> <li id="post-1">Item 1</li> <li id="post-2">Item 2</li> <li id="post-3">Item 3</li> <li id="post-4">Item 4</li> <li id="post-5">Item 5</li> <li id="post-6">Item 6</li> </ul>

咱们还假设,当每一个子元素被点击时,将会有各自不一样的事件发生。你能够给每一个独立的li元素添加事件监听器,但有时这些li元素可能会被删除,可能会有新增,监听它们的新增或删除事件将会是一场噩梦,尤为是当你的监听事件的代码放在应用的另外一个地方时。可是,若是你将监听器安放到它们的父元素上呢?你如何能知道是那个子元素被点击了?

简单:当子元素的事件冒泡到父ul元素时,你能够检查事件对象的target属性,捕获真正被点击的节点元素的引用。下面是一段很简单的JavaScript代码,演示了事件委托的过程:

// 找到父元素,添加监听器...
document.getElementById("parent-list").addEventListener("click",function(e) { // e.target是被点击的元素! // 若是被点击的是li元素 if(e.target && e.target.nodeName == "LI") { // 找到目标,输出ID! console.log("List item ",e.target.id.replace("post-")," was clicked!"); } });

第一步是给父元素添加事件监听器。当有事件触发监听器时,检查事件的来源,排除非li子元素事件。若是是一个li元素,咱们就找到了目标!若是不是一个li元素,事件将被忽略。这个例子很是简单,ULli是标准的父子搭配。让咱们试验一些差别比较大的元素搭配。假设咱们有一个父元素div,里面有不少子元素,但咱们关心的是里面的一个带有”classA” CSS类的A标记:

// 得到父元素DIV, 添加监听器...
document.getElementById("myDiv").addEventListener("click",function(e) { // e.target是被点击的元素 if(e.target && e.target.nodeName == "A") { // 得到CSS类名 var classes = e.target.className.split(" "); // 搜索匹配! if(classes) { // For every CSS class the element has... for(var x = 0; x < classes.length; x++) { // If it has the CSS class we want... if(classes[x] == "classA") { // Bingo! console.log("Anchor element clicked!"); // Now do something here.... } } } } });

上面这个例子中不只比较了标签名,并且比较了CSS类名。虽然稍微复杂了一点,但仍是很具表明性的。好比,若是某个A标记里有一个span标记,则这个span将会成为target元素。这个时候,咱们须要上溯DOM树结构,找到里面是否有一个 A.classA 的元素。

由于大部分程序员都会使用jQuery等工具库来处理DOM元素和事件,我建议你们都使用里面的事件委托方法,由于这里工具库里都提供了高级的委托方法和元素甄别方法。

但愿这篇文章能帮助你理解JavaScript事件委托的幕后原理,但愿你也感觉到了事件委托的强大用处!

 

十3、模块化

AMD异步加载,依赖前置,提早执行,CMD同步加载,依赖就近,延迟执行

十4、拖拽实现

在我工做的将近一年时间,印象中拖拽是我作的最多的一种效果,在这里和你们分享一下。
    以后有时间还会作两个稍微复杂点的效果,这里先讲一下简单拖拽的实现
    
    首先,先分解一下拖拽的步骤:
    1)在目标元素上按下鼠标(这里没有细分左右键),也就是mousedown事件
    2)按下鼠标的同事,拖动鼠标,至关于在mousedown事件中绑定mousemove事件
    3)中止拖拽,释放鼠标按键,也就是mouseup事件
    代码表示以下:
    targetNode.onmousedown=function(){
        ...
        document.onmousemove=function(){
            ....
        }
        document.onmouseup=function(){
            ....
        }
    }
    这里的mousemove和mouseup事件都绑定在document上而不是目标元素上

    是由于拖拽的时候鼠标随时可能离开目标元素,这样将致使mouseover和mouseup

    找不到目标而影响拖拽的效果,具体代码以下(ps:下面的代码在火狐下是有bug的,这是由于拖拽元素的innerHTML是空的,解决办法能够加空的<span></span>标签或让其里面有内容便可,有兴趣可  以试一下)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
<style type="text/css">
*{ margin:0; padding:0;}
#dragDiv{ width:200px; height:200px; position:absolute; top:100px; left:100px; background:#ddd;}
</style>
</head>

<body>
<div id="dragDiv"></div>
<script type="text/javascript">
var dragDiv=document.getElementById('dragDiv');
//鼠标按下动做
dragDiv.onmousedown=function(event){
var e=event||window.event,
t=e.target||e.srcElement,
//鼠标按下时的坐标x1,y1
x1=e.clientX,
y1=e.clientY,
//鼠标按下时的左右偏移量
dragLeft=this.offsetLeft,
dragTop=this.offsetTop;
document.onmousemove=function(event){
var e=event||window.event,
t=e.target||e.srcElement,
//鼠标移动时的动态坐标
x2=e.clientX,
y2=e.clientY,
//鼠标移动时的坐标的变化量
x=x2-x1,
y=y2-y1;
dragDiv.style.left=(dragLeft+x)+'px';
dragDiv.style.top=(dragTop+y)+'px';
}
document.onmouseup=function(){
this.onmousemove=null;
}
}
</script>
</body>
</html>

 
e.target和e.srcElement表示的都是事件的目标
e.srcElement兼容IE,e.target兼容非IE
IE9,chrome(个人版本,具体不知道哪一版)两个属性都兼容
e.target||e.srcElement能够保证在任何一个浏览器上都有值
十5、JS继承实现
 

js是门灵活的语言,实现一种功能每每有多种作法,ECMAScript没有明确的继承机制,而是经过模仿实现的,根据js语言的自己的特性,js实现继承有如下通用的几种方式
1.使用对象冒充实现继承(该种实现方式能够实现多继承)
实现原理:让父类的构造函数成为子类的方法,而后调用该子类的方法,经过this关键字给全部的属性和方法赋值

Js代码   收藏代码
  1. function Parent(firstname)  
  2. {  
  3.     this.fname=firstname;  
  4.     this.age=40;  
  5.     this.sayAge=function()  
  6.     {  
  7.         console.log(this.age);  
  8.     }  
  9. }  
  10. function Child(firstname)  
  11. {  
  12.     this.parent=Parent;  
  13.     this.parent(firstname);  
  14.     delete this.parent;  
  15.     this.saySomeThing=function()  
  16.     {  
  17.         console.log(this.fname);  
  18.         this.sayAge();  
  19.     }  
  20. }  
  21. var mychild=new  Child("李");  
  22. mychild.saySomeThing();  

 

2.采用call方法改变函数上下文实现继承(该种方式不能继承原型链,若想继承原型链,则采用5混合模式)
实现原理:改变函数内部的函数上下文this,使它指向传入函数的具体对象

Js代码   收藏代码
  1. function Parent(firstname)  
  2. {  
  3.     this.fname=firstname;  
  4.     this.age=40;  
  5.     this.sayAge=function()  
  6.     {  
  7.         console.log(this.age);  
  8.     }  
  9. }  
  10. function Child(firstname)  
  11. {  
  12.   
  13.     this.saySomeThing=function()  
  14.     {  
  15.         console.log(this.fname);  
  16.         this.sayAge();  
  17.     }  
  18.    this.getName=function()  
  19.    {  
  20.        return firstname;  
  21.    }  
  22.   
  23. }  
  24. var child=new Child("张");  
  25. Parent.call(child,child.getName());  
  26. child.saySomeThing();  

 

3.采用Apply方法改变函数上下文实现继承(该种方式不能继承原型链,若想继承原型链,则采用5混合模式)
实现原理:改变函数内部的函数上下文this,使它指向传入函数的具体对象

Js代码   收藏代码
  1. function Parent(firstname)  
  2. {  
  3.     this.fname=firstname;  
  4.     this.age=40;  
  5.     this.sayAge=function()  
  6.     {  
  7.         console.log(this.age);  
  8.     }  
  9. }  
  10. function Child(firstname)  
  11. {  
  12.   
  13.     this.saySomeThing=function()  
  14.     {  
  15.         console.log(this.fname);  
  16.         this.sayAge();  
  17.     }  
  18.     this.getName=function()  
  19.     {  
  20.         return firstname;  
  21.     }  
  22.   
  23. }  
  24. var child=new Child("张");  
  25. Parent.apply(child,[child.getName()]);  
  26. child.saySomeThing();  

 

4.采用原型链的方式实现继承
实现原理:使子类原型对象指向父类的实例以实现继承,即重写类的原型,弊端是不能直接实现多继承

Js代码   收藏代码
  1. function Parent()  
  2. {  
  3.   
  4.     this.sayAge=function()  
  5.     {  
  6.         console.log(this.age);  
  7.     }  
  8. }  
  9. function Child(firstname)  
  10. {  
  11.     this.fname=firstname;  
  12.     this.age=40;  
  13.     this.saySomeThing=function()  
  14.     {  
  15.         console.log(this.fname);  
  16.         this.sayAge();  
  17.     }  
  18. }  
  19.   
  20. Child.prototype=new  Parent();  
  21. var child=new Child("张");  
  22. child.saySomeThing();  

 

5.采用混合模式实现继承

Js代码   收藏代码
  1. function Parent()  
  2. {  
  3.   
  4.     this.sayAge=function()  
  5.     {  
  6.         console.log(this.age);  
  7.     }  
  8. }  
  9.   
  10. Parent.prototype.sayParent=function()  
  11. {  
  12.    alert("this is parentmethod!!!");  
  13. }  
  14.   
  15. function Child(firstname)  
  16. {  
  17.     Parent.call(this);  
  18.     this.fname=firstname;  
  19.     this.age=40;  
  20.     this.saySomeThing=function()  
  21.     {  
  22.         console.log(this.fname);  
  23.         this.sayAge();  
  24.     }  
  25. }  
  26.   
  27. Child.prototype=new  Parent();  
  28. var child=new Child("张");  
  29. child.saySomeThing();  
  30. child.sayParent();  

 

 

 

这些天读了John Resig的《Secrets of JavaScript Ninja》,其中讨论到JS中实现继承的方案,很是有趣,本身探索了一下,造成了笔记,放到这里。

这个方案在Resig的博客上也有,虽然代码略微有点不一致,但核心思想是同样的

<html>
<head>
    <title></title>
</head>
<body>
<script type="text/javascript">
    // call a immediate funciton,prevent global namespace from being polluted.
    (function(){
        // 这个initializing变量用于标识当前是否处于类的初始建立阶段,下面会继续详述
        var initializing = false,
        // 这是一个技巧性的写法,用于检测当前环境下函数是否可以序列化
        // 附一篇讨论函数序列化的文章:http://www.cnblogs.com/ziyunfei/archive/2012/12/04/2799603.html
        // superPattern引用一个正则对象,该对象用于验证被验证函数中是否有使用_super方法
            superPattern = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;

        Object.subClass = function(properties){
            // 当前对象(父类)的原型对象
            var _super = this.prototype;

            // initializing = true表示当前处于类的初始建立阶段。
            // this构造函数里会判断initializing的状态,若是为false则不执行Init方法。
            // 事实上这也是很是须要的,由于在这个时候,咱们须要的只是一个干净的虚构的构造函数,彻底不须要其执行init函数,以免污染。init方法只有在当前类被实例化的时候才须要被执行,而当前正执行继承行为,不该该执行Init方法。
            initializing = true;
            // 当前对象(父类)的一个实例对象
            var proto = new this();
            // 初始建立阶段完成,置initializing为false
            initializing = false;

            // 在properties里提供的属性,做为当前对象(父类)实例的公共属性,供其子类实例共享;
            // 在properties里提供的方法,做为当前对象(父类)实例的公共方法,供其子类实例共享。
            for(var name in properties){
                proto[name] = typeof properties[name] == 'function' && //检测当前提供的是否为函数
                              typeof _super[name] == 'function' && //检测当前提供的函数名是否已经存在于父类的原型对象中,若是是,则须要下面的操做,以保证父类中的方法不会被覆盖且能够以某种方式被调用,若是否,则直接将该函数赋值为父类实例的方法
                              superPattern.test(properties[name]) ? f//检测当前提供的函数内是否使用了_super方法,若是有使用_super方法,则须要下面的操做,以保证父类中的方法不会被覆盖且能够以某种方式被调用,若是没有用到_super方法,则直接将该函数赋值为父类实例的方法,即便父类原型中已经拥有同名方法(覆盖)

                    // 使用一个立刻执行的函数,返回一个闭包,这样每一个闭包引用的都是各自的name和fn。
                    (function(name, fn){
                        return function() {
                            // 首先将执行方法的当前对象(子类的实例化对象)的_super属性保存到tmp变量里。
                            // 这是很是必要的, 由于this永远指向当前正在被调用的对象。
                            // 当C继承B,B继承A,而A\B\C均有一个dance方法且B\C的dance方法均使用了this._super来引用各自父类的方法时,下面这句操做就显得很是重要了。它使得在方法调用时,this._super永远指向“当前类”的父类的原型中的同名方法,从而避免this._super被随便改写。
                            var tmp = this._super;
                            
                            // 而后将父类的原型中的同名方法赋值给this._super,以便子类的实例化对象能够在其执行name方法时经过this._super使用对应的父类原型中已经存在的方法
                            this._super = _super[name];

                            // 执行建立子类时提供的函数,并经过arguments传入参数
                            var ret = fn.apply(this, arguments);
                            
                            // 将tmp里保存的_super属性从新赋值回this._super中
                            this._super = tmp;

                            // 返回函数的执行结果
                            return ret;
                        };
                    })(name, properties[name]) : 
                    properties[name];
            }

            // 内部定义个名叫Class的类,构造函数内部只有一个操做:执行当前对象中可能存在的init方法
            // 这样作的缘由:新建一个类(闭包),能够防止不少干扰(详细可对比JS高级设计第三版)
            function Class(){
                // 若是不是正在实现继承,而且当前类的init方法存在,则执行init方法
                // 每当subClass方法执行完毕后,都会返回这个Class构造函数,当用户使用new 方法时,就会执行这里面的操做
                // 本质:每次调用subClass都新建一个类(闭包)
                if(!initializing && this.init){
                    // 这是子类的初始化方法,里面能够定义子类的私有属性,公共属性请在上方所述处添加
                    this.init.apply(this, arguments);
                }
            }

            // 重写Class构造函数的prototype,使其再也不指向了Class原生的原型对象,而是指向了proto,即当前对象(类)的一个实例
            // 本质:一个类的原型是另外一个类的实例(继承)
            Class.prototype = proto;
            // 为何要重写Class的构造函数?由于这个Class函数,它原来的constructor指向的是Function对象,这里修正它的指向,使其指向本身。
            Class.constructor = Class;
            // 就是这个操做,使得每次调用subClass都会新生命的Class对象,也拥有subClass方法,能够继续被继承下去
            // 本质:使得每次继承的子类都拥有被继承的能力
            Class.subClass = arguments.callee;
            // 返回这个内部新定义的构造函数(闭包)
            return Class;
        };
    })();


    var Person = Object.subClass({
        init: function(isDancing) {
            this.dancing = isDancing;
        },
        dance: function(){
            console.log('i am a person,i dance.');
            return this.dancing;
        }
    });

    var Ninja = Person.subClass({
        init:function(){

        },
        dance: function() {
            console.log('i am an Ninja,i dance.');
            this._super();
            return;
        },
        swingSword:function(){
            return true;
        }
    });

    var Chileung = Ninja.subClass({
        dance: function(){
            console.log('i am Chileung.i dance.');
            this._super();
            return;
        }
    });

    var p = new Person();
    p.dance();

    var n = new Ninja();
    n.dance();

    var c = new Chileung();
    c.dance();
</script>
</body>
</html>十6、前端优化、前端安全
相关文章
相关标签/搜索