jQuery 1.4, MooTools 1.2 比较

2010年1月14日,我在Nettuts网站上看到了《 jQuery 1.4 Released: The 15 New Features you Must Know
》的文章,16号的时候就有中文版的译文了,《[译]jQuery 1.4 发布:15个新特性实例精讲 》,我也感受了一下 jQuery 1.4给我们带来的变化。有意思的是我所看到的jQuery1.4的新特性,在MooTools1.2+的版本里早有实现。

我在这里不想jQuery VS MooTools ,也不想为谁公正。 很显然我比较喜欢MooTools ,因为它更适合我和我的工作,我也不想重复学习一些东西。我所看到的对jQuery的偏见,其实是大家有目共睹的,jQuery也是明显的(就是jQuery也采用了MooTools的一些特性等等的做法)。然而,当你阅读到这儿的时候我也不是试图去说服你转入到MooTools下当门徒,说jQuery是劣等的,从而抛弃jQuery 。就好像你选择浏览器是IE,操作系统是Windows,汽车是福特,喝的百事可乐。小平爷爷说的好“不管黑猫白猫,抓住老鼠就是好猫”。我只是在这里分享我用MooTools开发的一些想法(其实我有好几个项目就是采用的jQuery开发的)。

无论如何,为了方便自己,我使用jsfiddlemooshell 工具 – 在线可以帮助您编写 html, css 和 javascript,并且可以测试实例。我选择的jsfiddle在线工具来偷懒代码片段的,可以节省一些时间,快速测试,也方便我们快速了解jQuery1.4中令人敬畏的新特性,以及MooTools中更多令人敬畏的东西。

原文来自:jQuery 1.4, MooTools 1.2 Compared

作者与博客:Ryan Florence Blog 

Enjoy!

1. Passing Attributes During Element Construction / 传参给 jQuery(…)

jQuery 1.4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
jQuery('<div/>', {  
 
    id: 'foo',  
 
    css: {  
 
        fontWeight: 700,  
 
        color: 'green'  
 
    },  
 
    click: function(){  
 
        alert('Foo has been clicked!');  
 
    } 
 
});

MooTools (all versions)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
new Element('div',{ 
 
  id: 'foo', 
 
  styles: { 
 
    'font-weight': 700, 
 
    color: 'green' 
 
  }, 
 
  events: { 
 
    'click': function(){ 
 
      alert('Foo has been clicked!'); 
 
    } 
 
  } 
 
});

jQuery is looking a lot more moo-ish here by passing an object in rather than chaining everything.

jQuery Shell

MooTools Shell

2. Everything Until! / 直到遇见你…

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<ul id="fruit">  
 
  <li>Apple</li>  
 
  <li>Banana</li>  
 
  <li>Grape</li>  
  <li>Strawberry</li>  
 
  <li>Pear</li>  
 
  <li>Peach</li>  
 
</ul>

jQuery 1.4

1
2
3
jQuery('ul#fruit li:contains(Apple)').nextUntil(':contains(Pear)');
 
// Selects Banana, Grape, Strawberry

MooTools 1.2 + Element.GetUntil Plugin

1
2
3
4
5
$$('ul li:contains(Apple)')[0].getAllNextUntil(':contains(Pear)); 
 
// more mooish 
 
$('fruit').getElement('li:contains(Apple)').getAllNextUntil(':contains(Pear));

I thought these new until methods were interesting so I extended MooTools with similar functionality. See my post about Element.GetUntil.

jQuery

MooTools

3. Binding Multiple Events / 绑定多个事件处理器

jQuery 1.4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
jQuery('#foo').bind({  
 
    click: function() {  
 
        // do something   
 
    },  
 
    mouseover: function() {  
 
        // do something   
 
    },  
 
    mouseout: function() {  
 
        // do something   
 
    }  
 
});

MooTools (all versions)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$('foo').addEvents({ 
 
  click: function(){ 
 
    // do something 
 
  }, 
 
  mouseenter: function(){ 
 
    // do stuff a bit better than mouseover 
 
  }, 
 
  mouseleave: function(){ 
 
    // do stuff a bit better than mouseout 
 
  } 
 
});

jQuery 1.4 again is looking a lot more like mootools, very nice
because now you can store a handful of events in an object and toss
them around.

Note: “MooTools features mouseenter and mouseleave
because mouseover/mouseout sometimes just don’t not work as expected.
Mouseenter only fires once you enter the element and does not fire
again if your mouse crosses over children of the element.” moootools.net

jQuery

MooTools

4. Per Property Easing / 依属性指定缓动效果

jQuery 1.4

1
2
3
4
5
6
7
jQuery('#foo').animate({  
 
    left: 500,  
 
    top: [500, 'easeOutBounce']  
 
}, 2000);

MooTools 1.2 + Fx.Transmorph Plugin

Fx.Transmorph is the same thing, different syntax:

1
$('foo').transmorph({height: 100, width: 100}, {width: 'bounce:out'});

MooTools 1.2 + Fx.Flux Plugin

Fx.Flux is unique in that it allows you to define ANY of the
Fx.Morph instructions rather than just the transition. Yes, you can
change the duration, transition, unit, etc.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$('foo').flux({ 
 
    'top':[370, { 
 
        duration: 1500, 
 
        transition:'bounce:out' 
 
    }], 
 
    'left':[370, { 
 
        duration: 3000, 
 
        transition:'cubic:out' 
 
    }] 
 
});

Just Mootools

You’d have to set up multiple Tween / Morph instances. However, this
affords you control over every aspect of the tween (including events),
not just the easing.

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
var foo = $('foo'); 
 
var fooFx1 = new Fx.Tween(foo,{ 
 
  transition: 'elastic:out', 
 
  duration: 2000, 
 
  onStart: function(){ 
 
    // do something fun 
 
  } 
 
}); 
 
var fooFx2 = new Fx.Morph(foo,{ 
 
  transition: 'sine:in:out', 
 
  duration: 500, 
 
  onComplete: function(){ 
 
    // do something important 
 
  } 
 
}); 
 
fooFx1.start('left',500); 
 
fooFx2.start({'top':500, 'border':'10'});

So yeah, a lot of code. I think jQuery implemented something cool
here and I certainly hope to see a version of Fx.Flux in the mootools
forge. When we all start getting crazy with canvas and svg we’ll want
leaner syntax for animation than the mootools code block above this,
and more control than just the easing in jQuery. Oh, Fx.Flux, yes,
that’s what I’m thinking of.

jQuery

MooTools Fx.Flux

5. Live Events / 更新的 Live 事件!

That’s just another name for event delegation. I’ve got an entire post
on event delegation with mootools. Basic concept, instead of adding the
same events (or as jquery calls it, binding events) on multiple
elements, just add the event to a single parent element and delegate,
or relay the event to the children. Then any dynamically added elements
(inserted via ajax, or otherwise) will have the event.

jQuery 1.4

1
2
3
4
5
jQuery('ul#foo li').live('click', function(){  
 
    // do something with this   
 
});

MooTools 1.2 + Element.Delegates

1
$('foo').addEvent('click:relay(li)');

Some very big differences in the two approaches here.

  1. jQuery listens to the entire document for clicks. That feels a
    little, erm, less-awesome than it should be. That means every single
    click goes ahead and finds out if it was an li inside of foo that was clicked.

  2. MooTools only listens to the element you tell it to.

MooTools is also more clear about what’s going on. You are adding
the event to an element that will relay the event to it’s matched
children. The identical code in MooTools to the jquery example would be:

1
document.addEvent('click:relay(ul#foo > li)');

But don’t ever do that if you don’t have to. Srsly d00d. Don’t get
me wrong, event delegation is one of my favorite toys, so I’m very
excited it’s part of jQuery now, just a bit disappointed I have to
listen to the whole document, he’s going to be a busy man.

Note: Jquery kicks MooTools in the pants when it comes to delegating focusin and focusout. The current implementation of MooTools event delegation doesn’t support the focus and blur methods, but MooTools 2.0 will.

jQuery

MooTools

6. Controlling a Functions Context / 控制函数上下文

In other words, what will this be inside a function? Given this:

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
var app = {  
 
    config: {  
 
        clickMessage: 'Hi!'  
 
    },  
 
    clickHandler: function() {  
 
        alert(this.config.clickMessage);  
 
    }  
 
}; 
 
 
 
// jQuery 
 
jQuery('a').bind('click', app.clickHandler); // won't work, `this` is the clicked `a` 
 
 
// Mootools 
 
$$('a').addEvent('click', app.clickHandler); // same thing

When an anchor tag is clicked, we want to alert this.config.clickMessage, or ‘Hi!’. Here are the solutions:

jQuery 1.4

1
2
3
4
5
6
7
jQuery('a').bind( 
 
  'click', 
 
  jQuery.proxy(app, 'clickHandler') 
 
);

MooTools (all versions)

1
2
3
4
5
6
7
$$('a').addEvent( 
 
  'click', 
 
  app.clickHandler.bind(app) 
 
);

This should have been in jQuery a long time ago. I have a hard time
imagining writing a well structured javascript app without binding, or
proxy-ing (?) as shown in this example. I think the MooTools syntax is
easier as you don’t have to split up the object, just bind it. Things
get a little confusing too with jQuery when you’ve got nested methods
in an object:

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
42
43
44
45
46
47
var app = {  
 
    config: {  
 
        clickMessage: 'Hi!'  
 
    }, 
 
    clickHandler: function() {  
 
        alert(this.config.clickMessage);  
 
    }, 
 
    nested: { 
 
        keyupHandler: function() {  
 
            alert(this.config.clickMessage);  
 
        } 
 
    }  
 
}; 
 
 
 
jQuery('a').bind({ 
 
  'click': jQuery.proxy(app, 'clickHandler'), 
 
  'keyup': jQuery.proxy(app.nested.keyupHandler, app) // backwards? 
 
} 
 
 
 
// MooTools 
 
$$('a').addEvents({ 
 
  'click': app.clickHandler.bind(app) 
 
  'keyup': app.nested.keyupHandler.bind(app) // coherent 
 
});

Seems really strange to swap the arguments around to accommodate a
nested method. MooTools is much clearer here, just pass in the function
as you would normally, then bind whatever you want.

jQuery

MooTools

7. Delay an animation queue / 动画队列延迟

jQuery

1
2
3
4
5
6
7
8
9
10
11
12
$('#foo') 
 
  .animate({'width': 250}) 
 
  .delay(500) 
 
  .fadeOut() 
 
  .delay(1000) 
 
  .fadeIn();
<em></em>

MooTools 1.2 with Chain.Wait

1
2
3
4
5
6
7
8
9
10
11
$('foo') 
 
   .tween('width', 250) 
 
   .pauseFx(500) 
 
   .fade('out') 
 
   .pauseFx(1000) 
 
   .fade('in');

jQuery

MooTools

8. Check if an element has something / 检测元素是否含有特定内容

jQuery 1.4

1
jQuery('div').has('ul');

MooTools 1.2

1
$('div').hasChild('ul');

9. Unwrap an element / 给元素剥皮!

jQuery 1.4

1
jQuery('p').unwrap();

MooTools 1.2

Nuthin’ baked in, but if you find yourself needing to unwrap elements often you could extend Element to handle it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// include this with your other classes and javascript 
 
Element.implement({ 
 
    unwrap: function(){ 
 
        var parent = this.getParent(); 
 
        parent.getChildren().inject(parent,'before'); 
 
        parent.dispose(); 
 
        return this; 
 
    } 
 
}); 
 
 
 
// now you've got unwrap 
 
$('p').unwrap();

Edit: Thanks to Chee Aun in the comments, he pointed out that I missed text nodes in my solution. Indeed. Check out his gist for a better solution. You would instead target an element to remove rather than a child to oust it’s parent.

jQuery

MooTools

10. Remove elements without deleting data / 移除元素,而不删除数据

jQuery

1
2
3
4
5
6
7
8
9
foo.detach(); // Remove it from the DOM   
 
 
 
// ... do stuff   
 
 
 
foo.appendTo('body'); // Add it back to the DOM

MooTools (all versions)

1
2
3
4
5
6
7
foo.dispose(); // Remove from the DOM 
 
 
// ... do stuff 
 
 
foo.inject(document.body); // Add it back to the DOM

Again, this was one of those things that surprised me that jquery
didn’t have, especially since jQuery’s focus is the DOM. It’s
especially helpful when you’ve got some heavy duty dom manipulation
going on: pull everything out, manipulate, the browser doesn’t try to
redraw, inject it back into the DOM. Only redraws once.

11. Index enhancements / index(…) 的功能增强

jQuery 1.4

1
2
3
4
5
6
7
jQuery('li').click(function(){  
 
  alert( jQuery(this).index() ); 
 
  alert( jQuery(this).index('li.other') ); 
 
});

MooTools

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var els = $$('li'); 
 
els.addEvent('click',function(){ 
 
    alert(els.indexOf(this)); 
 
    alert($$('li.other').indexOf(this)); 
 
}); 
 
 
 
// more common 
 
$$('li').each(function(element, index){ 
 
  element.addEvent('click',function(){ 
 
    alert(index); 
 
  }); 
 
});

This is clearly more valuable to the jquery coding style. I’ve never used indexOf in mootools, I’m usually in an each loop.

jQuery

MooTools

12. DOM Manipulation accepts functions as arguments / DOM 操纵可接收回调函数

jQuery 1.4

1
2
3
4
5
jQuery('li').html(function(i){  
 
    return 'Index of this list item: ' + i;  
 
});

This is actually quite interesting, it’s geared a lot more toward
the coding style of jQuery than mootools, but after talking to Thomas
Aylott about it, we (read: he), came up with this …

MooTools 1.2 with Elements.setEach Plugin

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
$$('li').setEach('html',function(i){ 
 
  return 'Index of this list item: ' + i; 
 
}); 
 
 
 
// actually, there's a ton you can do with setEach 
 
 
 
function replaceFooWithBar(string){ 
 
    return String(string).replace(/\bfoo\b/g,'bar'); 
 
}; 
 
 
 
// just like jQuery 
 
$$('a').setEach('href', function(currentHref, i){ 
 
    return currentHref + '?foo=bar'; 
 
}); 
 
 
 
// or pass in an array of stuff and it'll do it all
 
// notice how `html` is accessible in the function 
 
$$('a').setEach('html',[ 
 
    "New foo HTML!", 
 
    function(html){ return html + ' appended moar foo!'; }, 
 
    replaceFooWithBar, 
 
    function(html,i){ return html + ' Index is ' + i; } 
 
 
 
]); 
 
 
 
// or set multiple things, in this case, multiple styles 
 
$$('a').setEachStyle({ 
 
    'color': function(currentColor, i) { 
 
        i = i.toString(16); 
 
        return ['#', i, i, i].join(''); 
 
    }, 
 
    'background-color': function(currentColor, i) { 
 
        i = (15 - i).toString(16); 
 
        return ['#', i, i, i].join(''); 
 
    } 
 
});

Radical. Hats off to Thomas Aylott for this 30 minute script.

jQuery

MooTools

13. Determine the Type of Object (sort of) / 判定对象类型

jQuery 1.4

1
2
3
4
5
6
7
8
9
10
11
jQuery.isEmptyObject({}); // true   
 
jQuery.isEmptyObject({foo:1}); // false   
 
 
 
jQuery.isPlainObject({}); // true   
 
jQuery.isPlainObject(window); // false    
 
jQuery.isPlainObject(jQuery()); // false

I’m not entirely sure how helpful this is. Seems like if an object
is empty when you iterate over it, nothing happens, is there a reason
to check first? Also, why do I care if it’s {} versus new Object(). I’m genuinely curious, not bashing.

MooTools 1.2

Straight from Keetology: Up the Moo Herd V: Evident Utensil

1
2
3
4
5
6
7
8
9
10
11
12
13
// JavaScript's typeof operator..  
 
typeof "a";       // 'string'  
 
typeof 1;         // 'number'  
 
typeof {};        // 'object'  
 
typeof [];        // 'object'.. wait, what?  
 
typeof /m/;       // 'object' in some, 'function' in others..  
 
typeof $('id');   // 'object'.. you're not

站点统计