编写函数来遍历jquery样式库中的元素

时间:2016-01-09 10:09:46

标签: javascript

我正在编写一个非常简单的jquery模仿库,以允许一些简单的DOM操作。

我正在编写方法以允许我更改文本的颜色等。当我希望更改类元素颜色时,我必须在每个方法中使用循环。理想情况下,我想有一个函数为我做这个循环,然后我可以在每个方法中使用。不幸的是,我的尝试不起作用。

请参阅下面的代码:

function _(elem) {
  this.classOrId(elem);
}

_.prototype = {
  add: function(text) {
    if (this.e.length >= 1) {
      for (var i = 0; i < this.e.length; i++) {
        this.e[i].innerHTML = this.e[i].innerHTML + text;
      }
    } else {
      this.e.innerHTML = this.e.innerHTML + text;
    }
    return this;
  },
  replace: function(text) {
    if (this.e.length >= 1) {
      for (var i = 0; i < this.e.length; i++) {
        this.e[i].textContent = text;
      }
    } else {
      this.e.textContent = text;
      document.body.appendChild(elem);
    }
    return this;
  }
}

_.prototype.classOrId = function(elem) {
  var classOrId = elem.charAt(0);
  if (classOrId === "#") {
    elem = this.sliceElement(elem);
    this.e = document.getElementById(elem);
    return this;
  } else if (classOrId === ".") {
    elem = this.sliceElement(elem)
    this.e = document.getElementsByClassName(elem);
    return this;
  }
};

_.prototype.sliceElement = function(elem) {
  var elem = elem.slice(1);
  return elem;
};

正如您所看到的,此代码中存在大量重复。我尝试写下面的内容以减少重复,但它没有用。 这里的任何建议将不胜感激。

_.prototype.loopOverElements = function(effect) {
  for (var i = 0; i < this.e.length; i++) {
    return this.e[i][effect];
  }
}

使用下面的代码,当它们传递给函数时,它无法识别innerHTMLstyle等javascript DOM方法。

使用上面的代码,如果我将效果传递给loopOverElements函数,它会在传递给方法时显示console.log(this.e[i][effect])未定义。

4 个答案:

答案 0 :(得分:1)

您应该在codereview发布此内容,但我会试一试。困扰我的第一件事就是if (this.e.length >= 1) { } else { }。即使只有一个元素,也要使e成为一个数组,只有变量的值应该“变量”而不是它的类型。

关于classOrId(),由于document.querySelectorAll(返回所需的数组),它可以缩减为一行。所以代码变成了:

function _(elem) {
    var about = {
        Name: "pQuery",
        Version: 0.1,
        Author: "Paul Fitzgerald"
    }

    if (elem) {
        if (window === this) {
            return new _(elem);
        }
        this.e = document.querySelectorAll(elem); // no need for classOrId() anymore
    } else {
        return about;
    }
}

_.prototype = {
    add: function (text) {
        // no if else anymore
        for (var i = 0; i < this.e.length; i++) {
            this.e[i].innerHTML = this.e[i].innerHTML + text;
        }
        return this;
    }
}

关于重复,将函数分成类似的用法,例如,您可以为与样式相关的所有操作编写函数:

_.prototype = {
    _eachStyle: function (prop, value) {
        for (var i = 0; i < this.e.length; i++) {
          this.e[i].style[prop] = value;
        }

        return this;
    },
    hide: function () {
        return _eachStyle('display', 'none');
    },
    color: function (color) {
        return _eachStyle('color', color);
    }
}

对于基本属性:

_.prototype = {
    _each: function (prop, value, append) {
        append = append || false; // by default, replace the value
        for (var i = 0; i < this.e.length; i++) {
          this.e[i][prop] = append ? element[prop] + value : value;
        }
        return this;
    },
    add: function (text) {
        return _each('innerHTML', text, true);
    },
    replace: function (text) {
        return _each('textContent', text);
    }
}

同样地,要在所有元素上调用函数:

_.prototype = {
    _eachFn: function (fn, args) {
        for (var i = 0; i < this.e.length; i++) {
          this.e[i][fn](args);
        }
        return this;
    },
    remove: function () {
        return _eachFn('remove');
    },
}

答案 1 :(得分:1)

正如我之前在聊天会话中提到的,您基本上希望对数组中的每个DOM元素应用转换。使用定义需要完成的功能并通过此函数映射每个元素的函数是理想的方法。

_.prototype.loopOverElements = function(effect) {
  for (var i = 0; i < this.e.length; i++) {
    effect(this.e[i]);
  }
};

And I can use it as

var test = new _('.test');
test.loopOverElements(function(elem) {
  elem.innerHTML += " Modified";
});

Here is a working demo for this implementation.

但您的要求是您需要一个包含2个参数的循环方法 - propertyNamevalue。与此相关的问题有很多,例如假设属性为style.color。您无法使用this.e[i]['style.color']访问该媒体资源。它不是有效的js。它应该是this.e[i]['style']['color']。所以基本上this.e[i][effect]在这种情况下不起作用。像lodash这样的库有一个_.set方法,您可以在其中指定属性路径,并且将正确设置该值。 You can see the implementation here

我已经创建了set方法的简单实现。

_.prototype.set = function set(obj, path, value) {
  var codeString = 'obj';
  codeString += path.split('.').reduce(function(prev, curr) {
    return prev += '.' + curr;
  }, '');

  codeString += ' = value';
  eval(codeString);
};

Now your loop code looks like

_.prototype.loopOverElements = function(property, value){
  for(var i = 0; i < this.e.length; i++){
    this.set(this.e[i], property, value);
  }
};

And it can be used like

document.addEventListener("DOMContentLoaded", function(event) {
  var test = new _('.testClass');
  test.loopOverElements('style.color', 'red');
});

<强> Here is a working demo for this implementation.

答案 2 :(得分:0)

使用括号表示法,即[effect]代替.effect

_.prototype.loopOverElements = function(effect){
  for(var i = 0; i < this.e.length; i++){
    return this.e[i][effect];
  }
}

另见JavaScript property access: dot notation vs. brackets?

答案 3 :(得分:0)

解决问题的另一种方法是使用回调函数:

_.prototype.applyOnElements = function(callback) {
   for(var i = 0; i < this.e.length; i++){
     callback(this.e[i]);
   }
}

你用这种方式:

this.applyOnElements(function(element) {
    element.style.color = myColor;
});

然后,可以通过Array.forEach替换循环并在此函数中包含if (this.e is array) then ... else ... endif来避免更多代码重复。