是否可以将相同属性的元素与 querySelectorAll 组合在一起

is it possible to combine elements for the same attributes with querySelectorAll?

本文关键字:元素 querySelectorAll 组合 在一起 属性 是否      更新时间:2023-09-26

出于好奇,是否有可能重构它:

document.querySelectorAll('input[id^=' + tagId + '],select[id^=' + tagId + '],textarea[id^=' + tagId + ']');

到更小的东西,像这样?

document.querySelectorAll('(input|select|textarea)[id^=' + tagId + ']');

当然这行不通,这就是我问的原因。可能吗?

使用伪类:any;

document.querySelectorAll('[id^=' + tagId + ']:-webkit-any(input, textarea, select)');

现在,您需要在Chrome和Safari上加上-webkit-前缀,或者为Firefox添加-moz前缀;不支持IE。这很可能最终以:matches的名称进行标准化。请参阅此处的 MDN 文档。

但是,通过 DOM 元素的 ID 来管理 DOM 元素,就好像它们是某个巨型全局命名空间中的命名变量一样,是一种反模式。很可能有更好的方法来查找和跟踪元素,而不是在代码中分配一堆 ID,然后每次转身时都在那里执行getElementById或等效操作以再次找到它,更不用说做相当于通配符的搜索了。

您可以将

"[id^=" + tagId + "]":not(/* element */):not(/* element */)一起使用

var tagId = "abc";
var elems = document.querySelectorAll("[id^=" + tagId + "]:not(div):not(p)");
console.log(elems)
<input id="abc-1"> 
<select id="abc-2"></select>
<textarea id="abc-3"></textarea>
<div id="abc-4"></div>
<p id="abc-5"></p>

或者,您可以向inputselecttextarea元素添加classNamedata-*属性;data-*属性不需要名称或值;仅用于选择过滤;然后可以使用document.querySelectorAll("[id^=" + tagId + "][data-_]");或更简短的document.querySelectorAll("[data-_]")

var tagId = "abc";
var elems = document.querySelectorAll("[id^=" + tagId + "][data-_]");
console.log(elems, elems[0].dataset)
<input id="abc-1" data-_> 
<select id="abc-2" data-_></select>
<textarea id="abc-3" data-_></textarea>
<div id="abc-4"></div>
<p id="abc-5"></p>

一种使用Array.prototype.filter()的方法,虽然不像使用唯一的classNamedata-*属性那么简短,类似于OP中描述的模式

var tagId = "abc";
var elems = [].filter.call(document.querySelectorAll("[id^=" + tagId + "]")
            , function(el) {
                return /input|select|textarea/i.test(el.tagName)
            });
console.log(elems)
<input id="abc-1"> 
<select id="abc-2"></select>
<textarea id="abc-3"></textarea>
<div id="abc-4"></div>
<p id="abc-5"></p>

:any选择器标准化之前,您可以使用帮助程序函数,类似于使用 CSS 预处理器(借用@guest271314的示例):

function makeSelector(tagId, elements) {
  return elements.map(function(el) {
    return el + '[id^=' + tagId + ']';
  }).join(',');
}
var selector = makeSelector('abc', ['input','select','textarea']);
console.log(document.querySelectorAll(selector));
<input id="abc-1"> 
<select id="abc-2"></select>
<textarea id="abc-3"></textarea>
<div id="abc-4"></div>
<p id="abc-5"></p>

然后,您可以在以后交换帮助程序实现

(例如,使用:any )交换帮助程序实现,而不会影响功能。

一种扩展document.querySelcectorAll()的方法,通过在:any处使用功能检测,在选择器字符串中不包含供应商前缀document.body.style。也许可以通过多种方式进行改进;可以添加当前需要供应商前缀的其他css选择器,多个if语句可以更彻底或更短;和其他改进

originalQuerySelectorAll = document.querySelectorAll;
console.log(originalQuerySelectorAll);
document.querySelectorAll = function() {
  var selector = arguments[0];
  if (/':any/.test(selector)) {
      if ("webkitAnimation" in document.body.style) {
        selector = selector.replace(/':(any)/g, ":-webkit-$1");
      }
      if ("MozAnimation" in document.body.style) {
        selector = selector.replace(/':(any)/g, ":-moz-$1");
      }
  }
  return originalQuerySelectorAll.call(document, selector)
}
var tagId = "abc";
var elems = document.querySelectorAll("[id^=" + tagId + "]:any(input, select, textarea)");
console.log(elems)
<input id="abc-1"> 
<select id="abc-2"></select>
<textarea id="abc-3"></textarea>
<div id="abc-4"></div>
<p id="abc-5"></p>

JSFIDDLE https://jsfiddle.net/0xpu1bvw/