Как сделать селектор для прямого потомка узла root? - PullRequest
0 голосов
/ 09 января 2020

Учтите, что вам дан узел node, и вы должны предоставить всех прямых потомков, указанных селектором Direct. Селектор для прямого дочернего элемента:

childParent > directChild

Однако в консоли возникает ошибка:

document.body.querySelectorAll(">div")
SyntaxError: '>div' is not a valid selector

У меня есть функция, которая должна что-то делать на выбранных прямых дочерних узлах, но я не уверен, как справиться с этим. За исключением, конечно, использования for l oop и анализа детей с помощью моего собственного кода, полностью отбрасывающего селекторы.

Следующий код не работает. Можно ли изменить его так, чтобы он делал то, что задумано?

function doWithDirectChildren(parentNode) {
    // does not work, the selector is invalid
    const children = parentNode.querySelector(">.shouldBeAffected");
    for(const direct of children) {
        // do something with the direct child
    }
}

Я прошу решение, а не обходной путь.

Ответы [ 3 ]

2 голосов
/ 09 января 2020

Это просто неверный селектор CSS:

> .shouldBeAffected {
    border: none;
}

Это означает, что вы не сможете использовать querySelector или querySelectorAll от прямого родителя. Но следующая функция принимает только селектор '.shouldBeAffected' и родительский элемент и возвращает всех прямых потомков, соответствующих селектору:

const directChildren = (element, selector) => (
    [...element.children].filter((child) => child.matches(selector))
);

// test run: get all divs with class child that are a direct child of `parent`

const parent = document.getElementById('parent');
console.log(directChildren(parent, 'div.child'));
<div id="parent">
    <div class="child">yes</div>
    <span class="child">no</span>
    <button class="child">no</button>
    <div class="child">
        yes
        <div class="child child--fake">NO!</div>
    </div>
</div>

Теперь ваша функция может быть изменена следующим образом, чтобы она работала.

function doWithDirectChildren(parentNode) {
    const children = directChildren(parentNode, ".shouldBeAffected");
    for(const direct of children) {
        // do something with the direct child
    }
}

Редактировать

Из комментариев мы можем сделать еще один шаг и создать функции querySelectorChild и querySelectorChildren в качестве эквивалентов querySelector и querySelectorAll соответственно:

/**
 * Get the first direct child of `element` that matches `selector`
 */
const querySelectorChild = (element, selector) => (
    Array.from(element.children).find((child) => child.matches(selector))
);

/**
 * Get all direct children of `element` that match `selector`
 */
const querySelectorChildren = (element, selector) => (
    Array.from(element.children).filter((child) => child.matches(selector))
);
0 голосов
/ 09 января 2020

дочерний комбинатор оператор > является бинарным оператором, поэтому использование его без левого поля недопустимо.

Дочерний комбинатор (>) находится между два CSS селектора. Он соответствует только тем элементам, которые соответствуют второму селектору, которые являются прямыми потомками элементов, соответствующих первому.

Если вы можете предоставить отдельные селекторы parent и child, вы можете сделать что-то простое, например: this

let directChildren = (parent, child) => document.querySelectorAll(`${parent} > ${child}`);
directChildren('body','div');//...

Если ваш родительский аргумент является узлом или коллекцией, вы должны будете использовать метод преобразования его обратно в селектор, такой, как этот

0 голосов
/ 09 января 2020

jQuery решает эту проблему двумя способами. Рассмотрим этот код:

$('div.root').find('> .p2').addClass('highlighted');
$('div.root').children('.p2').addClass('red');
.highlighted {
  background: yellow
}

.red {
  color: red
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="root">
  <p>div 1</p>
  <p class="p2">paragraph 2</p>
  <p>paragraph 3</p>
  
  <div>
    <p class="p2">paragraph 2 2</p>
  </div>
</div>

с использованием .find('> selector) находит только прямые потомки, соответствующие селектору, а использование .children('selector') также делает то же самое.

...