Можно ли объединить элементы для одинаковых атрибутов с querySelectorAll?

Из любопытства, было бы возможно рефакторинг это:

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

к чему-то меньшему, вот так?

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

Конечно, это не работает, поэтому я спрашиваю. Является ли это возможным?

4 ответа

Использование :any Псевдо-класс;

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

Прямо сейчас вам нужно добавить префикс -webkit- для Chrome и Safari, или -moz для Firefox; нет поддержки IE. Это, вероятно, будет стандартизировано в конце концов под названием :matches, Смотрите документацию MDN здесь.

Однако управление элементами DOM через их идентификаторы, как если бы они назывались переменными в каком-то гигантском глобальном пространстве имен, является анти-паттерном. Весьма вероятно, что есть более эффективные способы поиска и отслеживания элементов, чем назначать связку идентификаторов здесь, в вашем коде, а затем делать 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>

в качестве альтернативы, вы можете добавить className или data-* приписывать input, select, textarea элементы; 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() хотя и не так кратко, как использование уникального className или же data-* атрибут, аналогичный шаблону, описанному в 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>

Подход, расширяющий 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/

До :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) без ущерба для функциональности.

Другие вопросы по тегам