今日任务:学习Node模块,对拆合菜单实例代码进行优化重构.
前面我们分别讲解了DOM 和Event模块,那时是按照使用什么模块就引用什么模块的原则编写代码的。同时,我们也在Event章节提到过:通常DOM事件无需直接引用event,只需use('node')即可。使用use('base')时也无需手动引入 event。那么本节我们就来具体体会下Node模块的功能。
一、Node.one与DOM.get
one和get同样是获取符合选择器的第一个元素,但有本质上的区别,one属于node模块,而get属于dom模块。使用one意味着使用类似于jquery获取元素的方式,而get是类似YUI获取元素的方式,二者的返回值也是不同的,接下来以一个demo来具体演示其差别:
KISSY.use('node',function(S,Node){ var menu=Node.one("#menu"); alert(menu); }); KISSY.use('dom',function(S,DOM){ var menu=DOM.get("#menu"); alert(menu); }); |
效果图分别是:
可以看到二者的返回值是不一样的,使用Node模块的menu是object,而使用DOM模块的menu是HTNLUListElement。其实可以把one方法看做是对get的二次封装。当元素存在时,S.one返回的是Node实例(就可以使用类似jquery的链式调用,继续调用node的其他方法);不存在返回null。
在DOM章节里,有这样一段代码:
var menu = DOM.get("#menu"); Event.on('#btn-4','click',function(evt){ var menuChildrens = DOM.children(menu); alert(menuChildrens.length); }); |
用途是点击id为btn-4的按钮,弹出获取到的拆合菜单的子节点li的个数。那么下面看看用one如何实现这个功能:
KISSY.use('node',function (S,Node) { var len= Node.one("#menu").children().length; Node.one("#btn-4").on('click',function(){ alert(len); }); }); |
代码是不是简洁多了?既然有children(),可以预见还有prev()、next()、parent()、text()等,只要是dom模块中的方法,node模块都有对应的接口。不仅是dom模块,event和anim模块中的方法,node模块都有对应的接口。
三、Node演练:向第二个子菜单添加新的菜单项
先来看看DOM章节的代码:
KISSY.use('dom,event', function (S,DOM,Event) { //向第二个子菜单添加新的菜单项 Event.on('#btn-7','click',function(evt){ var menuChildrens = DOM.children(menu); var secondUl = DOM.children(menuChildrens[1],'ul'); //创建一个新的li节点 var newLi = DOM.create('<li class="new"><a>test13</a></li>'); DOM.append(newLi,secondUl); }); }); |
再来看下使用node的API的代码:
KISSY.use('node', function (S,Node) { //向第二个子菜单添加新的菜单项 Node.one('#btn-7').on('click',function(){ Node.one("#menu").children().item(1).children('ul').append('<li class="new"><a>test13</a></li>'); }); }); |
一行代码搞定,node模块的简洁性是dom模块无法比拟的,如果你熟悉jquery,那么无疑可以快速掌握node模块用法,node模块的API命名,基本上与jquery的API保持一致,但有一些事不同的,这要留意,比如获取第二个子菜单,jquery是$("#menu").children('li').eq(1),而kissy是S.one("#menu").children().item(1)。
另外,对于Node的事件操作:
KISSY.use('node',function (S,Node) { Node.one('#btn-3').on('click', function(e) { e.halt(); alert('event: ' + e.type + ' target: ' + e.target.tagName); }); }); |
弹出的窗口如下图:
回调传回一个门面对象e,注意e不是原生事件对象,是封装后的,这时e.target是裸的节点。除了preventDefault()和stopPropagation()之外,e还包含halt()方法,停止事件加阻止默认行为。
四、什么是nodelist
nodelist很好理解,就是节点集合,比如你要获取拆合菜单的三个li节点。
KISSY.use('node', function (S,Node) { var list=Node.all("#menu li"); alert(list.length); }); |
list长度是:
all遍历出了拆合菜单下的所有li,包括二级菜单的li。即,如果在上节的实例中结果将会是12。
查找节点集合最简单的办法即使用S.all,DOM 操作方法中,KISSY库会尽可能的返回节点集合,而非节点。通过nodeList[i]来获取第i个节点(从0开始计算)。
节点集合暴露each()方法,方便我们对节点集合进行遍历。对一个Nodelist执行attr方法,将返回第一个节点的属性值。
Node 实例支持逐级查找S.all('.s1').all('.s2')和S.all('.s1 .s2')是等价的。
S.all('.s1').all('.s2')和S.all('.s1 .s2')毕竟还是不同的,在一个多次遍历的场景中,无报错的情况下,通常第一个用法速度优于第二个,因为S.one始终从document根节点开始查找。
五、each
非常常用的一个方法,用于遍历节点集合。
KISSY.use('node', function (S,Node) { //向第二个子菜单添加新的菜单项 Node.one('#btn-9').on('click',function(evt){ Node.all("#menu div").each(function(o,i){ var txt = o.text(); if(txt == 'test2') alert(i); }); }); }); |
弹出的窗口是:
each的参数为一个函数,该函数带有2个参数,一个是元素(KISSY.Node的实例),一个是元素索引值。
当然,关于Node模块以上内容是远远不够的,但是,相信学习到现在,一定对KISSY的理解更加深入了。还有些方法equals、item、slice、append、appendTo、insertBefore等等都很重要,请查看API文档自行理解学习。