【问题标题】:Generic class addition using querySelectorAll / classList without having to constantly loop使用 querySelectorAll / classList 添加通用类,无需不断循环
【发布时间】:2017-05-29 12:36:59
【问题描述】:

我正面临以下问题。

每次我必须使用querySelectorAllElement.classList 时,我都需要

  1. Element.querySelectorAll返回的NodeList转换为数组
  2. 对数组执行 forEach 以分别操作每个项目。

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,将其转换为数组,forEach 数组并 * 执行用户给出的方法。

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

【问题讨论】:

  • 你想用纯 JavaScript 实现 jQuery 的 addClassremoveClass 方法,对吗?
  • 是的,但我想对 querySelectorAll 每次返回的 NodeList 进行抽象循环..
  • @Kaiido 这是我想在内部使用的东西,所以如果该方法不存在,它应该什么都不做或返回 false .. 我可以通过调用或仅使用 [... nodelist] 但我想完全隐藏循环
  • 除了在新对象中递归地重写 Element 的所有属性之外,我没有看到其他方法。但是你仍然需要定义 getter 是如何工作的。例如,在您的 myhelper('.someClass').classList.add() 中,如果您停在 .classList 会发生什么?
  • 好问题。我想我会选择一个更简单的解决方案!

标签: javascript jquery arrays selectors-api


【解决方案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>

edit,根据评论,手动添加额外的方法不会有问题,但是希望在不复制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>

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

【讨论】:

  • 感谢您的努力,如果没有其他问题,我会将其标记为正确,尽管我看到我们需要为每种方法执行 for(或 forEach).. 我只是想知道是否有可能使该方法成为将在内部传递的参数,并且实际上对于所有内容只有一种方法,否则我想这非常简单
  • 我明白你的意思。实施仍然需要为每个重复。添加了一个示例以包含更通用的方法。它只公开你自己添加的方法,但添加这样的方法就像this.text = fn('textContent');this.addClass = fn('classList', 'add'); 一样简单
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-30
  • 1970-01-01
  • 2022-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多