Element.classlist
Содержание:
reduce/reduceRight
Метод «arr.reduce(callback)» используется для последовательной обработки каждого элемента массива с сохранением промежуточного результата.
Это один из самых сложных методов для работы с массивами. Но его стоит освоить, потому что временами с его помощью можно в несколько строк решить задачу, которая иначе потребовала бы в разы больше места и времени.
Метод используется для вычисления на основе массива какого-либо единого значения, иначе говорят «для свёртки массива». Чуть далее мы разберём пример для вычисления суммы.
Он применяет функцию по очереди к каждому элементу массива слева направо, сохраняя при этом промежуточный результат.
Аргументы функции :
- – последний результат вызова функции, он же «промежуточный результат».
- – текущий элемент массива, элементы перебираются по очереди слева-направо.
- – номер текущего элемента.
- – обрабатываемый массив.
Кроме , методу можно передать «начальное значение» – аргумент . Если он есть, то на первом вызове значение будет равно , а если у нет второго аргумента, то оно равно первому элементу массива, а перебор начинается со второго.
Проще всего понять работу метода на примере.
Например, в качестве «свёртки» мы хотим получить сумму всех элементов массива.
Вот решение в одну строку:
Разберём, что в нём происходит.
При первом запуске – исходное значение, с которого начинаются вычисления, равно нулю (второй аргумент ).
Сначала анонимная функция вызывается с этим начальным значением и первым элементом массива, результат запоминается и передаётся в следующий вызов, уже со вторым аргументом массива, затем новое значение участвует в вычислениях с третьим аргументом и так далее.
Поток вычислений получается такой
В виде таблицы где каждая строка – вызов функции на очередном элементе массива:
результат | |||
---|---|---|---|
первый вызов | |||
второй вызов | |||
третий вызов | |||
четвёртый вызов | |||
пятый вызов |
Как видно, результат предыдущего вызова передаётся в первый аргумент следующего.
Кстати, полный набор аргументов функции для включает в себя , то есть номер текущего вызова и весь массив , но здесь в них нет нужды.
Посмотрим, что будет, если не указать в вызове :
Результат – точно такой же! Это потому, что при отсутствии в качестве первого значения берётся первый элемент массива, а перебор стартует со второго.
Таблица вычислений будет такая же, за вычетом первой строки.
Метод arr.reduceRight работает аналогично, но идёт по массиву справа-налево.
Вычисленные стили: getComputedStyle
Итак, изменить стиль очень просто. Но как его прочитать?
Например, мы хотим знать размер, отступы, цвет элемента. Как это сделать?
Свойство оперирует только значением атрибута , без учёта CSS-каскада.
Поэтому, используя , мы не можем прочитать ничего, что приходит из классов CSS.
Например, здесь не может видеть отступы:
…Но что, если нам нужно, скажем, увеличить отступ на ? Для начала нужно его текущее значение получить.
Для этого есть метод: .
Синтаксис:
- element
- Элемент, значения для которого нужно получить
- pseudo
- Указывается, если нужен стиль псевдоэлемента, например . Пустая строка или отсутствие аргумента означают сам элемент.
Результат вызова – объект со стилями, похожий на , но с учётом всех CSS-классов.
Например:
Вычисленное (computed) и окончательное (resolved) значения
Есть две концепции в :
- Вычисленное (computed) значение – это то, которое получено после применения всех CSS-правил и CSS-наследования. Например, или .
- Окончательное () значение – непосредственно применяемое к элементу. Значения или являются относительными. Браузер берёт вычисленное значение и делает все единицы измерения фиксированными и абсолютными, например, или . Для геометрических свойств разрешённые значения могут иметь плавающую точку, например, .
Давным-давно был создан для получения вычисленных значений, но оказалось, что окончательные значения гораздо удобнее, и стандарт изменился.
Так что, в настоящее время фактически возвращает окончательное значение свойства, для геометрии оно обычно в пикселях.
требует полное свойство!
Для правильного получения значения нужно указать точное свойство. Например: , , . При обращении к сокращённому: , , – правильный результат не гарантируется.
Например, если есть свойства , то что мы получим вызывая ? Ничего, или, может быть, «сгенерированное» значение из известных внутренних отступов? Стандарта для этого нет.
Есть и другие несоответствия. Например, некоторые браузеры (Chrome) отображают в документе ниже, а некоторые (Firefox) – нет:
Стили, применяемые к посещённым ссылкам, скрываются!
Посещённые ссылки могут быть окрашены с помощью псевдокласса .
Но не даёт доступ к этой информации, чтобы произвольная страница не могла определить, посещал ли пользователь ту или иную ссылку, проверив стили.
JavaScript не видит стили, применяемые с помощью . Кроме того, в CSS есть ограничение, которое запрещает в целях безопасности применять к CSS-стили, изменяющие геометрию элемента. Это гарантирует, что нет обходного пути для «злой» страницы проверить, была ли ссылка посещена и, следовательно, нарушить конфиденциальность.
Стили элемента
В DOM у каждого элемента есть свойство , с помощью которого мы можем управлять его стилями. Значение данного свойства — это объект, который доступен только для чтения. Установка стилей элементу в этом случае осуществляется посредством добавления к нему соответствующих свойств.
Пример, как можно к элементу добавить стили через DOM-свойство :
<div class="square">Квадрат</div> <script> const square = document.querySelector('.square'); square.style.width = '170px'; square.style.height = '170px'; square.style.backgroundColor = 'green'; </script>
Имена свойств объекта обычно совпадают с названиями CSS-свойств. Исключение составляют только те CSS-свойства, в которых используется дефис. Например, . В этом случае дефис и следующая за ним буква заменяется на прописную. Например, CSS-свойство для объекта будет указывать как . А, например, CSS-свойство с браузерным префиксом — как .
Удаление стилей
Например, установим некоторый цвет фона:
document.body.style.backgroundColor = '#eee';
Если теперь данный стиль нужно убрать, то чтобы это выполнить мы должны просто присвоить ему пустую строку:
document.body.style.backgroundColor = '';
Примеры использования DOM-свойства style для установки стилей элементам.
<p id="introtext" style="font-weigth: bold;">...</p> <p>...</p> <p>...</p> <script> // установим элементу с id = "introtext" с использованием style красный цвет текста document.querySelector('#introtext').style.color = 'red'; // установим всем элементам p на странице с использованием style зелёный цвет текста var paragraphs = document.querySelectorAll("p"); for (var i = 0, length = paragraphs.length; i < length; i++) { paragraphs.style.backgroundColor = 'green'; } // выведем в консоль все CSS свойства элемента с идентификатором "introtext" var styleElem = document.querySelector('#introtext').style; for (var i = 0, length = styleElem.length; i < length; i++) { console.log(styleElem); } </script>
Свойство cssText
Кроме индивидуального установления стилей элементу мы можем установить их сразу с помощью специального свойства . Осуществляется это посредством присваивания этому свойству строки, состоящей из набора стилей, разделённых между собой с помощью точки с запятой. Т.е. выполняется это аналогично тому, как мы устанавливаем стили в HTML-атрибуте .
Пример, в котором установим стили элементам с классом :
Примеры
Пример: добавляем или удаляем класс ‘highlight’ при клике.
<!DOCTYPE html> <html> <head> <style> p { margin: 4px; font-size:16px; font-weight:bolder; cursor:pointer; } .blue { color:blue; } .highlight { background:yellow; } </style> <script src="http://code.jquery.com/jquery-1.9.1.js"></script> </head> <body> <p class="blue">Click to toggle</p> <p class="blue highlight">highlight</p> <p class="blue">on these</p> <p class="blue">paragraphs</p> <script> $("p").click(function () { $(this).toggleClass("highlight"); }); </script> </body> </html>
Демо
Пример: добавляем класс «highlight» при каждом третьем клике; удалить при каждом втором.
<!DOCTYPE html> <html> <head> <style> p { margin: 4px; font-size:16px; font-weight:bolder; cursor:pointer; } .blue { color:blue; } .highlight { background:red; } </style> <script src="http://code.jquery.com/jquery-1.9.1.js"></script> </head> <body> <p class="blue">Click to toggle (<span>clicks: 0</span>)</p> <p class="blue highlight">highlight (<span>clicks: 0</span>)</p> <p class="blue">on these (<span>clicks: 0</span>)</p> <p class="blue">paragraphs (<span>clicks: 0</span>)</p> <script> var count = 0; $("p").each(function() { var $thisParagraph = $(this); var count = 0; $thisParagraph.click(function() { count++; $thisParagraph.find("span").text('clicks: ' + count); $thisParagraph.toggleClass("highlight", count % 3 == 0); }); }); </script> </body> </html>
Демо
Пример: добавляем/удаляем классы к элементам div в зависимости от нажатых кнопок.
<!DOCTYPE html> <html> <head> <style> .wrap > div { float: left; width: 100px; margin: 1em 1em 0 0; padding=left: 3px; border: 1px solid #abc; } div.a { background-color: aqua; } div.b { background-color: burlywood; } div.c { background-color: cornsilk; } </style> <script src="http://code.jquery.com/jquery-1.9.1.js"></script> </head> <body> <div class="buttons"> <button>toggle</button> <button class="a">toggle a</button> <button class="a b">toggle a b</button> <button class="a b c">toggle a b c</button> <a href="#">reset</a> </div> <div class="wrap"> <div></div> <div class="b"></div> <div class="a b"></div> <div class="a c"></div> </div> <script> var cls = ; var divs = $('div.wrap').children(); var appendClass = function() { divs.append(function() { return '<div>' + (this.className || 'none') + '</div>'; }); }; appendClass(); $('button').on('click', function() { var tc = this.className || undefined; divs.toggleClass(tc); appendClass(); }); $('a').on('click', function(event) { event.preventDefault(); divs.empty().each(function(i) { this.className = cls; }); appendClass(); }); </script> </body> </html>
Демо
classList.toString()
Если вам однажды понадобится превратить в строку, используйте этот
метод. — это еще один метод JavaScript, характерный не только для
.
Спецификация W3C по этому поводу говорит только, что «объекты DOMTokenList должны
быть преобразованы в строку, которая лежит в их основе». WHATWG остановилась на
определении «Обработчик, преобразовывающий список в строку, должен возвратить
результат преобразования для соответствующего списка маркеров».
Разница только в формулировке.
Он не принимает никакие параметры, когда используется с , и возвращает
все классы для элемента в виде строки с пробелом-разделителем.
Methods
The method accepts an object that defines the TailwindCSS classes that you wish to use. It converts this object into a string of classnames.
For basic cases, you simply provide an object where the keys are the part of a Tailwind class before the first . For example, would be represented by and would be represented by .
import { classList } from 'tailwind-classlist'; const classes = classList({ m: 2, cursor: 'pointer', bg: 'grey-400', }); // Outputs "m-2 cursor-pointer bg-grey-400"
To use multiple classes with the same Tailwind prefix, group them together into an array.
const classes = classList({ text: 'lg', 'grey-600' }); // Outputs "text-lg text-grey-600"
To use state variants and responsive prefixes, group them together into an object.
const classes = classList({ bg: 'white', text: 'red-400', hover: { bg: 'red-400', text: 'white', }, focus: { outline: 'none', }, md: { text: 'lg', } }); // Outputs "bg-white text-red-400 hover:bg-red-400 hover:text-white focus:outline-none"
To use both state variants and responsive prefixes, use a nested object that begins with the responsive prefix first.
const classes = classlist({ md: { hover: { bg: 'red-800', text: 'blue-400', } } }); // Outputs "md:hover:bg-red-800 md:hover:text-blue-400"
Some classes in Tailwind don’t have any dashes in their name. These can be included by setting their value to .
const classes = classList({ fixed: true, italic: true, }); // Outputs "fixed italic"
The method accepts 2 or more classList strings and merges them together, overwriting any conflicting classes as it goes.
import { mergeClassLists } from 'tailwind-classlist'; const classListA = 'bg-blue-500 m-4'; const classListB = 'bg-red-500 p-4'; const combinedClasses = mergeClassLists(classListA, classListB); // Outputs 'bg-red-500 m-4 p-4'
It recognizes when multiple classes have the same prefix but shouldn’t overwrite eachother. In the example below, overwrites , but it has no effect on .
const classListA = 'bg-blue-500 bg-bottom m-4'; const classListB = 'bg-red-500 p-4'; const combinedClasses = mergeClassLists(classListA, classListB); // Outputs 'bg-red-500 bg-bottom m-4 p-4';
Similarly, it recognizes classes with conflicting styles that don’t have the same prefix. In the example below, and both affect the CSS property, so will overwrite .
const classListA = 'bg-blue-500 bg-bottom text-xs m-4 static'; const classListB = 'bg-red-500 p-4 text-lg fixed'; const result = mergeClassLists(classListA, classListB); // Outputs 'bg-red-500 bg-bottom text-lg m-4 p-4 fixed'
Any classes that aren’t part of the default Tailwind library will pass through without any filtering.
const classListA = 'bg-blue-500 text-xs sc-0dWm9Vdw2'; const classListB = 'bg-red-500 fixed test-class'; const result = mergeClassLists(classListA, classListB); // Outputs 'sc-0dWm9Vdw2 test-class bg-red-500 text-xs fixed'
The method performs the opposite operation as classList. It takes a string of classnames and returns a parsed classList object. Any classes that aren’t a part of the default Tailwind library will be grouped into an array under the key .
import { parseClassList } from 'tailwind-classlist'; const classes = 'm-2 cursor-pointer bg-grey-400'; const classObj = parseClassList(classes); // Outputs { m: 2, cursor: 'pointer', bg: 'grey-400' };
const classes = 'm-2 cursor-pointer sc-8d3jd6Ko customclass'; const classObj = parseClassList(classes); // Outputs { m: 2, cursor: 'pointer', extraClasses: };
Добавление и удаление нескольких классов
В спецификации говорится о «маркерах» (англ. «tokens» — прим.
переводчика), в описании методов и они упомянуты во
множественном числе.
Пока ни в одном браузере не реализован метод добавления/удаления более чем
одного класса сразу, но для нас не составит труда дополнить прототип
с помощью написанной вручную функции:
В браузерах на движке Blink можно добавлять и удалять несколько классов
одновременно с помощью , кроме того,
можно дополнить прототип написанной нами функцией, пока
поддержка не будет внедрена во всех браузерах:
Так же и для удаления:
В 2011 году была подана жалоба (касательно документа, который уже не существует)
с пожеланием разрешить для и список с
пробелом в качестве разделителя или массив.
«Маркеры» в множественном числе наталкивают на мысль о том, что массив должен быть
разрешен, но на практике он не работает. Указание выводить
если в «маркерах» присутствуют пробелы все еще в силе,
так что такой подход точно не сработает.
Если вы хотите заменить весь новым списком классов, можете
использовать функции, которые будут приведены в конце статьи.
Когда полезен доступ к атрибутам?
Когда браузер читает HTML и создаёт DOM-модель, то он создаёт свойства для всех стандартных атрибутов.
Например, свойства тега описаны в спецификации DOM: .
Например, у него есть свойство . Кроме того, он имеет и другие свойства, общие для всех элементов, которые описаны в спецификации в .
Все стандартные свойства DOM синхронизируются с атрибутами, однако не всегда такая синхронизация происходит 1-в-1, поэтому иногда нам нужно значение именно из HTML, то есть атрибут.
Рассмотрим несколько примеров.
Синхронизация не гарантирует одинакового значения в атрибуте и свойстве.
Для примера, посмотрим, что произойдёт с атрибутом при изменении свойства:
Это происходит потому, что атрибут может быть любым, а свойство , , должно быть полной ссылкой.
Стало быть, если мы хотим именно то, что в HTML, то нужно обращаться через атрибут.
Есть и другие подобные атрибуты
Кстати, есть и другие атрибуты, которые не копируются в точности
Например, DOM-свойство имеет логическое значение , а HTML-атрибут – любое строковое, важно лишь его наличие
Работа с через атрибут и свойство:
Изменение некоторых свойств обновляет атрибут. Но это скорее исключение, чем правило.
Чаще синхронизация – односторонняя: свойство зависит от атрибута, но не наоборот.
Например, при изменении свойства атрибут не меняется:
То есть, изменение DOM-свойства на атрибут не влияет, он остаётся таким же.
А вот изменение атрибута обновляет свойство:
Эту особенность можно красиво использовать.
Получается, что атрибут хранит оригинальное (исходное) значение даже после того, как пользователь заполнил поле и свойство изменилось.
Например, можно взять изначальное значение из атрибута и сравнить со свойством, чтобы узнать, изменилось ли значение. А при необходимости и перезаписать свойство атрибутом, отменив изменения.
Что такое класс?
Итак, что же такое ? Это не полностью новая языковая сущность, как может показаться на первый взгляд.
Давайте развеем всю магию и посмотрим, что такое класс на самом деле. Это поможет в понимании многих сложных аспектов.
В JavaScript класс – это разновидность функции.
Взгляните:
Вот что на самом деле делает конструкция :
- Создаёт функцию с именем , которая становится результатом объявления класса. Код функции берётся из метода (она будет пустой, если такого метода нет).
- Сохраняет все методы, такие как , в .
При вызове метода объекта он будет взят из прототипа, как описано в главе F.prototype. Таким образом, объекты имеют доступ к методам класса.
На картинке показан результат объявления :
Можно проверить вышесказанное и при помощи кода:
Миксин ParentNode
Данный миксин предназначен для обработки родительских элементов (предков), т.е. элементов, содержащих одного и более потомка (дочерних элементов).
Такая структура называется и представляет собой массивоподобный объект (псевдомассив). Существует еще одна похожая структура — .
Массивоподобные объекты имеют свойство с количеством потомков, метод (), позволяющий перебирать узлы (делать по ним итерацию). Такие объекты позволяют получать элементы по индексу, по названию () и т.д. Однако, у них отсутствуют методы настоящих массивов, такие как , , и др., что делает работу с ними не очень удобной. Поэтому массивоподобные объекты рекомендуется преобразовывать в массивы с помощью метода или spread-оператора:
- — первый потомок — элемент
- — последний потомок — элемент
Для дальнейших манипуляций нам потребуется периодически создавать новые элементы, поэтому создадим еще одну утилиту:
Наша утилита принимает 4 аргумента: идентификатор, текст, название тега и CSS-класс. 2 аргумента (тег и класс) имеют значения по умолчанию. Функция возвращает готовый к работе элемент. Впоследствии, мы реализуем более универсальный вариант данной утилиты.
- — добавляет элемент в начало списка
- — добавляет элемент в конец списка
Наиболее универсальными способами получения ссылок на элементы являются методы и . Причем, в отличие от , они могут вызываться на любом родительском элементе, а не только на . В качестве аргумента названным методам передается любой валидный CSS-селектор (, , и т.д.):
Создадим универсальную утилиту для получения элементов:
Наша утилита принимает 3 аргумента: CSS-селектор, родительский элемент и индикатор количества элементов (один или все). 2 аргумента (предок и индикатор) имеют значения по умолчанию. Функция возвращает либо один, либо все элементы (в виде обычного массива), совпадающие с селектором, в зависимости от значения индикатора:
Сброс стилей
Иногда нам нужно добавить свойство стиля, а потом, позже, убрать его.
Например, чтобы скрыть элемент, мы можем задать .
Затем мы можем удалить свойство , чтобы вернуться к первоначальному состоянию. Вместо мы должны присвоить ему пустую строку: .
Если мы установим в пустую строку, то браузер применит CSS-классы и встроенные стили, как если бы такого свойства вообще не было.
Полная перезапись
Обычно мы используем для присвоения индивидуальных свойств стиля. Нельзя установить список стилей как, например, , потому что – это объект, и он доступен только для чтения.
Для задания нескольких стилей в одной строке используется специальное свойство :
Это свойство редко используется, потому что такое присваивание удаляет все существующие стили: оно не добавляет, а заменяет их. Можно ненароком удалить что-то нужное. Но его можно использовать, к примеру, для новых элементов, когда мы точно знаем, что не удалим существующий стиль.
То же самое можно сделать установкой атрибута: .
Поддержка браузерами и полифилы
ClassList API .
По меньшей мере базовая поддержка была реализована, начиная с Firefox 3.6, Opera
11.50, Chrome 8 и Safari 5.1.
Белым пятном являются IE9 и старше и всё еще довольно популярный Android 2.3
и старше.
, которые помогут справиться с
этой проблемой.
Написанный на скорую руку полифил Девона Говета (Devon Govett)
обеспечивает поддержку только для IE9, также стоит почитать комментарии,
содержащие информацию о написании кросбраузерного JavaScript.
Полифил Эли Грея (Eli Grey) дает более широкую поддержку. Он поддерживает
IE8 и обеспечивает базовую поддержку , и
для Android 2.1 и младше.
Также есть полифил для поддержки от Егора Халимоненко под
браузеры, которые поддерживают , но не понимают для .
Проверить поддержку API браузером можно следующим образом:
Toggle Class
Step 1) Add HTML:
Toggle between adding a class name to the div element with id=»myDIV» (in this example we use a button to toggle the class name).
Example
<button onclick=»myFunction()»>Try it</button><div id=»myDIV»>
This is a DIV element.</div>
Step 2) Add CSS:
Add a class name to toggle:
Example
.mystyle { width: 100%; padding:
25px; background-color: coral;
color: white; font-size: 25px;}
Step 3) Add JavaScript:
Get the <div> element with id=»myDIV» and toggle between the «mystyle» class:
Example
function myFunction() { var element = document.getElementById(«myDIV»);
element.classList.toggle(«mystyle»);}
Tip: Also see How To Add A Class.
Tip: Also see How To Remove A Class.
Tip: Learn more about the classList property in our JavaScript Reference.
❮ Previous
Next ❯
Итого
- Атрибуты – это то, что написано в HTML.
- Свойство – это то, что находится внутри DOM-объекта.
Таблица сравнений для атрибутов и свойств:
Свойства | Атрибуты |
---|---|
Любое значение | Строка |
Названия регистрозависимы | Не чувствительны к регистру |
Не видны в | Видны в |
Синхронизация между атрибутами и свойствами:
- Стандартные свойства и атрибуты синхронизируются: установка атрибута автоматически ставит свойство DOM. Некоторые свойства синхронизируются в обе стороны.
- Бывает так, что свойство не совсем соответствует атрибуту. Например, «логические» свойства вроде , всегда имеют значение , а в атрибут можно записать произвольную строку.Выше мы видели другие примеры на эту тему, например .
Нестандартные атрибуты:
- Нестандартный атрибут (если забыть глюки старых IE) никогда не попадёт в свойство, так что для кросс-браузерного доступа к нему нужно обязательно использовать .
- Атрибуты, название которых начинается с , можно прочитать через . Эта возможность не поддерживается IE10-.
Для того, чтобы избежать проблем со старыми IE, а также для более короткого и понятного кода старайтесь везде использовать свойства, а атрибуты – только там, где это действительно нужно.
А действительно нужны атрибуты очень редко – лишь в следующих трёх случаях:
- Когда нужно кросс-браузерно получить нестандартный HTML-атрибут.
- Когда нужно получить «оригинальное значение» стандартного HTML-атрибута, например, .
- Когда нужно получить список всех атрибутов, включая пользовательские. Для этого используется коллекция .
Если вы хотите использовать собственные атрибуты в HTML, то помните, что атрибуты с именем, начинающимся на валидны в HTML5 и современные браузеры поддерживают доступ к ним через свойство .
Итог
Можно рассматривать API в двух плоскостях. В большинстве случаев это
простой способ добавить, удалить и проверить наличие отдельных классов для
элемента HTML. На данный момент я использую его в каждом проекте, и мне очень
редко приходится отклоняться от этих простых методов. Не могу придумать, в каком
случае , или могли бы пригодиться сами по себе,
поэтому они меня не особо волнуют.
С другой стороны, здесь вся соль в работе с объектом, поиске функциональных
способов управлять состоянием веб-страниц, разделении функций, прогрессивном
улучшении.
Только от вас зависит, для чего вы будете его использовать, но, как я говорил в
начале, с API легко разобраться, и он делает легким то, что раньше
было трудным. Советую прислушаться к тому, о чём я здесь написал, и
поэкспериментировать в своих собственных проектах, если для вас API
является новым понятием; если же он вам уже хорошо знаком, поделитесь в
комментариях мнением о том, что можно было бы рассказать лучше.