【问题标题】:create a HTMLCollection创建一个 HTMLCollection
【发布时间】:2011-10-13 12:40:31
【问题描述】:

我正在尝试填充 Element.prototype.children,它应该返回一个 HTMLCollection

有一个window.HTMLCollection

然而

var h = new HTMLCollection();
//TypeErrror: HTMLCollection is not a constructor

var h = Object.create(HTMLCollection.prototype);
h[0] = div;
h.item(0); 
// Could not convert JavaScript argument

测试 Firefox 7 和 Chrome

除了 shiming HTMLCollection 有什么方法可以与之交互吗?

如果您可以提出解决方案,请在this github issue 上提供反馈

【问题讨论】:

  • 我认为正确的做法是定义自己的自定义MyHTMLCollection构造函数,然后使用它代替宿主构造函数HTMLCollection(这不可靠)
  • 虽然我无法回答您关于 HTMLCollection 的具体问题,但扩展本机 DOM(托管)对象通常被认为是不好的做法。详细解释见这篇文章:perfectionkills.com/whats-wrong-with-extending-the-dom
  • @skyline3000 我完全清楚后果。我们需要这样做来生成一个 DOM-shim。我们不是使用自定义方法(邪恶)扩展 DOM,而是使用根据 DOM4 规范应该存在的方法

标签: javascript dom dom4


【解决方案1】:

我认为这是创建由浏览器处理的 HTMLCollection 的正确方法。

var docFragment = document.createDocumentFragment();
docFragment.appendChild(node1);
docFragment.appendChild(node2);
var myHTMLCollection = docFragment.children;

参考:

https://stackoverflow.com/a/35969890/10018427

https://developer.mozilla.org/en-US/docs/Web/API/NodeList

https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection

https://www.w3schools.com/js/js_htmldom_nodelist.asp

【讨论】:

  • 不错!这是更新和更合适的答案。
  • 这是一个非常实用的解决方案
【解决方案2】:

我会这样做:

function MyHTMLCollection( arr ) {
    for ( var i = 0; i < arr.length; i += 1 ) {
        this[i] = arr[i];
    }

    // length is readonly
    Object.defineProperty( this, 'length', {
        get: function () {
            return arr.length;
        }
    });

    // a HTMLCollection is immutable
    Object.freeze( this );
}

MyHTMLCollection.prototype = {
    item: function ( i ) {
        return this[i] != null ? this[i] : null;
    },
    namedItem: function ( name ) {
        for ( var i = 0; i < this.length; i += 1 ) {
            if ( this[i].id === name || this[i].name === name ) {
                return this[i];
            }
        }
        return null;
    }
};

其中arr 是一个常规数组,其中包含应该在 HTMLCollection 中的所有 DOM 元素。

待办事项:

  • 应事先检查参数arr:它是一个数组吗?该数组的所有元素都是 DOM 元素吗?

【讨论】:

  • instance[4] = newEl 怎么样。 length 会失败。我认为您需要在每次调用时计算长度才能使其正常工作。
  • @Raynos 我刚刚更新了我的答案。 Object.freeze( this ) 在构造函数中,但我不确定规范对 HTML 集合的不变性有何规定。我会检查...
  • Object.defineProperty 也只适用于 IE8 中的 DOM,所以我的 dom-shim 刚刚在 IE8 中中断。我想我可以在 IE8 中将 length 属性设为静态值,然后就忘了它。
  • @ŠimeVidas - check the spec,集合具有只读长度。
  • @RobG 是的,我将它定义为没有设置器的访问器属性 - 这使它成为只读的。 { value: arr.length, writable: false } 会更合适,但这也有效。
【解决方案3】:

不要期望宿主对象表现得像(ECMAScript)原生对象,它们是完全不同的东西。一些浏览器确实实现了它们的 DOM 对象,如 ECMAScript 对象,但这不是必需的,也不应该依赖它。请注意,大多数 HTML 集合都是实时的,很难在本机对象中模拟它。

【讨论】:

  • 如果没有代理,它们确实很难模拟。
【解决方案4】:

我知道这是一个较老的问题,但我遇到了类似的需要创建一个空的 HTMLCollection,我通过简单地创建一个元素然后使用该元素中不存在的类对其运行 getElementsByClassName() 来做到这一点.

document.createElement("div").getElementsByClassName('noClassHere');

这会返回一个空的 HTMLCollection 对象。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-06
    • 2016-03-17
    • 1970-01-01
    相关资源
    最近更新 更多