接下来要谈的是,怎么编写代码让我们的事件变得简单。先不要理会技术层面的事件,假如现在有这么一个JS类,里面有若干方法,这些方法足以让我们完成上面以及比上面更加复杂的事件。这个假设存在的类,因为只有方法名,没有具体实现,我们把它称为接口。那些下面要讲的是定义接口,当我们觉得接口中的方法能满足需求,我们再去实现它。(这是比较好的开发流程,先规划后行动)
- 实例化一个对象
开发项目中,因为不止无限层次节点操作这个插件,还有很多,囊括了b2c和b2b常用的插件,比如轮换,分页,表单验证,表单元素取设值,批量上传图片,事件的重新包装,事件的批量处理,搜索的自动补全,购物车的ajax操作,以及公共方法的类。所以整个js会有很多类,每个类对应一个js变量,这样一来就有很多公共的js变量,如果开发的时候不小心在别的地方声明了一个同名的变量,那么这个类被消失。为了避免这种情况,我把所有类封装到一个名为$jkit类中,这样公共的变量就只有一个了。插件的类变成了局部,我怎么样访问呢?我另外定义一个$CL的类,里面定义了一些方法,这些方法用于访问$jkit的类,这样一来,就算有再多插件,都只会有两个公共变量$CL和$jkit。$CL负责调用$jkit。比如$CL中的newObj就用于实例化插件对象的方法。newObj有两个参数,第一个指定要实例化哪个插件,第二个参数用于实例化这个插件时的初始化参数,以数组的形式传参。
<table id="jkit"> <tbody> <tr> <th class="align">Option</th> <th> <a href="javascript:void(0);">Status</a> </th> <th> <a href="javascript:void(0);">Attribute</a> </th> </tr> <tr> <td></td> <td> <select size="3" name="status"> <option value="all">所有</option> <option value="0">下架</option> </select> </td> <td> <ul> <li id="lior">L</li> <li>XL</li> </ul> </td> </tr> <tr> <td></td> <td></td> <td></td> </tr> </tbody> </table> |
/* 下面代码实例化了一个无限层次节点操作插件的对象,相当于重新构造了一棵新的对象树,新的对象树带有新的成员方法。就下面的例子,新对象树引用为table,table也是新树的根。它的后代对象由第二个参数childs决定 。新树的根引用是操作其后代对象的入口。重点讲解一下第二个参数。childs是一个数组结构,数组的第一个元素为tr,表示为dom根节点root的孩子节点tr重新构造新对象。如果原dom根节点root的中没有tr,将不会构造对象;如果tr内嵌有tr,不会为内嵌的tr构造节点,也就是说只会为孩子节点构造对象,孩子以下不会理会。第二个元素是td th,为什么有两个呢?因为tr下的孩子节点可以是th也可以是td,如果想同时为th td构造新的对象,就要同时写进去,用空格分开,检签的顺序不限制。第三个元素为select ul,为什么这两个可以写在一起?因为他们位于同一层次的,相对于根节点,它们都在第三层。只要同一层次的都可以写在一起。后面的以此类推,数量不限,就是无限层次了。新对象树的层次结构和原dom树的层次结构是一一对应的。 */ root = document.getElementById('category'),
childs = ['tr', 'td th', 'select ul', 'li option'],
table = $CL.newObj('maNode', [root, childs]); |
|
- 新树的成员方法,阅读下面的API时,请心里紧记两点,其一,根对象以及后代对象的所有方法都是针对原DOM对象的,比如对新对象调用del,其实质是删除了对应的原DOM对象;其二,每次调用对象的增删改时,都会重新构造相应的分枝
- 根对象独有方法
- function map(index1,index2,,,indexN){}
该方法用于寻找后代节点,table.map(1,1,0)会找到第二行的第二个单元格的第一个对象,也就是select对应的对象。当map只有一个参数,并且该参数为DOM原生对象,那么该方法返回对应的新对象。 - function index(DOMElement){}
该方法返回原生DOMElement对象对应的素引,table.index(document.getElementById('lior')),则返回[1,2,0,0],结果是数组形式 - 后代对象独有的方法
- function add(index, html){}
该方法用于增加兄弟节点,index是相对于调用该方法的对象所处位置的位移,html就是要插要的节点,html可以是符合W3c标淮的任意html字任串 table.map(2).add(-1,'<tr><td></td><td></td><td></td></tr>'),在第三行前面新增一行(可以同时插入多行) table.map(2).add(-2,'<tr><td></td><td></td><td></td></tr>'),在第三行前一行前面新增一行 table.map(0).add(2,'<tr><td></td><td></td><td></td></tr>'),在第一行后一行前面新增一行 table.map(1).add(0,'<tr><td></td><td></td><td></td></tr>'),index为0表示在当前行前面新增一行,并把当前行删除 table.map(1).add('<tr><td></td><td></td><td></td></tr>'),省略第一个参数,这是比较特别的用法,不用理会由哪个对象用,会在最后一行新增一行 table.map(1,1).add(1,'<td class="one">新增单元格</td>'),在第二行的第二个单元格之后新增一个单元格,再深入的节点如些类推,只需由map方法来确定节点就可以了
- function del(index){}
该方法用于删除兄弟节点,index是相对于调用该方法的对象所处位置的位移 table.map(1).del(),index省略表示删除自身,这里删除第二行等同于table.map(1).del(0) table.map(0).del(2),这里删除相对于当前调用对象后面第二行,这里就是删除第三行 table.map(2).del(-2),这里删除相对于当前调用对象前面第二行,这里就是删除第一行 table.map(0,1).del([0,-1,1]),如果index是一个数组,那么就是删除指定索引的兄弟节点,这时不用理会由哪个对象调用,索引为负数表示从最后计起,-1表示最后一个,这里删除第一个,第二个以及最后一个th table.map(0,1).del(0,-1),如果有两个参数,表示删除指定区间的兄弟节点,这时不用理会由哪个对象调用,索引为负数表示从最后计起,-1表示最后一个,这里删除第一个至后一个元素,参数大的可以作为第一个参数,大小顺序没有限制
- function getParent(){}
获取调用对象父对象对应的原生DOM对象节点,table.map(0,1).getParent().tagName为tr - function getHigher(){}
获取调用对象的父对象,table.map(0,1).getHigher.getNode().tagName为tr - 根对象以及后代对象都拥有的方法
- function getNode(){}
获取调用对象对应的原生DOM对象节点,table.getNode().tagName为table,table.map(0,1).getNode()为th - function sizeOf(){}
获取调用对象子对象的个数,table.sizeOf()为3,表示有三行 - function pos(){}
获取调用对象在其所有兄弟节点的所处的位置,table.map(1).pos()为1 - function html(html){}
获取调用对象对应原生dom对象的innerHTML,如果有传参,为其innerHTML属性赋值(请不要对innerHTML为只读的对象赋值) - function attr(html){}
获取调用对象对应原生dom对象的innerHTML,如果有传参,为其对应的属性赋值(还未实现) - function before(index,html){}
往调用对象的指定子对象前面添加节点,index是相对位移 table.before(1,'<tr><td></td><td></td><td></td></tr>'),第二行前面添加一个行 table.map(1,2,0).before(-1,'<li style="color:red;">新增li节点</li>'),在最后一个li前面新增一个li(索引为负数表示从最后计起,-1表示最后一个) table.before('<tr><td></td><td></td><td></td></tr>'),省略第一个参数表示在第一个子对象前面新增节点 - function append(index,html){}
往调用对象的指定子对象后面添加节点,index是相对位移 table.append(1,'<tr><td></td><td></td><td></td></tr>'),第二行后面添加一个行 table.map(1,2,0).append(-1,'<li style="color:red;">新增li节点</li>'),在最后一个li后面新增一个li(索引为负数表示从最后计起,-1表示最后一个) table.append('<tr><td></td><td></td><td></td></tr>'),省略第一个参数表示在第一个子对象后面新增节点 - function replace(index,html){}
用html生成的节点替代调用对象的指定子对象对应的原生DOM节点,index是相对位移 table.replace(2,'<tr><td>新增行</td><td></td><td></td></tr>'),新增一行,并用其替换掉第二行 table.replace(-1,'<tr><td>新增行</td><td></td><td></td></tr>'),新增一行,并用其替换掉最后一行(索引为负数表示从最后计起,-1表示最后一个) - function clean(index){}
该方法用于删除兄弟节点,index是相对于调用该方法的对象所处位置的位移 table.clean(),index省略表示删除第一个子对象,这里删除第一行等同于table.map(1).del(0) table.clean(2),这里表示删除第三行 table.clean(-2),这里表示删除最后一行 table.map(0).clean([0,-1,1]),如果index是一个数组,那么就是删除指定索引的子对象,索引为负数表示从最后计起,-1表示最后一个,这里删除第一个,第二个以及最后一个th table.map(0).clean(0,-1),如果有两个参数,表示删除指定区间的子对象,索引为负数表示从最后计起,-1表示最后一个,这里删除第一个至后一个元素,参数大的可以作为第一个参数,大小顺序没有限制
- 如果新树的根节点是table,而其子节点是tbody/thead/tfoot,由于我们更多时候不会操作这些节点,而是直接操作tr,所以我做了一个允许略过这些节点的处理。当然你如果想操作tbody也是可以的,你大可以这样传参['tbody thead tfoot','tr','td'];只想取其中一个的话可以['tbody','tr','td'];直接取tr的话,可以['tr','td'],这种情况会对tbody/thead/tfoot中的所有tr生成新对象
结束语:回过头想想,有了这么一个插件之后,节点操作不就是小菜一碟,之前提到的操作节点的三大烦恼就迎刃而解了吧。而且这个插件与任何逻辑无关,不需要二次加工,拿起来就可以用了,遇到无法满足需求的时候还可以对其进行扩展。想象有一天开发流程好像是拼图游戏,开发好的插件经过组合,一个项目就出来,那是多么美妙的事啊。可能结果并没有预期的美好,但是可以预料得到,向着这个方向走,事件变得越来越简单是必然的。因为篇幅太长了,源码部分会在下次发表文章的时候进行详细的解讲。
(责任编辑:admin) |