使用querySelectorAll / classList添加泛型类,而不必经常循环

时间:2017-05-29 12:37:00

标签: javascript jquery arrays selectors-api

我正面临以下问题。

每次我必须querySelectorAll使用Element.classList,我需要

  1. 将从Element.querySelectorAll返回的NodeList转换为数组
  2. 对数组执行forEach以分别操作每个项目。
  3. jQuery抽象了上面的内容,所以我想开发一个类似于jQuery工作方式的辅助方法,它可以这样工作:

    myhelper('.someClass').classList.add('newClass'); // there are more than 1 .someClass items
    myhelper('#id').classList.remove('existingClass');
    

    基本上myhelper(selector)应该抽象上面的点1 + 2:从querySelectorAll获取NodeList,将其转换为Array,forEach数组和*执行用户给出的方法。

    PS:为简化起见,它可以用于一组特定的本机方法:例如classList方法和textContent。

1 个答案:

答案 0 :(得分:1)

我的第一个冲动是建议只使用jQuery并在需要的地方扩展;)

但是要试一试:如果将my_Helper函数用作对象,它可以缓冲元素并包含在其自身上使用这些元素的函数。如果直接调用my_Helper,则可以强制它返回一个新对象。 此外,添加的功能可以返回对象本身,因此链接可以像jquery一样使用。 addClass的一个简单示例:

function my_Helper(query){
	if(this.constructor !== my_Helper)
  	 return new my_Helper(query); //if called directly (not as new()), return a new object
     
  this.elements = document.querySelectorAll(query);  
  this.addClass = function(className) {
  	for(var el of this.elements)
    	el.classList.add(className);
  	return this; //to be able to use chaining
  }
  return this;
}



my_Helper('.someClass').addClass('newClass').addClass('newClass2'); //2 separate classes to test chaining
.newClass{
  width:100px;
  height:100px;  
}

.newClass2{
  border:1px solid black;
}
<div class= 'someClass'></div>
<div class= 'someClass'></div>
<div class= 'someClass'></div>

编辑,根据评论,手动添加额外方法不会有问题,但希望在不复制foreach的情况下更轻松地添加单个方法?下面有一个通用的invoke函数,它可以从对象和辅助函数外部调用,使用这个调用来创建其他方法(并且还引入了一个简单调用addClass的classList包装器,以便更容易地迁移代码)

function my_Helper(query){
	if(this.constructor !== my_Helper)
  	 return new my_Helper(query); //if called directly (not as new()), return a new object
  
  this.elements = document.querySelectorAll(query);        
  let self = this;
  
  this.invoke = function(property , func, ...pars){
  	for(let el of self.elements){    
    	if(!func){  //no function given -> property setter
      	if(property)
        	el[property] = [pars]
      }
      else {
        let p = property ? el[property] : el; //if no property is given, use element itself
        if(!p) continue;

        let fn = p[func];
        if(!fn) continue; //function does not exist on the property or element      
        fn.apply(p,pars);
      }
    }
    return self;
  }
  
  function fn(property, functionName, ...pars){
  	return (...pars) => self.invoke(property, functionName, pars);
  }
  
  this.addClass = fn('classList', 'add');
  this.removeClass = fn('classList', 'add');
  this.text = fn('textContent');
  
  this.classList = {add:self.addClass, remove:self.removeClass}; //if classlist has to be used instead of addClass
  
  return this;
}

my_Helper('.someClass').classList.add('newClass').addClass('newClass2').text('aaa');
.newClass{
  width:100px;
  height:100px;  
}

.newClass2{
  border:1px solid black;
}
<div class= 'someClass'></div>
<div class= 'someClass'></div>
<div class= 'someClass'></div>

在这个基本实现中,invoke需要字符串,但它也可以很容易地扩展为接受函数。