是否可以使用querySelectorAll组合相同属性的元素?

时间:2016-03-19 08:55:25

标签: javascript selectors-api

出于好奇,有可能重构这个:

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

更小的东西,像这样?:

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

当然这不起作用,这就是我要问的原因。 有可能吗?

4 个答案:

答案 0 :(得分:2)

使用:any伪类;

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

现在,您需要为Chrome和Safari添加-webkit-前缀,或为Firefox添加-moz;没有IE支持。这可能最终以名称:matches标准化。请参阅MDN文档here

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

答案 1 :(得分:0)

您可以将"[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>

或者,您可以向classNamedata-*input元素添加selecttextarea属性; 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>

答案 2 :(得分:0)

:any选择器标准化之前,您可以使用辅助函数,类似于使用CSS预处理器(借用@guest271314's example):

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),而不会影响功能。

答案 3 :(得分:0)

通过使用document.body.style处的功能检测,将document.querySelcectorAll()扩展为在:any内部添加供应商前缀而不在选择器字符串中包含供应商前缀的方法。可能会在几个方面得到改善;可以添加当前需要供应商前缀的其他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/