zoukankan      html  css  js  c++  java
  • select节点clone全解析

    select节点clone全解析

    2009-12-18

    在开发ns-log项目中,统计分类有复制的功能。由于之前的统计分类中的数据是通过JS赋值进去的,之后用户可能又进行了修改,发现进行节点克隆时,出现了 无法复制select下拉框值的怪异现象。本文对这个怪异现象进行解析和给出解决办法。

    问题现状

    使用节点的cloneNode(true/false)进行克隆时,目前是下面的表现情况:

    1. select为设置初始值或者初始值是第一个option。 表现:各大浏览器都没什么问题。
    2. select初始值不是在第一个option。 表现:IE下无法克隆,其他内核的浏览器没什么问题。
    3. select的值被用户或者JS修改。 表现:各个浏览器均无法克隆到真确的值。值结果跟第二条结果相同。

    IE的特殊处理

    对于上面第二条,初始值不在第一个option时无法克隆的情况,确实是IE的一个Bug,相信不少人都遇到过这样的问题。并且IE下使用cloneNode方法时,还有Event方面的问题,所以差不多可以放弃使用这个方法。

    IE下可以使用节点的outerHTML属性解决这个问题,它能够实时的获取节点的内容,哪怕是select的值被用户或者程序改变。下面给出简单的实现。

    function clone(node) {
        var div = document.createElement('div');
        div.innerHTML = node.outerHTML;
        return div.childNodes[0];
    }

    其他内核浏览器的处理

    既然IE内核的浏览器可以通过outerHTML属性来解决这个问题,那FF等浏览器可以通过类似的方法来实现吗?虽然FF等浏览器没有outerHTML属性,但是可以通过innerHTML属性实现,如:

    function getOuterHTML(node) {
        var div = document.createElement('div');
        div.appendChild(node);
        try {
            return div.innerHTML;
        } catch (e) {
            div = null;
        }
    }

    答案是否定。

    为什么会这样呢?难道是FF等浏览器的bug?

    下面还是从W3C中对cloneNode方法,select标签,属性的定义进行说明。

    下面引用的资料都是来自HTML5草案,HTML4或者XHTML对这些没有太多详细的定义。虽然是HTML5的,但这些节点跟以前没什么变化。

    W3C中的cloneNode

    具体链接:http://www.w3.org/TR/DOM-Level-2-Core/core.html

    里面有2点比较重要:

    1. 克隆时会拷贝节点的所有属性和对应的值。
    2. 如果cloneNode方法的参数为true,会通过递归的方法克隆子节点。

    W3C中的select节点

    具体链接:http://dev.w3.org/html5/spec/forms.html#the-select-element

    W3C对于属性的定义有2种,一种是内容性属性(Content attributes),另一种是操作性属性(未给出具体的命名,这里暂时使用这个名字)。

    对于select标签,内容性属性主要有:Global attributes,autofocus,disabled,form,multiple,name,size。其中Global attributes包含一些常用的属性(accesskey,class,contenteditable,contextmenu,dir,draggable,hidden,id,itemid, itemprop,itemref,itemscope,itemtype,lang,spellcheck,style,tabindex,title),这些属性是所有标签里都包含的,具体的见http://dev.w3.org/html5/spec/dom.html#global-attributes

    而selectedIndex和value都属于操作性属性,这两个属性获取值的方式如下:

    select . selectedIndex[ = value ]
    Returns the index of the first selected item, if any, or −1 if there is no selected item. Can be set, to change the selection.
    select . value [ = value ]
    Returns the value of the first selected item, if any, or the empty string if there is no selected item. Can be set, to change the selection.

    内容性属性和操作性属性的区别

    给节点添加属性有两种方式,如下面所示:

    var div = document.createElement('div')
    div.id = 'welefen'; //直接加属性
    div.setAttribute('id','welefen'); //通过setAttribute方法添加属性

    对于内容性属性,这两种方法是完全相同的。

    但对于操作性属性,第一种方式只会将属性添加在操作范围内,当把节点添加到DOM中,属性就失效了。

    由于selectedIndex和value都是操作性属性,如果select的值被用户或者程序改变,clone时当前的值是无法带过去的。所以才会出现了无法克隆值的情况。并且也无法使用innerHTML来克隆值,因为innerHTML的原理跟这个是一样的。

    innerHTML实现原理请看这里:

    FF等浏览器解决方案

    目前有2中解决方案,第一种是在select绑定change事件,触发change的时候,改变options里的selected属性,当然这种方法是很不可取的。另一种方案就是在克隆时获取元素的值,然后再赋值到克隆后的对象上去。

    总结

    当前出现这个情况的时候,以为是FF等浏览器的bug。当后来仔细想想,应该不会这样的情况,后来反复查看W3C相关的文档,终于确认了这一问题。下面给出完整的解决方案:

    function cloneSelect(select) {
        if (document.all) {
            var html = select.outerHTML,
                div = document.createElement('div');
            div.innerHTML = html;
            return div.childNodes[0];
        }
        var cloneSelect = select.cloneNode(true);
        cloneSelect.selectedIndex = select.selectedIndex;
        cloneSelect.value = select.value;
        return cloneSelect;
    }

    原文链接:http://www.welefen.com/select-clone.html

  • 相关阅读:
    [Real World Haskell翻译]第24章 并发和多核编程 第一部分并发编程
    [Real World Haskell翻译]第22章 扩展示例:Web客户端编程
    [Real World Haskell翻译]第27章 网络通信和系统日志 Sockets and Syslog
    druid 解密
    git clone 所有远程分支到本地
    十、Delphi 把Json转成Delphi实体类
    XML External Entity attack/XXE攻击
    大家好!
    XXE攻防——XML外部实体注入
    ubuntu安装Go环境
  • 原文地址:https://www.cnblogs.com/lly001/p/4688378.html
Copyright © 2011-2022 走看看