Home  >  Article  >  Web Front-end  >  API for node operations, subverting the native API for operating HTML DOM nodes_javascript skills

API for node operations, subverting the native API for operating HTML DOM nodes_javascript skills

WBOY
WBOYOriginal
2016-05-16 18:13:58855browse

第一次看到敏捷开发的定义,我就被敏捷开发迷住了。通俗来说,敏捷开发可以让我们用过的代码可以再次重用,因为是再次重用,所以相对安全,再次调试也没有第一次那么费心,省时省力。不断重用代码的过程中把存在的bug不断的修复,也因为不断的去重用, 这个模板变得起越来越独立,适用的情况越来越广范,最后在安全方面达到铜墙铁壁,在开发方面达到随心所欲,在维护方面达到从容面对。

敏捷开发的确是利害,但如何练就这种深奥的武功呢?就我自身的情况靠人传授武功是不可能了,因为公司就我一个做开发的,苦思幂想之后,决定从开源的优秀框架入手,把它一行一行代码看懂,然后再为我所用。因为是一个人开发,前台和后台都得包办,哪从那一面做起呢? 之前有过一二个月的开发经验,觉得前台的JS很费时,而且老觉得在做重复的事情,比如发ajax请求,接收结果之后操作节点(有时候遇到不兼容的情况,如select和table在IE下不支持使用innerHTML,style在IE不会自动转化为字符串,要用cssText代替,一旦这些情况遇上,真得是无比打击程序员的积极性,因为你要为此花时间去找替代方案,去调试),还有节点轮换,弹出层,表单验证等一系列烦琐工作。所以我就坚决从前台的JS做起。为了练就怎么把JS的重用性提高,我选择向Jquery取经。花了几个月看了一大半,略有所得。我其中之一的JS模块“无限深度操作节点”(文采不好,名字不妥别见怪)出来了。有了它,我在操作节点方面变得容易,代码变得精简,而且不用写额外的代码去兼容浏览器,谈笑中,功能就完成了。

首先我谈谈是什么让操作节点给我们带来烦恼:
  • 编写ajax程序时,动态增删改页面元素几乎是不可避免的,使用属性innerHTML就是我们经常利用的途径,但在IE中table,thead,tfoot,tbody,tr,col,colgroup,html,title,style,frameset的innerHTML属性是只读的,也就是我们不能使用innerHTML更新这些节点。(这里没有提到select,其实select也是不会成功的,估计是IE的bug)。例子如下:(下面的$id代表document.getElementById)
    //执行代码:
    $id('jkit').innerHTML = '';
    //IE下并没有报任何错误,但select一个option节点都没有了。如果你对table使用innerHTML,IE会报unknown runtime error
     
    对于这种情况比较常用的兼容方法是外加一个外层元素,例子如下:

        
    //执行代码:
    $id('jkit').innerHTML = '';
    //这样IE也成功改变select,但这种做法有个缺点,如果你对select注册过事件,这些事件会全部丢失,你要外加代码来重新注册事件。
     
  • 在指定的节点前后新增节点,这就涉及于节点定位,节点创建以及给节点属性设置。使用innerHTML通常只用于覆盖DOM元素的所有节点,如果只想改变元素的某个子节点,或者只想在某个子节点前后增加节点,仍然使用innerHTML就适得其反,实现起来很吃力了,而且使用了innerHTML之后,对子节点注册过的事件肯定全部丢失掉。不使用innerHTML,那只好使用原生的DOM方法了,但这种代替方案也不好使,看下面例子:
    //现在我想在jkit之前多加一个option,用原生的DOM方法实现:
    var newNode = document.createElement('option'),//新建一个节点
    selector = document.getElementById('jkit3'),
    /* 也可以用selector.options,但getElementsByTagName更通用。
    那用childNodes怎么?最好也不要,对于空白节点,IE和FF的处理方式不一样,
    就这例子,在FF中,select的firstChild是空白文本节点,
    因为select和第一个option之间有换行以及空白字符,
    FF会为其创建节点,而IE会忽略 */
    options = document.getElementsByTagName('option');
    newNode.setAttribute('value','new');
    //newNode.setAttribute('text','NewNode');text不支持这样设置
    //newNode.text = 'NewNode';ie不支持这种方式
    newNode.innerHTML = 'NewNode';
    selector.insertBefore(newNode,options[1]);//在kit之前插入
     
    After executing the above code, select has one more option:

                
                
                    

                          L
                          
    • XL

    •                 

                
            
            
                
                
                
            
        
    /* 下面代码实例化了一个无限层次节点操作插件的对象,相当于重新构造了一棵新的对象树,新的对象树带有新的成员方法。就下面的例子,新对象树引用为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]);  
  • Member methods of the new tree, When reading the following API, please keep two points in mind. First, all methods of the root object and descendant objects are for the original DOM object, such as calling del on the new object. , its essence is to delete the corresponding original DOM object; secondly, every time the addition, deletion or modification of the object is called, the corresponding branch will be reconstructed

    Root object unique method
    function map(index1,index2,,,indexN){}
    This method is used to find descendant nodes. table.map(1,1,0) will find the second row of The first object of the two cells is the object corresponding to select. When map has only one parameter, and the parameter is a DOM native object, then this method returns the corresponding new object.
    function index(DOMElement){}
    This method returns the index corresponding to the native DOMElement object, table.index(document.getElementById('lior')), then returns [1,2 ,0,0], the result is in array form
    Methods unique to descendant objects
    function add(index, html){}
    This method is used to add sibling nodes. Index is the displacement relative to the position of the object that calls this method. HTML is what is to be inserted. Node, html can be any html string that conforms to W3c standards
    table.map(2).add(-1,'< /td>'), add a new line before the third line (multiple lines can be inserted at the same time)
    table.map(2).add(-2, ''), add a new line before the previous line of the third line
    table.map(0).add(2,'table.map(1).add(0,''), an index of 0 means adding a new row before the current row and deleting the current row
    table.map(1).add('< tr>'), omitting the first parameter, this is a special usage, Regardless of which object is used, a new row will be added to the last row
    table.map(1,1).add(1,'New cell '), add a new cell after the second cell in the second row, and so on for further nodes, just use the map method to determine the node
    function del(index){}
    This method is used to delete sibling nodes, index is the displacement relative to the position of the object that calls this method
    table.map(1) .del(), omitting index means deleting itself. Deleting the second row here is equivalent to table.map(1).del(0)
    table.map(0).del(2). Deleting here is relative to the current call. The second line after the object, here is to delete the third line
    table.map(2).del(-2), here is to delete the second line in front of the current calling object, here is to delete the first line
    table .map(0,1).del([0,-1,1]), if index is an array, then the sibling node of the specified index is deleted. At this time, it does not matter which object is called. A negative index means starting from the last Counting, -1 means the last one, here delete the first, second and last th
    table.map(0,1).del(0,-1), if there are two parameters, it means delete Specify the sibling nodes of the interval. At this time, it does not matter which object is called. A negative index means counting from the end, -1 means the last one. Here, delete the first to last elements. The larger parameter can be used as the first parameter. There is no limit to the order of size
    function getParent(){}
    Get the native DOM object node corresponding to the parent object of the calling object, table.map(0,1).getParent().tagName is tr
    function getHigher(){}
    Get the parent object of the calling object, table.map(0,1).getHigher.getNode().tagName is tr
    Methods owned by root objects and descendant objects
    function getNode(){}
    Get the native DOM object node corresponding to the calling object, table.getNode().tagName is table, table.map(0,1).getNode() for th
    function sizeOf(){}
    Get the number of sub-objects of the calling object. table.sizeOf() is 3, which means there are three rows
    function pos(){}
    Get the position of the calling object in all its sibling nodes, table.map(1).pos() is 1
    function html(html){}
    Get the innerHTML of the native DOM object corresponding to the calling object. If there are parameters passed, assign a value to its innerHTML attribute (please do not assign a value to the read-only object innerHTML )
    function attr(html){}
    Get the innerHTML of the native DOM object corresponding to the calling object. If there are parameters passed, assign values ​​to their corresponding attributes (not yet implemented)
    function before(index,html){}
    Add a node in front of the specified sub-object of the calling object, index is the relative displacement
    table.before(1,' '), add a line
    table.map(1 ,2,0).before(-1,'
  • New li node
  • '), add a new li before the last li (the index is a negative number means counting from the end, -1 means the last)
    table.before(''), omitting the first parameter means adding a new node in front of the first sub-object.
    function append(index,html){}
    Add a node behind the specified sub-object of the calling object, index is the relative displacement
    table.append(1,' '), add a line after the second line
    table.map(1 ,2,0).append(-1,'
  • New li node
  • '), add a new li after the last li (the index is a negative number means counting from the end, -1 means the last)
    table.append(''), omitting the first parameter means adding a new node after the first sub-object.
    function replace(index,html){}
    Replace the native DOM node corresponding to the specified sub-object of the calling object with the node generated by html. Index is the relative displacement
    table.replace( 2,'New line'), add a new line and use It replaces the second line
    table.replace(-1,'New line'), add a new line and replace the last line with it (a negative index means counting from the end, -1 means the last one)
    function clean(index){}
    This method is used to delete sibling nodes. Index is the displacement relative to the position of the object that calls this method.
    table.clean(), Omitting index means deleting the first sub-object. Deleting the first row here is equivalent to table.map(1).del(0)
    table.clean(2). Here it means deleting the third row
    table.clean (-2), here means deleting the last row
    table.map(0).clean([0,-1,1]), if index is an array, then the sub-object of the specified index is deleted, and the index is a negative number means counting from the end, -1 means the last one, here delete the first, second and last th
    table.map(0).clean(0,-1), if there are two parameters, it means Delete the sub-objects in the specified range. A negative index means counting from the end, -1 means the last one. Here, delete the first to last elements. The larger parameter can be used as the first parameter. There is no limit on the size order
    If the root node of the new tree is table, and its child nodes are tbody/thead/tfoot, since we will not operate these nodes more often, but directly operate tr, so I made a slightly allowed through the processing of these nodes. Of course, if you want to operate the tbody, you can pass the parameters like this ['tbody thead tfoot', 'tr', 'td']; if you only want to get one of them, you can ['tbody', 'tr', 'td ']; if you directly take tr, you can ['tr','td']. In this case, new objects will be generated for all tr ​​in tbody/thead/tfoot
Conclusion: Thinking back, with such a plug-in, node operation is a piece of cake. The three major troubles of node operation mentioned before will be solved. Moreover, this plug-in has nothing to do with any logic and does not require secondary processing. It can be used as soon as you pick it up. It can also be expanded when it cannot meet the needs. Imagine that one day the development process will be like a jigsaw puzzle. After the developed plug-ins are combined, a project will come out. How wonderful it would be. The result may not be as good as expected, but it can be expected. Going in this direction, it is inevitable that events will become simpler and simpler. Because the article is too long, the source code part will be explained in detail next time I publish an article.
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn