循环使用多个元素并为每个元素添加一个包装器

时间:2014-12-25 00:33:41

标签: javascript

在等待人们过圣诞节的同时,我试图用香草JS开始一个类似浮动标签的库。而且我被困在我在输入

周围添加包装的部分
var materialFloatLabel = function(o) {
  o = (typeof o === 'undefined') ? '' : o;

  var lib = {
    // Just for the futur settings
    settings: {
      selector: o.selector ? o.selector : '.matFloat'
    },

    // Getting the inputs
    inputs: function() {
      return document.querySelectorAll(this.settings.selector);
    },

    // Adding a specific class to each input so it can easily be selected later 
    addWrapper: function() {
      for(var i = 0; i < this.inputs().length; i++) {
        this.inputs()[i].className = this.inputs()[i].className + ' materialFloatLabel' + i;
        var wrapper = document.createElement('div');
        wrapper.appendChild(this.inputs()[i]);
        // ERROR DOWN HERE
        document.querySelectorAll('.materialFloatLabel' + i).parentNode.replaceChild(wrapper, document.querySelectorAll('.materialFloatLabel' + i));
      }
    },

    init: function() {
      this.addWrapper();
    }
  };

  return lib.init();
};

(function() {
  materialFloatLabel();
})();

我坚持的当前错误是Uncaught TypeError: Cannot read property 'replaceChild' of undefined我无法完成它。有什么想法吗?

这是a fiddle现场检查

1 个答案:

答案 0 :(得分:1)

您需要使用:

document.querySelectorAll('.materialFloatLabel' + i)[0]

即使只返回了一个元素。

根据MDN spec

elementList = document.querySelectorAll(selectors);
// elementList is a non-live NodeList of element objects.

NodeListarray-like object


在代码中:

for(var i = 0; i < this.inputs().length; i++) {
    this.inputs()[i].className = this.inputs()[i].className + ' materialFloatLabel' + i;
    // Create a Node, which is NOT on DOM yet.
    var wrapper = document.createElement('div');   
    // MOVE the input to the new Node, so the input is not on DOM anymore!
    wrapper.appendChild(this.inputs()[i]);         
    // Since the input is not on DOM, querySelectorAll('.materialFloatLabel' + i) returns []
    document.querySelectorAll('.materialFloatLabel' + i)[0].parentNode.replaceChild(wrapper, document.querySelectorAll('.materialFloatLabel' + i)[0]);
}

添加新类后无法查询输入,因为输入不再出现在DOM上。请注意appendChild会将节点移动到新位置({{ 3}})。由于您要将输入移至wrapper,但尚未在DOM上,您的querySelectorAll将返回空。

还有更多

每次都不要执行this.input(),因为您的DOM正在发生变化。如果你不小心,你的循环可能变得一团糟。由于querySelectorAll的结果不存在,您可以保持选择结果的一致性。

更重要的是,为了获得更好的性能,最好将中间结果存储在某些变量中。

以下是一个工作示例:MDN Spec