Js селекторы: Знаете ли вы селекторы?

Содержание

Готовим селекторы в Redux / Хабр

Зачем нужны селекторы?

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

Редакс — Single-store стейт-менеджер, в котором к тому же принято группировать данные по объектам. Примерно так же, как в стейте классовых компонентов в реакте. То есть, это совершенная противоположность атомарного подхода, которому, к примеру, следуют многие хуки реакта или Multi-store стейт-менеджеры (например Effector, где селекторы не нужны по определению — достаточно сторов).

Помимо этого, объекты, которыми оперируют редьюсеры в редаксе, не являются какой-то полноценной сущностью — это просто кусок чистых данных. Противоположность — MobX, где в сторах могут быть экшны и компьютеды. Кстати, последние как раз являются заменой селекторов в MobX.

В общем, раз в редаксе нет возможностей ни эффектора, ни MobX, нам лишь остается напрямую обращаться к данным, начиная с самого верха. Это превращается в нечто вроде state.

foo.bar.baz. А если перед этим еще нужно произвести какие-то вычисления с участием других значений из стора?

Собственно по этим причинам, там и напрашивается какой-то отдельный слой, который возьмет на себя роль получения, комбинирования и преобразования данных. Этим слоем стали селекторы.

// src/features/cart/model/selectors.js
// Селектор стейта корзины покупок
export const all = state => state.cart
// Массив покупок, добавленных в корзину
export const items = state => all(state).items
// Бонусы, которые будут получены за покупку
export const collectedBonuses = state => all(state).collectedBonuses
/*
 * Суммарная стоимость покупок
 * Здесь используется функция createSelector из библиотеки reselect,
 * в данном случае она нужна чтобы не делать вычисления лишний раз
 * Подробнее такие селекторы будут рассмотрены ниже
 */
export const totalAmount = createSelector(
  items,
  items => items.reduce((acc, item) => {
    const { price, count } = item
    return acc + price * count
  }, 0)
)

Основные правила использования селекторов

Чтобы извлечь максимальную пользу от селекторов, нужно соблюдать несколько правил.

1. Не писать функции-селекторы прямо в компонентах

const Counter = () => {
  // плохо!
  const count = useSelector(state => state.counter.count)
}
Почему?
  • Если в нескольких местах нужно получить одни и те же данные — код начинает дублироваться, его становится тяжело поддерживать.

  • При каждом рендере — новая функция.
    И нет, это не относится к секте «плодить функции в компоненте плохо».
    Просто селектор будет вызываться при каждом рендере, а не только когда обновились данные в сторе.
    Вот эта логика в исходниках useSelector.

  • Логика получения данных из структуры стора находится внутри компонента.
    Но зачем компоненту знать об этом?

  • Ну и это просто-напросто неудобно.

И что делать?

Смотреть следующий пункт =)

2. Выносить селекторы в отдельный слой

Вы можете располагать этот слой в различных местах, в зависимости от используемой вами архитектуры. Но это всегда место, близкое к слайсу (редьюсеру, экшнам).

Например, при использовании методологии feature-sliced (кстати рекомендую) с чистым редаксом (а это не рекомендую) — выглядеть это будет как-то так:

features
 ┗ counter
   ┗ model
     ┣ types.js
     ┣ reducer.js
     ┣ actions.js
     ┣ selectors.js <- вот тут
     ┗ index.js

Также важно, чтобы селекторы были в отдельном файле, а не там же, где например редьюсер и прочие нерелевантные к извлечению данных вещи.

Сам файл может выглядеть так:

export const all = state => state.counter
export const count = state => all(state).count
export const step = state => all(state).step
export const nextCount = state => count(state) + step(state)
export const prevCount = state => count(state) - step(state)

Кстати, как видите, у функций нет префикса select. Об этом будет подробнее в следующем пункте.

Зачем это нужно?

Когда селекторы расположены в одном месте, мы получаем сразу массу преимуществ.

Во-первых, мы не размазываем логику получения данных из стора по куче анонимных функций, передаваемых в useSelector. Ну или по множеству mapStateToProps (если вдруг кто-то все еще использует connect =)

Соответственно, раз анонимных функций и прочих прелестей больше нет — при внесении изменений не надо ничего искать по всему проекту. К тому же у селекторов теперь есть понятные имена.

Во-вторых, селекторы становятся переиспользуемыми и инкапсулируют в себе определенную логику. Плюсы можно увидеть уже в примере выше: nextCount и prevCount уже не знают о том, как работает count и не зависят от местоположения этой части данных в сторе. А внешний код тем более не должен знать детали получения каких-то данных, особенно если стор имеет специфичную структуру.

В-третьих, раз близкие по фиче селекторы находятся в одном файле — их можно удобно использовать в соседних селекторах. Например, комбинировать или просто создавать вложенные селекторы.

3. Группировать селекторы в один объект (namespace)

Как вы помните, в примере из прошлого пункта у функций-селекторов в названии не было слова select.

Здесь тоже простая логика — зачем нам каждый раз повторяться, если можно просто объединить селекторы в один namespace? Например так:

// counter/model/index.js
export * as counterSelectors from './selectors'

Теперь, при использовании во внешнем коде, мы можем просто написать следующее:

const Counter = () => {
	const count = useSelector(counterSelectors.count)
}
Зачем это нужно?

Помимо того, что такой namespace позволяет нам без потери семантики полностью уйти от каких-либо префиксов в функциях, он так же избавляет нас от потенциальных конфликтов между именами селекторов в различных модулях.

Допустим, если бы у нас еще была фича likes, состояние которой содержит поле count — могло бы появиться 2 селектора с именем selectCount.

При чем selectCount ничего не говорит о фиче, к которой относится селектор, и поэтому в нем требуются дополнительные уточнения, и в итоге мы получаем что-то вроде selectLikesCount. С перспективы внутри фичи это выглядит странно — ведь и так из контекста понятно, что селектор относится к likes. Скорее, такое название функция должна получать на этапе реэкспорта наружу как часть публичного интерфейса модуля.

Все эти проблемы решает объединение в namespace. И это довольно важный пункт.

Из потенциальных минусов — проблемы с code splitting. Но часто ли вы видите ситуацию, что на каком-то этапе можно не загружать все селекторы? Да и вообще, как много места они займут в чанке?

4. Не использовать мемоизацию, когда она не нужна

Вы наверное знаете про библиотеку reselect.

Многие, только ознакомившись с этой библиотекой, принимаются абсолютно каждый селектор создавать через createSelector. Такой подход конечно же неправильный, и мемоизированные селекторы полезны не во всех случаях.

Иногда мемоизированные селекторы только усложнят код, замедлят его, или будут расходовать лишнюю память.

На этом пункте мы закончим с основными правилами и перейдем к видам селекторов — там я как раз объясню, как писать селекторы в различных ситуациях.

Виды селекторов

  • Мемоизированные селекторы, созданные через createSelector из reselect

  • Селекторы без мемоизации, в которых мы ручками принимаем state и возвращаем нужные данные

Мемоизированные селекторы

В редаксе нельзя подписаться на изменение конкретного кусочка данных. Изначально, можно лишь узнать о том, что «где-то что-то изменилось».

Поэтому, при совершенно любом изменении где угодно в сторе, будут вызваны все активные mapStateToProps и useSelector. Соответственно, все селекторы, которые были в них переданы, тоже будут вызваны.

Именно из этого факта вытекает необходимость в мемоизированных селекторах.

Тяжелые вычисления

Вы же не хотите, чтобы тяжелые преобразования выполнялись на каждое изменение в сторе? Например, для интернет-магазина, что насчет пересчитать корзину покупок после того, как пользователь открыл какую-нибудь модалку, состояние которой хранится глобально в редаксе?

Вот-вот =)

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

// только оплаченные элементы
const paidItems = createSelector(
  items,
  items => items.filter(filters.onlyPaid)
)
// только оплаченная сумма
const paidAmount = createSelector(
  paidItems,
  items => items.reduce(reducers.total, 0)
)
// общая сумма покупок
const totalAmount = createSelector(
  items,
  items => items.reduce(reducers.total, 0)
)
Преобразование данных и композиция
const loadingState = state => ({
  isLoading: isLoading(state),
  isLoaded: isLoaded(state),
  isFailed: isFailed(state),
})

Из-за проблемы редакса, которая была описана выше, селектор вызовется даже тогда, когда изменившиеся данные не имеют к нему никакого отношения.

Но, как видите, в примере нет никаких тяжелых вычислений. Тут важно другое — данный селектор каждый раз возвращает новый объект с новой ссылкой.

Проблемы начинаются тогда, когда от данного объекта начинают зависеть компоненты, хуки, и другие селекторы.

Почти везде сравнение происходит по ссылке:

  • useSelector и connect увидят, что результат изменился, и перерендерят компонент. И не важно, что содержимое объекта один в один равно предыдущему.

  • Другие мемоизированные селекторы увидят, что входные данные изменились, и выполнятся заново. И ладно, если эти селекторы возвращают примитивы. Но если они также возвращают объекты — это может привести к еще большей цепочке новых расчетов.

  • Хуки, зависимости которых содержат данный объект, вызовутся заново. В лучшем случае — это дополнительные расчеты, в худшем — вызов важной не идемпотентной бизнес логики.

Поэтому, используем мемоизированный селектор:

const loadingState = createSelector(
  isLoading,
  isLoaded,
  isFailed,
  (isLoading, isLoaded, isFailed) => ({
    isLoading,
    isLoaded,
    isFailed
  })
)

Возможен и другой случай:

const somePrimitive = createSelector(
  isA,
  isB,
  isC,
  (isA, isB, isC) => {
    return isA && isB && isC
  }
)

Этот селектор возвращает примитивное значение и не делает никаких тяжелых расчетов. Так что с точки зрения оптимизации нам не нужно здесь использовать 

createSelector. Более того, мемоизированный селектор будет выполнять больше вычислений и занимать больше памяти (хоть и ненамного).

А вот то же самое обычным селектором:

const somePrimitive = state => {
  return isA(state) && isB(state) && isC(state)
}

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

В таких случаях я отдаю предпочтение версии c createSelector, хоть она и уступает по производительности. В контексте всего приложения разница будет несущественная.

Обычные селекторы

const all = state => state.cart
const items = state => all(state).items
const calculation = state => all(state).calculation
const bonuses = state => calculation(state).
bonuses

Такие селекторы стоит использовать всегда, когда мы напрямую ссылаемся на данные из стора. Даже если возвращаемое значение является объектом, не стоит беспокоиться — мы лишь возвращаем ссылку на уже существующий объект, который находится в стейте, так что ни к каким проблемам это не приведет.

Мемоизированные селекторы в подобных случаях использовать не стоит — из-за проверки входных данных и сравнения их с предыдущими, такие селекторы будут медленнее (~ в 30 раз в последнем Chrome), а объем занимаемой памяти увеличится, так как предыдущие входные данные нужно где-то хранить. Проблема с памятью не очень заметна, но становится вполне ощутима, когда входными данными является объект с множеством данных.

Re-reselect — селекторы с более сложным кэшем

Многие любят создавать селекторы, принимающие пропсы.
Например, так можно вынести из компонента получение конкретного юзера по ID.

Я не топлю за подобное, но, возможно, есть случаи когда селектор не просто что-то получает по ID, а делает тяжелые расчеты — может тогда это и оправдано.

Но дело в том, что у селекторов, созданных с помощью reselect, объем кэша (сохраненных вычислений) равен 1.

Это означает, что если вы зарендерите 10 компонентов, каждый из которых вызывает один и тот же селектор с разными аргументами — мемоизация не будет работать так, как вам хотелось бы. Например, в случае со списком юзеров, селектор, при каждом его вызове, будет видеть, что ID изменился — расчет будет выполнен заново, а единственный элемент кэша будет перезаписан. Такая мемоизация, если и будет работать, то в очень редких случаях.

Для решения этой проблемы была создана библиотека re-reselect. Она позволяет создавать селекторы с более умным и вместительным кэшем.

В случае с юзерами — при вызове такого селектора с разными ID, кэш для каждого из них будет сохраняться и использоваться при следующих вызовах. Вы можете прочитать как это работает в GitHub библиотеки.

А теперь пример:

// features/user/model/selectors.js
import { createCachedSelector } from 're-reselect'
const all = state => state. users
const users = state => all(state).users
const usersById = createSelector(
  users,
  users => users.reduce((acc, user) => {
    acc[user.id] = user
    return acc
  }, {})
)
const userById = createCachedSelector(
  (_, id) => id,
  usersById,
  (usersById, id) => usersById[id] ?? null
)(
  id => id
)
// features/user/components/profile.js
const UserProfile = ({ id }) => {
  const user = useSelector(state => userSelectors.userById(state, id))
}

Упс, это что, создание нового селектора в компоненте?
Да, выше я писал о том, что не нужно так делать.

Но конкретно в этом случае я не нашел другого выхода.

Впрочем, сравнение аргументов с предыдущими — не то, чтобы очень тяжелая операция.
Но, согласитесь, все же лучше, когда код не выполняется лишний раз.

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

Немного о useSelector

Может показаться, что useSelector позволяет не использовать мемоизированные селекторы, но это не так.

Первая причина — функция, переданная внутрь, выполняется при каждом изменении в сторе. Это означает, что различные тяжелые вычисления будут в любом случае выполнены, не важно изменилась ли вообще часть данных стейта, с которой функция работает. В отличие от мемоизированных селекторов, useSelector не может сравнить входящие аргументы функции (в данном случае он всего один — state, который и не выйдет сравнить без глубокого сравнения).

Вторая причина — нельзя отказываться от удобной возможности для композиции селекторов. Как уже обсуждалось здесь, без reselect такое не сделать без боли (либо понадобится писать свой хелпер).

Чтобы предотвратить ререндер, если не изменился результат селектора, useSelector, так же как и connect, сравнивает результаты текущего и прошлого выполнения функции (в случае с connect этой функцией является mapStateToProps). Отличие в том, что по дефолту useSelector производит простое сравнение по ссылке, а connect выполняет shallowCompare (поверхностное сравнение, при котором сравнивается содержимое объектов, но только первая вложенность).

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

Причина, по которой так сделано изначально — атомарный подход при использовании хуков. Так же, как и в случае с this.state и хуком useState, вместо создания одного большого объекта мы несколько раз вызываем хуки, ответственные за определенную часть данных. Поэтому shallowCompare изначально не требуется и нужен в редких случаях.

// здесь просто сравнить не выйдет
// объект каждый раз новый, так что надо проверять содержимое
const mapStateToProps = state => ({
  one: selectors.one(state),
  two: selectors. two(state),
})
// а здесь для результатов можно использовать простое сравнение
const one = useSelector(selectors.one)
const two = useSelector(selectors.two)

То есть, при работе с useSelector, крайне нежелательно делать так:

/*
 * При совершенно любом изменении state, данный селектор будет вызван
 * А так как он каждый раз возвращает новый объект,
 * - наш компонент будет всегда ререндериться
 * Проблему можно решить с помощью передачи shallowCompare 2 аргументом,
 * - но это лишь костыль
 * Правильное решение - разбиение на несколько вызовов useSelector:
 * Первый получает one, второй - two
 *
 * (функция-селектор написана прямо в компоненте
 * только ради наглядности, не стоит так делать)
 */
useSelector(state => ({
  one: state.one,
  two: state.two
}))

Заключение

Соблюдайте основные правила
  • Выносите селекторы в отдельный слой (например на уровне модуля) и далее используйте их в остальных участках приложения.

  • Объединяйте селекторы в объект (namespace), чтобы избежать повторений кода и конфликтов имен. Лучше всего для этого подходит ре-экспорт.

  • Не рассчитывайте на useSelector в плане оптимизаций. Он лишь предотвращает ререндер, если сравнение результата через === вернуло true.

Используйте обычные селекторы без мемоизации когда:
  • Нужно просто достать значение из стора.

  • (не обязательно) Нужно сделать простую операцию между какими-то значениями, при этом результатом этой операции является примитив.

Используйте мемоизированные селекторы когда:
  • В селекторе есть тяжелые вычисления (фильтрация, сортировка, сложное преобразование данных, и так далее).

  • Результатом вызова селектора является объект. Ну и конечно же, это касается массивов и различных структур вроде Set и Map, так как они тоже являются объектами.

Используйте re-reselect когда:
Изучайте интересные вещи
  • Effector — очень крутой стейт-менеджер.
    Multi-store, декларативность, инструменты для flow-control.
    Никаких спорных вещей вроде Proxy или декораторов.

  • Feature Sliced — отличная архитектурная методология для фронтенда.

.querySelector() — JavaScript — Дока

  1. Кратко
  2. Как пишется
  3. Как понять
  4. На практике
    1. Николай Лопин советует

Кратко

Секция статьи «Кратко»

Метод определён для объекта document и любого HTML-элемента (Element) страницы. Позволяет найти элемент по CSS-селектору среди дочерних. Если элементов несколько, то вернётся первый подходящий. Если подходящих элементов нет, то вернёт null.

Как пишется

Секция статьи «Как пишется»

Метод принимает один параметр — CSS-селектор в виде строки. Если передан не CSS-селектор, то система выбросит ошибку. Например, можно выбрать первый элемент внутри <div>:

<body>  <div>    <p>      Князь Василий говорил всегда лениво, как актер говорит роль старой      пиесы.  Анна Павловна Шерер, напротив, несмотря на свои сорок лет, была      преисполнена оживления и порывов.    </p>    <p>      Быть энтузиасткой сделалось её общественным положением, и иногда, когда      ей даже того не хотелось, она, чтобы не обмануть ожиданий людей, знавших      её, делалась энтузиасткой. Сдержанная улыбка, игравшая постоянно на лице      Анны Павловны, хотя и не шла к её отжившим чертам, выражала, как у      избалованных детей, постоянное сознание своего милого недостатка, от      которого она не хочет, не может и не находит нужным исправляться.    </p>  </div>  <p>Это параграф, дочерний для body</p>  <script>    const firstParagraph = document.querySelector('div > p')    console.log(firstParagraph.textContent)    // напечатает текст, начинающийся с 'Князь Василий'    // ищем несуществующий элемент    const spanFromBody = document.querySelector('span')    console.log(spanFromBody)    // null  </script></body>
          <body>
  <div>
    <p>
      Князь Василий говорил всегда лениво, как актер говорит роль старой
      пиесы.  Анна Павловна Шерер, напротив, несмотря на свои сорок лет, была
      преисполнена оживления и порывов.
    </p>
    <p>
      Быть энтузиасткой сделалось её общественным положением, и иногда, когда
      ей даже того не хотелось, она, чтобы не обмануть ожиданий людей, знавших
      её, делалась энтузиасткой. Сдержанная улыбка, игравшая постоянно на лице
      Анны Павловны, хотя и не шла к её отжившим чертам, выражала, как у
      избалованных детей, постоянное сознание своего милого недостатка, от
      которого она не хочет, не может и не находит нужным исправляться.
    </p>
  </div>
  <p>Это параграф, дочерний для body</p>
  <script>
    const firstParagraph = document.querySelector('div > p')
    console.log(firstParagraph.textContent)
    // напечатает текст, начинающийся с 'Князь Василий'
    // ищем несуществующий элемент
    const spanFromBody = document.querySelector('span')
    console.log(spanFromBody)
    // null
  </script>
</body>

Динамический пример, введите селектор в поле поиска и нажмите «Искать»:

Открыть демо в новой вкладке

Как понять

Секция статьи «Как понять»

Метод работает с DOM, который связан с HTML-разметкой. Каждый HTML-элемент имеет родительские и дочерние элементы:

  • Родители — это элементы, которые содержат текущий элемент. В примере выше у первого элемента <p> есть два родительских элемента — <div> и <body>.
  • Дочерние элементы — это элементы, которые содержит текущий элемент. Они могут быть, а могут не быть. Например, для тега <body> все элементы страницы дочерние. У <p> дочерний элемент — текст внутри тега.

Если вы работаете с корнем страницы, объектом document, то поиск идёт по всем элементам страницы (от <body>), если от конкретного элемента, то поиск идёт только по всем дочерним.

На практике

Секция статьи «На практике»

Николай Лопин советует

Секция статьи «Николай Лопин советует»

🛠 Для поиска первого элемента в DOM нужно передать строку '*' аргументом querySelector(), её называют wildcard.

Если вы нашли ошибку, отправьте нам пул-реквест!

Во время отправки формы что-то пошло не так. Попробуйте ещё раз?

.getElementsByTagName()

alt +

.querySelectorAll()

alt +

Селекторы W3.JS

❮ Назад Далее ❯


Селекторы W3.JS

W3.JS выбирает элементов HTML и выполняет действий над выбранными элементами:

w3. действие ( селектор )

  • Действие () выполняется на выбранных элементах
  • ( селектор ) выбирает элемент(ы) HTML

Пример

w3.hide(‘p’)  // Скрыть все элементы

Попробуй сам » С помощью CSS »

Знакомы ли вы с селекторами CSS?

W3. JS использует синтаксис CSS для выбора элементов HTML и управления ими.

Селекторы используются для «поиска» (выбора) HTML-элементов на основе имени их тега, id, классы, типы, атрибуты, значения атрибутов и многое другое. Список все селекторы можно найти в нашем селекторе CSS Ссылка.


Примеры селекторов

Чтобы выбрать элементы HTML, используйте имя тега:

Скрыть все элементы

:

w3.hide(‘h3’)

Попробуй сам »

Чтобы выбрать элемент с определенным идентификатором, напишите символ решетки, а затем идентификатор HTML-элемента:

Скройте элемент с помощью:

w3.hide(‘#London’)

Попробуй сам »

Чтобы выбрать элементы с определенным классом, напишите символ точки, а затем имя класса:

Скрыть все элементы с помощью:

w3.hide(‘.city’)

Попробуй сам »


Дополнительные примеры селекторов

Селектор Описание Пример
(«*») Выбирает все элементы в документе Попробуйте
(этот) Выбирает текущий элемент HTML Попробуйте
(«вступление») Выбирает все элементы

с

Попробуйте
(«дел п») Выбирает все элементы

внутри всех элементов

Попробуйте
(«дел p:первый-потомок») Выбирает первый элемент

внутри всех элементов

Попробуйте
(«[ссылка]») Выбирает все элементы с атрибутом href Попробуйте
(«а[цель=_пусто]») Выбирает все элементы со значением целевого атрибута, равным «_blank» Попробуйте
(«p:nth-ребенок(четный)») Выбирает все четные элементы

Попробуйте

Полную информацию обо всех селекторах CSS см. в нашем Справочнике по селекторам CSS.

❮ Предыдущий Далее ❯


НОВИНКА

Мы только что запустили
Видео W3Schools

Узнать

ВЫБОР ЦВЕТА
КОД ИГРЫ

Играть в игру




Лучшие учебники
Учебник HTML
Учебник CSS
Учебник JavaScript
Учебник How To
Учебник SQL
Учебник Python
Учебник W3.CSS
Учебник Bootstrap
Учебник PHP
Учебник Java
Учебник C++
Учебник jQuery

900 Справочник Справочник по HTML
Справочник по CSS
Справочник по JavaScript
Справочник по SQL
Справочник по Python
Справочник по W3.CSS
Справочник по Bootstrap
Справочник по PHP
Цвета HTML
Справочник по Java
Справочник по Angular
Справочник по jQuery

Основные примеры
Примеры HTML
Примеры CSS
Примеры JavaScript
Примеры инструкций
Примеры SQL
Примеры Python
Примеры W3. CSS
Примеры Bootstrap
Примеры PHP
Примеры Java
Примеры XML
Примеры jQuery

О

W3Schools оптимизирован для обучения и обучения. Примеры могут быть упрощены для улучшения чтения и обучения. Учебники, ссылки и примеры постоянно пересматриваются, чтобы избежать ошибок, но мы не можем гарантировать полную правильность всего содержания. Используя W3Schools, вы соглашаетесь прочитать и принять наши условия использования, куки-файлы и политика конфиденциальности.

Copyright 1999-2022 Refsnes Data. Все права защищены.
W3Schools использует W3.CSS.

Использование селекторов CSS в Javascript

В CSS селекторы — это шаблоны, используемые для выбора элементов, которые вы хотите стилизовать, но, как видно из заголовка выше, селекторы также полезны в javascript, и ниже приведены некоторые примеры как их использовать.

Основы

Использование селектора в javascript
  • Используйте . querySelector метод
 const div = document.querySelector("div") // => Первое появление элемента div в документе
const p = div.querySelector("p") // => Первое вхождение элемента p в div
 
Войти в полноэкранный режимВыйти из полноэкранного режима
  • Чтобы получить все совпадающие элементы, используйте метод document.querySelectorAll
 document.querySelectorAll("div") // Список узлов всех элементов div
 
Войти в полноэкранный режимВыйти из полноэкранного режима
По идентификаторам

Чтобы получить элемент по его идентификатору, используйте # перед идентификатором элемента

 document.querySelector("#id") // => document.getElementById('id')
 
Войти в полноэкранный режимВыйти из полноэкранного режима
По классам

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

 document.querySelectorAll(". myElementClass")
 
Войти в полноэкранный режимВыйти из полноэкранного режима
По имени тега

Чтобы получить элементы по имени тега, просто введите имя тега

 document.querySelectorAll("body") // => document.getElementsByTagName('body')
 
Войти в полноэкранный режимВыйти из полноэкранного режима
Репликация
.getElementById и getElementsByTagName
  • Репликация .getElementById
 document.querySelector("#myDivId") // => document.getElementById('myDivId')
 
Войти в полноэкранный режимВыйти из полноэкранного режима
  • Репликация .getElementsByTagName
 document.querySelectorAll("a") // => document.getElementsByTagName('a')
 
Войти в полноэкранный режимВыйти из полноэкранного режима
Все элементы

Чтобы получить все элементы, используйте *

 document.querySelectorAll("*") // => NodeList[. ..]
 
Войти в полноэкранный режимВыйти из полноэкранного режима
Использование нескольких селекторов

Чтобы использовать несколько селекторов, мы разделяем каждый из них цифрой 9.0236, .

 
    <тело>
        

Привет, я абзац

Привет, я ссылка Я еще одна ссылка
Войти в полноэкранный режимВыйти из полноэкранного режима
 document.querySelectorAll("p, a") // => NodeList[p,a,a]
 
Войти в полноэкранный режимВыйти из полноэкранного режима

Еще с элементами

В приведенных выше примерах мы сделали базовые запросы, но можно делать и другие вещи, например, получать элементы по порядку или по родителю.

Получение дочерних элементов

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

 
    <тело>
        

Привет, я абзац

<дел> Привет, я ссылка <р> Привет, я абзац, и вот ссылка

Войти в полноэкранный режимВыйти из полноэкранного режима

На приведенном выше HTML-коде в качестве примера мы рассмотрим эти два варианта.

  • Прямой ребенок
 document.querySelector("div > a") // => Эй, я ссылка
 
Войти в полноэкранный режимВыйти из полноэкранного режима
  • Все дети
 document.querySelectorAll("div a") // => NodeList[a,a]
 
Войти в полноэкранный режимВыйти из полноэкранного режима
Получение элементов по порядку

Это также можно сделать двумя способами. Рассмотрим следующий HTML.

 
    <тело>
        <дел>
             com">Привет, я ссылка
            
Я должен вмешаться, но не буду

Привет, я еще один абзац

Привет, я абзац

Войти в полноэкранный режимВыйти из полноэкранного режима
  • Размещается после
 document.querySelector("div + p") // => 

Привет, я абзац

Войти в полноэкранный режимВыйти из полноэкранного режима
  • Предшественник

Для ~ не имеет значения, какой элемент находится сразу за совпадением.

 document.querySelector("a ~ p") // => 

Привет, я еще один абзац

Войдите в полноэкранный режимВыйдите из полноэкранного режима

и мы увидим, что pre 9Элемент 0237 не повлиял на результат, потому что не имеет значения, был ли там до . Но следующий селектор потерпит неудачу, потому что он проверяет элемент непосредственно над ним.

 document.querySelector("a + p") // => ноль
 
Войти в полноэкранный режимВыйти из полноэкранного режима

Получение элементов по атрибуту

Селектор атрибутов начинается с [ и заканчивается ] и используется как таковой

 
    <тело>
        

Привет, я в стиле

Привет, у меня нет стиля

Войти в полноэкранный режимВыйти из полноэкранного режима
 document. querySelector("p[style]") // => 

Привет, я в стиле

Войти в полноэкранный режимВыйти из полноэкранного режима
Проверить значение атрибута

Для проверки значения атрибута используется символ = .

 
    <тело>
        Привет, я ссылка
        Я еще одна ссылка
    

 9="https://awesome"]') // => Эй, я ссылка
 
Войти в полноэкранный режимВыйти из полноэкранного режима
  • Проверить, заканчивается ли атрибут на...
 document.querySelectorAll('a[href$=".com"]') // => NodeList[a,a]
 
Войти в полноэкранный режимВыйти из полноэкранного режима
  • Проверить, содержит ли атрибут подстроку
 document.querySelectorAll('a[href*="place"]') // => NodeList[a,a]
 
Войти в полноэкранный режимВыйти из полноэкранного режима 902:30 Расширенные селекторы
  • :фокус

Выбирает элемент, который в данный момент находится в фокусе

  • :visited

Используется с тегами и и выбирает ссылки, которые были посещены

  • :ссылка

Это также используется с тегами и , но в этом случае выбираются ссылки, которые не посещались

  • :enabled

Это выбирает элементы, которые включены ( не отключено )

 
    <тело>
        

Я абзац

Я другой абзац

com">Привет, я ссылка Я еще одна ссылка
Войти в полноэкранный режимВыйти из полноэкранного режима
 document.querySelectorAll(":enabled") // => NodeList[p,p,a,a]
 
Войти в полноэкранный режимВыйти из полноэкранного режима
  • :отключено

Выбирает элементы, которые были отключены

 
    <тело>
        

Я абзац

Я другой абзац

Привет, я ссылка Я еще одна ссылка
Войти в полноэкранный режимВыйти из полноэкранного режима
 document.querySelector(":disabled") // => 
 
Войти в полноэкранный режимВыйти из полноэкранного режима
  • :first-child

Это выбирает элемент, который является первым дочерним элементом его родителя

 
    <тело>
        

Я абзац

Я другой абзац

com">Привет, я ссылка Я еще одна ссылка
Войти в полноэкранный режимВыйти из полноэкранного режима
 document.querySelector("p:first-child") // => 

Я абзац

Войти в полноэкранный режимВыйти из полноэкранного режима
  • :последний ребенок

Это выбирает элемент, который является последним дочерним элементом его родителя

 
    <тело>
        

Я абзац

Я другой абзац

Привет, я ссылка Я еще одна ссылка
Войти в полноэкранный режимВыйти из полноэкранного режима
 document.querySelector("p:last-child") // => Я другая ссылка
 
Войти в полноэкранный режимВыйти из полноэкранного режима
  • el :первый тип

Выбирает элемент, который является первым дочерним элементом своего родителя и имеет тот же тип, что и el

 
    <тело>
        

Я абзац

com">Привет, я ссылка

Я другой абзац

Я еще одна ссылка
Войти в полноэкранный режимВыйти из полноэкранного режима
 document.querySelector("a:first-of-type") // => Эй, я ссылка
 
Войти в полноэкранный режимВыйти из полноэкранного режима
  • el :последний тип

Выбирает элемент, который является последним дочерним элементом своего родителя и имеет тот же тип, что и el

 
    <тело>
        

Я абзац

Привет, я ссылка

Я другой абзац

Я еще одна ссылка
Войти в полноэкранный режимВыйти из полноэкранного режима
 document.querySelector("p:last-of-type") // => 

Я другой абзац

Войти в полноэкранный режимВыйти из полноэкранного режима
  • :not( selector )

Это выбирает элементы, которые не соответствуют селектору

 
    <тело>
        

Я абзац

com">Привет, я ссылка Я еще одна ссылка
Войти в полноэкранный режимВыйти из полноэкранного режима
 document.querySelector(":not(a)") // => 

Я абзац

Войти в полноэкранный режимВыйти из полноэкранного режима
  • :nth-child( n )

Выбирает элемент, который является n -м дочерним элементом своего родителя.

 
    <тело>
        <дел>
            

Я абзац

Привет, я ссылка Я еще одна ссылка
Войти в полноэкранный режимВыйти из полноэкранного режима
 document.querySelector("div:nth-child(2)") // => Эй, я ссылка
 
Войти в полноэкранный режимВыйти из полноэкранного режима
  • :nth-last-child( n )

Это выбирает элемент, который является n -м до последнего дочернего элемента его родителя.

 
    <тело>
        <дел>
            

Я абзац

Привет, я ссылка Я еще одна ссылка