只支持safari和chrome
转自:http://www.webkit.org/blog-files/3d-transforms/morphing-cubes.html
只支持safari和chrome
转自:http://www.webkit.org/blog-files/3d-transforms/morphing-cubes.html
早在两年前,互联网中的网页数量就已超过了1万亿,并且,每天还会增加数十亿。虽然是如此浩瀚的世界,我们却可以通过url轻而易举的找到每一个页面,可见url对于网络世界时多么的重要。
随着浏览器的进步和对用户体验要求的提升,整站ajax之类的一站式前端应用正在逐步取代传统的一个url对一个页面的展示方式。在整站ajax中,数个模块在一个url下,采用无刷新的方式切换,通过减少页面刷新有效的提升了用户体验,但也带来了一些问题:
1. 某些用户习惯根据url判断自己所在的位置,如果明明点击了链接,页面变化了,url却没有变化,用户会比较晕
2. 用户保存书签后,在打开这个书签,得到的可能并不是自己想要的内容
3. 模块间切换后,不能使用浏览器的回退键退回去
针对上述问题,比较简单的方式是使用锚点做标记:每个模块切换时,锚点都会有所变化,比如:/index#list,/index#edit,这样,可以有效的解决上面提到的第1个问题;对第2个问题,前端代码初始化时根据当前页面的hash做些处理也就行了;第3个问题稍微麻烦一些,需要监控页面url的变化。
浏览器不可以给地址栏添加监听时间,只能通过定时读取location.hash/href来判断锚点是否发生了变化。定时长度不能太长,否则影响用户体验,也不能太频,会耗太多资源。这种定时的方式虽然很土,但出了“坚挺”浏览器是否回退、前进以外,却还可以减少很多绑定链接click的操作:只需要给按钮链接的href加上锚点,将参数写在锚点里,用户点击这个url时,锚点变化被定时程序“监听”到,就可以执行相应的逻辑(还顺道解决了按钮重复点击的问题,一举多得呀 )。关于如何把button按钮转变为锚点链接的点击可以参考本人以前的博文:js触发链接。
不过使用定时方式“监听”浏览器回退,还有一个无法解决的缺陷(只是本人还未发现解决方法),IE6/7的锚点跳转记录不会进入history对象,也就是在IE6/7里,有A页面进入B页面后,B页面内由/B跳到/B#1,再跳到/B#2,再“回退”,也还是会回到A页面,无法回到中间的/B跳和/B#1…….IE而已,可以暂时不去理它。
前面说,使用方式监听地址栏变化有些土,那么,有跟好的办法吗?
之前转发的一篇博文(使用ajax和history.pushState无刷新改变页面URL)里提到了html5的一个新特性:可以注册“popstate”事件监听url的变化,我们可把前面的定时“监听”稍作改进,如果浏览器支持popstate,就使用popstate,如果不支持,在使用定时。本人测试表明,firefox、chrome、safari支持popstate事件,IE系、以及opera不支持。
———-End
前两篇介绍了javascript面向对象的基本知识和继承的实现,本篇主要介绍this关键字的使用
———–
5. 关于this
this在javascript里是一个比较神奇的东西,新手通常会被它搞到头大
1). 顶层javaScript代码中的this
在顶层javaScript代码中,this指代window对象
在嵌入浏览器中的javascript中,window即全局对象。全局对象只是一个对象,而不是类。既没有构造函数,也无法实例化一个新的全局对象。在顶层javaScript代码中,可以用关键字this引用全局对象。但通常不必用这种方式引用全局对象,因为全局对象是作用域链的头,这意味着所有非限定性的变量和函数名都会作为该对象的属性来查询。
下面几段代码中的this指代的均是window
ex1. var abc = 'sss'; alert(abc);//"sss" alert(this.abc);//"sss" function fun1(){ alert(this.abc); } fun1();//"sss" this.alert(123); alert(this.parseInt('234s4')); |
2). 构造方法/类方法里的this
大部分时候,构造方法/类方法里直接使用this,指代的都是被实例化后的类对象,但是,如果其中有function/setTimeout,或者其他回调函数时,情况就有些不同了,如果想让this仍然指代你你所需要指代的对象,可以使用call/apply方法:
ex2. var O1 = function(){ function O(){ this.abc = 123; function f2(){ alert(this.abc); } f2();//直接调用f2方法,this指代window f2.call(this);//通过call调用f2方法,this指代O1 } function pf(){ alert(this.abc); } O.prototype = { f1 : function(){ pf();//直接调用pf方法,this指代window pf.call(this);//通过call调用pf方法,this指代O1 } }; return O; }(); var o = new O1(); o.f1(); |
3). Events的this
这个相对比较简单,在给一个DOM节点注册一个事件处理函数时,函数内的this指代的这个DOM节点:
ex3. document.getElementById('xxxx').onclick = function(){ alert(this.id); }; //使用jquery注册事件时,结果是一样的 $('#xxxx').click(function(){ alert(this.id); $(this).xxx()...//以this创建jquery对象 }); |
4). 回调函数里的this
ex4: var abc = 'window'; //O1 var O1 = function(){ function O(){ this.abc = 'O1'; } O.prototype = { f1 : function(){ alert(this.abc); } }; return O; }(); //O2 var O2 = function(){ function O(){ this.abc = 'O2'; } O.prototype.callbackFun = function(fun){ fun(); } return O; }(); //实例化O1和O2 var o1 = new O1(); var o2 = new O2(); //猜猜看这里会alert什么.....window o2.callbackFun(o1.f1);//“window” //所以,在使用需要类环境的回调方法时,需要套一层function o2.callbackFun(function(){ o1.f1();//“O1” }); //当然,也可以通过call让this指向O2 o2.callbackFun(function(){ o1.f1.call(o2);//“O2” o1.f1.call(this);//“window” }); |
在访问现在很火的google plus时,细心的用户也许会发现页面之间的点击是通过ajax异步请求的,同时页面的URL发生了了改变。并且能够很好的支持浏览器的前进和后退。不禁让人想问,是什么有这么强大的功能呢?
HTML5里引用了新的API,就是history.pushState和history.replaceState,就是通过这个接口做到无刷新改变页面URL的。
与传统的AJAX的区别
传统的ajax有如下的问题:
虽然ajax可以无刷新改变页面内容,但无法改变页面URL
其次为了更好的可访问性,内容发生改变后,改变URL的hash。但是hash的方式不能很好的处理浏览器的前进、后退等问题
有的浏览器引入了onhashchange的接口,不支持的浏览器只能定时去判断hash是否改变
再有,ajax的使用对搜索引擎很不友好,往往蜘蛛爬到的区域是空的
为了解决传统ajax带来的问题,HTML5里引入了新的API,即:history.pushState, history.replaceState
可以通过pushState和replaceState接口操作浏览器历史,并且改变当前页面的URL。
pushState是将指定的URL添加到浏览器历史里,replaceState是将指定的URL替换当前的URL。
如何调用
var state = { title: title, url: options.url, otherkey: othervalue }; window.history.pushState(state, document.title, url); |
state对象除了要title和url之外,也可以添加其他的数据,比如:还想将一些发送ajax的配置给保存起来。
replaceState和pushState是相似的,不需要多做解释。
如何响应浏览器的前进、后退操作
window对象上提供了onpopstate事件,上面传递的state对象会成为event的子对象,这样就可以拿到存储的title和URL了。
window.addEventListener('popstate', function(e){ if (history.state){ var state = e.state; //do something(state.url, state.title); } }, false); |
这样就可以结合ajax和pushState完美的进行无刷新浏览了。
一些限制
1、无法跨域,这个是必然的。引用曾经在网上看到的一句经典的话:“如果javascript可以跨域的话,那他就可以逆天了!”
2、state对象虽然可以存储很多自定义的属性,但值不能是个对象。
对应后端的一些处理
这种模式下除了当前使用ajax可以无刷新浏览外,还要保证直接请求改变的URL后也可以正常浏览,所以后端要对这些处理下。
1、对结合pushState的ajax可以发送一个特殊的头,如: setRequestHeader(‘PJAX’, ‘true’)。
2、后端获取到有PJAX=true的header时,将页面中通用的部分都不输出。比如:PHP可以通过下面的判断
function is_pjax(){ return array_key_exists('HTTP_X_PJAX', $_SERVER) && $_SERVER['HTTP_X_PJAX'] === 'true'; } |
虽然接口上只有pushState、replaceState、onpopstate,但在使用的时候还是要做很多处理的。
————–
转自:http://www.52ladybug.com/?p=202
接上篇,本次主要将javascript的继承
—————
4. 继承
javascript本身没有类的机制,更不会有子类/父类的概念,但javascript是一个极自由的语言,既然可以用funciton模拟类的实现,肯定也可以通过某种方式来模拟继承
1) . call()
call方法(以及apple方法)用来调用对象O1的一个方法,以另一个对象 O2替换当前对象 O1,而对象的构造函数既然也是“方法”,那么,我们就可以利用它来用子类 O2调用父类 O1的构造方法,使 O2具有在 O1构造方式里为 O1添加的属性、方法,这样,O2就具有的O1的方法和属性:
ex1. //O1 父类 function O1(){ this.a1 = 123; } //O2 子类 function O2(){ O1.call(this); } var o = new O2(); alert(o.a1);//123 |
上面例子中的”O1.call(this)”,作用是:用O2里的this替代O1里的this,执行一遍O1(),这样,O2就有了属性a1
这种方法可以是O2继承O1构造函数类通过this.xx定义的属性/方法,但是不能继承O1 prototype添加属性/方法
2) prototype
什么是继承?
继承既是让子类拥有父类的属性和方法,回头再看一下prototype在function模拟Class时的作用:
“function在做为类定义的时候,创建类实例的过程(new的过程)要参照它的prototype对象,把prototype对象的所有属性/方法”
那么,我们可以这样在继承prototype
ex2. //O1 function O1(){ this.a1 = 123; } O1.prototype = { f1 : function(){ alert(this.a1); }, constructor : O1 }; //O2 function O2(){ //… } //将O1的所有属性和方法赋到O2.prototype O2.prototype = new O1(); O2.prototype.f2 = function(){...}; O2.prototype.constructor = O2; var o = new O2(); alert(o.a1);//123 |
这种方式基本可以实现继承的功能,但是,如大家所看到的,O1和O2的构造函数都不能有参数,在改进一下:
综合ex1.和ex2.,我们可以得到比较实用的继承方式,ex3:
ex3: //O1 function O1(a){ this.a1 = a; } O1.prototype = { f1 : function(){ alert(this.a1); }, constructor : O1 }; //O2 function O2(a){ O1.call(this); } //将O1的所有属性和方法赋到O2.prototype O2.prototype = new O1(); O2.prototype.f2 = function(){...}; O2.prototype.constructor = O2; |
但是如前面所说,这种书写方式会使代码有些散,另外,在执行O2.prototype = new O1() 时,仍然会无参的执行一遍O1的构造函数,如果O1()有参数,且参数是必须的,就会可能会出现一些错误
3).原型式继承和寄生组合式继承
ex4: //原型式继承 //将对象o的塑像和方法交给类F的prototype,然后返回实例化F,使返回对象具有o的属性和方法 function object_(o){ function F(){} F.prototype = o; return new F(); } //寄生式继承 //利用原型式继承的object_方法,将给定对象的属性和方法交给clone,然后为clone添加方法f1 function createAnother(original){ var clone = object_(original); //在通过原型继承以后,在给clone添加方法,这种方式导致代码复用率很低 clone.f1() = function(){…}; return clone; } //寄生组合式继承 使用寄生式继承父类的prototype对象到子类的prototype function inheritPrototype(superType, subType){ var prototype = object_(superType.prototype); prototype.construction = subType; subType.prototype = prototype; } //寄生组合式继承仍然只继承prototype,如果要实现完整的继承,仍然需要结合call方法 //下面是寄生组合式继承的示例 //O1 function O1(a){ this.a1 = a; } O1.prototype = { f1 : function(){ alert(this.a1); }, constructor : O1 }; //O2 function O2(a){ O1.call(this); } //将O2的所有属性和方法赋到O2.prototype inheritPrototype(O1, O2); O2.prototype.f2 = function(){...};//为子类添加额外的属性/方法 |
前面ex3.提到的继承方式和寄生组合继承都是javascript比较实用的继承方法,前者虽然有缺陷切效率比较低,但因原理比较好理解,所以使用相当普遍。YUI的YAHOO.lang.extend()使用了寄生组合继承,从而让寄生组合继承首次出现在了一个被广泛使用的javascript类库中。