javascript 事件模拟

7月 28th, 2010

很简单,做个记录,通过昨天史努比给的线索。找到了jquery的事件模拟触发代码。

http://code.google.com/p/jqueryjs/source/browse/trunk/plugins/simulate/jquery.simulate.js?r=6063

关键字2个:

dispatchEvent,fireEvent.

上述地址中的代码可见第104行-111行的dispatchEvent function。

Attributes.length

7月 28th, 2010

思考一下如果我想获得下面这个容器的attributes属性长度如何办到?

<div style=”display:none” data=”test1″ data2=”test2″ id=”test”>test</div>

恩,我们可以用get方法直接取,但是如果我不知道data,data2甚至不知道他又style,我们怎么办呢?

一般思路都是会去遍历这个节点了。

document.getElementById(”test”).attributes["data"];

恩。这样也可以取到你想要的。可是如果真的放入循环里,IE下的话你可真的就虾米了。我们来查看下Attributes.length这个属性在IF下和FF下到底有什么区别。

FF:Attributes。length:4; OK是我们想要的4个节点属性style,data,data2,id

IE:Attributes.length:110;NB啊。。。居然多达100多个。

好吧,通过遍历我得知那多出来的100多个属性都是什么onclick啊,onmouseover等等等等的默认属性,IE把他们也都算进去了。我靠,那怎么办。我们该如何获取兼容浏览器的,一个未知节点属性的元素,都存在什么自定义节点属性呢?

后来在javascriptkit里找到了答案:

http://www.javascriptkit.com/dhtmltutors/domattribute2.shtml

看下面代码:
var totalattributes=0

for (i=0;i<document.getElementById(”test”).attributes.length;i++){

//if attribute is user defined

if (document.getElementById(”test”).attributes[i].specified)

totalattributes++

}
一目了然了。

Element in IE

7月 28th, 2010

看过之前写的那篇BLOG,应该都发现了一句挺有意思的话。对于DOM中的element我可以添加自定义事件。比如:

Element.prototype.show=function(){this.style.display=’block’;}

喔~然后调用之

var test=document.getElementById(’test’);

test.show();

恩,虽然在最后的最后我知道了这么写是严重的污染原型链的一种及其牛逼的反面例子。但是确实我今天要说的不是这个问题。

经过测试所有的浏览器除了IE6/7(没有测试什么360,遨游,TT什么的杯具浏览器……)其他的浏览器都对外开放Element对象,允许你对齐prototype的原型链上添加或者重写方法。

但是当你遇到了IE,那么你就也遇到了 “Element is undefine”….这个错误了。

查了好久,具体的解决办法有2个,一个是在微软官方查到的用HTC的方法对Element进行扩展自定义方法,还有一种老外的方法,那么就是重写DOM方法。

显然,第2种方法在一些社区被受到推崇,号称可以解决99%的问题。而不用恶心人的HTC,而且不需要2个文件加载那么复杂。

那么到底是如何解决的呢?

首先:Element is undefine,那么我们建立一个Element就好了。

var Element=function(){};

恩 一个构造函数容器就建立了,他自身已经拥有了prototype属性了。因为是function嘛。

然后你每次给Element扩展方法的时候其实在IE6/7下都是给这个你自己定义的Element扩展的方法。那么我们如何调用这些扩展方法呢。

回想一下我们什么场合会用到事件。喔,getElementById,getElementsByTagName,createElement也就是这三种情况了。还有什么呢?原生的JS里只有这3种方法了吧?不对 只是99%,你可以.all也可以from[0]等等其他的方法获得元素,但是最基本其实就是这3个方法了。

那么我们要重写这3个DOM方法,在每次调用的时候都继承我们自己创建的Element对象下面的自定义方法。

如何去做呢?下面是完整的代码:

(function(w, undefined){
var Element=w.Element || function(){
return {
author:’longxiao’
};
};

if (!!Element().author) {
var __createElement = document.createElement;
document.createElement = function(tagName){
var element = __createElement(tagName);
for (var key in Element.prototype)
element[key] = Element.prototype[key];
return element;
}

var __getElementById = document.getElementById;
document.getElementById = function(id){
var element = __getElementById(id);
for (var key in Element.prototype)
element[key] = Element.prototype[key];
return element;
}

var __getElementsByTagName = document.getElementsByTagName;
document.getElementsByTagName = function(tagName){
var elements = __getElementsByTagName(tagName);
for (var key in Element.prototype){
for(var i=0;i<elements.length;i++){
elements[i][key]=Element.prototype[key];
}
}
return elements;
}
};

Element.prototype.getattrlength=function(){
alert(this.attributes.length)
};

document.getElementById(’page’).getattrlength();

})(window);

更多关于原型链的问题在我自己研究明白了之后再来分享……

用【观察者模式】实现自定义事件

7月 22nd, 2010

根据昨天写的那篇文章,今天写了个例子来配合说明。没有列举超人起飞的例子,那个例子是给自定义的superman对象,添加了3个自定义事件,而我下面的例子是给大家最熟悉也最关心的Element对象添加自定义事件。

代码如下(需要引入publisher):

var fuck=function(e){
this.e=e || ”;
alert(this.e+’ fuck off’);
}

Element.prototype.onfuck=new publisher;

fuck.subscriber(Element.prototype.onfuck);

var page=document.getElementById(’page’);

page.onfuck.deliver(); //alert(fuck off);

page.onfuck.deliver(1); //alert(1fuck off);

/* 你可以给你喜欢的事情随便添加自定义事件,在需要的时候就deliver触发。 */

page.onclick=function(){
this.onfuck.deliver(’ye~click my ‘+this.id+’ and’); //alert(ye~click my page and fuck off);
}

最后,关于自定义事件的触发条件,必须在这里说明,他的触发,比如click,比如mouseover等动作的实现
是需要自己来编写的,你可以借助click等动作触发,也可以自己模拟,比如重复轮询等,触发用deliver,触发条件必须自己实现。

所以最后的最后,自定义事件或者观察着模式的应用和作用,总结起来就是更彻底的包装了一些代码,实现js的高度解耦,让功能去做功能要做的事,分离开功能和被事件所绑定的对象,可能是Element对象,也可能是自己所创建的对象,任何对象。

希望我不要误导到一些人吧,更多关于自定义事件的文章google一下,仔细阅读,很多种实现方法,关键看适用场合适用场景了。这只是一种设计思想,而不是什么万能药,在需要实现很复杂的业务逻辑的时候用来解耦的一种很好方法。

javascript设计模式【观察者模式】

7月 22nd, 2010

首先说下标题,可能有点唬人,所以简单的解释一下,我是为了帮助自己理解才写的这篇文章。

个人认为观察者模式类似事件监听器,给任何一个你感兴趣的地方增加一个订阅点,然后在需要的时候触发它。

还是有点迷糊,看代码吧。

我们创建一个观察者类:

function publisher(){
this.subscribers=[];
}

这个构造器里有一个subscribers数组,用来保存订阅者列表。

增加投递方法:

publisher.prototype.deliver=function(data){
this.subscribers.forEach(function(fn){fn(data);})
return this;
}

里面用到了forEach这个js1.6的数组方法,array.forEach(fn)->参数是个函数,这个函数的参数会把这个数组的每个值都带入这个函数中当参数执行一次。

下面是增加订阅方法:

Function.prototype.subscriber=function(publisher){
var that=this;
var alreadyExists=publisher.subcribers.some(function(el){return el===that;});
if(!alreadyExists) publisher.subscribers.push(this);
return this;
}

解释一下,这里的some也是js1.6里的一个数组方法,以一个回调函数为参数,这个方法会依次访问数组每个元素,然后并把这个元素当作参数返回给这个回调函数,如果至少有一次回调函数的返回值是true,(其实就是如果有一个回调函数返回了true)则some返回true;否则返回false。

退订方法就不写了,其实就是在subscribers数组中检测,如果含有退订函数,则清空它。

OK。

现在理清一下思路。publisher和我们都做了什么。

publisher类,内部有一个数组,储存订阅清单。

外部方法deliver(data),作为增加订阅者也就是投递订阅的接口,参数data为回调参数。

然后给function原型增加了一个subscriber方法,用途是给这个function添加到publisher.subscribers这个数组下。

OK。到这里估计就真相大白了。

我们其实就是给每个函数增加了一个往一个全局数组中push的方法,然后需要触发这个函数的时候,就循环这个数组,遇到注册过的这个函数,就立刻触发。

设计模式书上的例子是给一个superman创建一个起飞的订阅,一个飞行中的订阅,一个降落的订阅。其实我们可以给任何东西增加订阅,也就是监听,监听我们感兴趣的时刻,然后触发回调函数即可。

本来还想写写自定义事件,但是确实想不出容易的例子来,以后再说吧,但是道理其实都是一样的。

Throttling function calls【译文】

7月 21st, 2010

在twitter上看到一篇比较好的推荐文章,至少我感觉又学到了东西,特别拿出来翻译和分享一下。

原文地址:http://javascript.feederss.com/post/2442.html

如果你做过用户文本框提交确认的功能,比如用到了onkeypress,那么你是否想过要减少你的检测函数的执行次数?举个最简单的例子,比如你要确认一个用户名是否存在,那么你可能并不想每次keypress都执行ajax异步检测,因为大多数的时候输入一个单词需要10分之一秒或者更久,那么你就需要控制你的ajax请求的间隔,而不是每次press之后都立刻去进行ajax请求,至少要在那10份之一秒钟让你的文本框处于休眠状态。

所以就会产生这么一个神奇的类似closure的一种javascript方案,下面是创建这个方法的一个简单的例子:

function throttle(fn, delay) {
  var timer = null;
  return function () {
    var context = this, args = arguments;
    clearTimeout(timer);
    timer = setTimeout(function () {
      fn.apply(context, args);
    }, delay);
  };
}

如果你是在用jquery来工作的话,如果你要写一个keypress的检测,你可以像下面这样使用:

$('input.username').keypress(throttle(function (event) {
  // do the Ajax request
}, 250));

这里的关键词是this和那个args,this其实就是你预期的那个input,而args是传入的event对象,通过这个方法你就可以准确的控制你的ajax请求是press一次的之后250毫秒过后再次触发了。

大概就是这么一篇文章,但是我承认以前确实没有注意到过,关于那个throttle函数,我在firebug里检测了下,里面最不明白的其实就是那个this和args。通过断点我检测出来了,虽然他文章最后也告诉了。

恩,最后如果你不用jquery的话,原始的js如何使用这个函数呢?

document.getElementById(’page’).onclick=throttle(function(e){
alert(e);
alert(’3000 later’);
},3000)

恩。。。就是这么简单……^_^

对了 这个文章的作者挺NB的,我也推荐订阅他的tw和rss……

一个自增自减的输入框例子

7月 20th, 2010

头几天被一个人要求写个表单可以自己加减输入框的例子。

简单用纯的js实现了,其实,用jquery的话几行就搞定了,代码如下:

http://pastebin.com/iarf8GSs

没什么好说的了。。。在努力狂读设计模式ing…

一个通用的JS弹出浮动层。

7月 20th, 2010

截图:

代码比较简单,有部分基于YUI。其实就是其中的DOM里的一个get方法,一个getViewportHeight/Width方法,还有一个 getDocumentScrollTop方法,应该所有框架都有的,我就没有自己写了。

代码实现部分如下链接,注释应该也很清楚,比较好理解,做个记录,以后用到就都使它了。。

http://pastebin.com/2gYMiAmG

入职

7月 5th, 2010

今天参加了入职培训,正式加入了淘宝这个大团队,在淘宝的开放办公区拿到了电脑,得知了花名,认识了师兄和师傅还有新的杭州的同事,还在培训签合同时认识了2个川大的做java开发和算法的同学,一切都在往着好的方向发展啊,明天开始要学习一些流程方面和团队方面的细节事情了,不知道会不会很难,不知道了,加油就好了。

好些日子不写代码了,手痒,唔,come on……我来了,我在杭州一切都好。

:)

谢谢你们。拜拜,北京。

7月 1st, 2010

9个月的京旅在今天就和小爝说结束了,而下一个要去的城市-杭州,对于我来说,它既熟悉又陌生。

我知道我不能如标题一样潇洒的离开,虽然北京这段时日只是我人生中短暂的停留,但这记忆恐怕却非常难忘。

很多事情转瞬又漫长,一切都像是昨天刚刚发生。

谢谢博文同学半年多的照顾,也祝福他以后在译言的工作越来越好,哥们,你行的……:)。

谢谢兔子同学在单位一直对我的默默无闻的照顾…才能让我安心的进入这行,得到成长与进步。兔哥一直担负着我以前公司的交互和设计重任,以后一定要照顾好自己和强哥哈…:)。

也谢谢那个一直陪我度过4个多月幸福时光的小狮子,虽然最后……总之,以后的路……加油,平安。:)

还有在北京这段时间认识的白羊伟男同学,天蝎胡罗同学,豆瓣js小组的金牛迈克同学和史努比同学,蛋哥等等……谢谢你们对我的帮助和鼓励。

感谢在北京的这段时间里我曾拥有你们。拜拜了,北京,但我们依然在路上。


Dtools Top
本页文章快速定位...