使用 querySelectorAll / classList 的通用 class 添加,无需不断循环
Generic class addition using querySelectorAll / classList without having to constantly loop
我面临以下问题。
每次我必须使用querySelectorAll with Element.classList,我需要
- 将从
Element.querySelectorAll
返回的 NodeList 转换为 Array
- 对 Array 执行 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。
我的第一反应是建议只使用 jQuery 并在需要的地方扩展 ;)
但试一试:如果 my_Helper
函数用作对象,它可以缓冲元素并包含在其自身上使用这些元素的函数。如果直接调用my_Helper,可以强制return一个新的对象。
此外,添加的功能可以 return 对象本身,因此可以像在 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>
在这个基本实现中,调用需要字符串,但它也可以很容易地扩展为接受函数。
我面临以下问题。
每次我必须使用querySelectorAll with Element.classList,我需要
- 将从
Element.querySelectorAll
返回的 NodeList 转换为 Array - 对 Array 执行 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。
我的第一反应是建议只使用 jQuery 并在需要的地方扩展 ;)
但试一试:如果 my_Helper
函数用作对象,它可以缓冲元素并包含在其自身上使用这些元素的函数。如果直接调用my_Helper,可以强制return一个新的对象。
此外,添加的功能可以 return 对象本身,因此可以像在 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>
在这个基本实现中,调用需要字符串,但它也可以很容易地扩展为接受函数。