One place for hosting & domains

      классов

      Изменение атрибутов, классов и стилей в DOM


      Введение

      В предыдущем руководстве данной серии, «Внесение изменений в DOM», мы рассказали о том, как создать, вставить и удалить элементы в объектной модели документов (DOM) с помощью встроенных методов. Благодаря повышению вашего уровня владения манипуляциями с DOM, вы сможете более эффективно использовать интерактивные возможности JavaScript и изменять веб-элементы.

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

      Описание выбора элементов

      До недавнего времени популярная JavaScript-библиотека jQuery чаще всего использовалась для выбора и изменения элементов в DOM. jQuery упрощал процесс выбора одного или нескольких элементов и внесения изменений для всех этих элементов одновременно. В статье «Доступ к элементам в DOM» мы описали методы DOM для захвата и работы с узлами в ванильном JavaScript.

      Напоминаем, что document.querySelector() и document.getElementById() — это методы, которые используются для доступа к отдельному элементу. Используя div с атрибутом id в примере ниже, мы так или иначе можем получить доступ к этому элементу.

      <div id="demo-id">Demo ID</div>
      

      Метод querySelector()​​​ обладает большей надежностью, поскольку с его помощью можно выбрать элемент на странице по любому типу селектора.

      // Both methods will return a single element
      const demoId = document.querySelector('#demo-id');
      

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

      // Change the text of one element
      demoId.textContent = 'Demo ID text updated.';
      

      Однако при получении доступа к нескольким элементам с общим селектором, например, к какому-то конкретному классу, мы вынуждены проходить по всем элементам в списке. В коде ниже мы имеем два элемента div с общим значением класса.

      <div class="demo-class">Demo Class 1</div>
      <div class="demo-class">Demo Class 2</div>
      

      Мы будем использовать querySelectorAll() для захвата всех элементов с примененным атрибутом demo-class и forEach() для прохождения по ним и внесения изменений. Также возможно доступ к определенному элементу с помощью querySelectorAll() таким же образом, как и к массиву, т.е. с помощью квадратных скобок.

      // Get a NodeList of all .demo elements
      const demoClasses = document.querySelectorAll('.demo-class');
      
      // Change the text of multiple elements with a loop
      demoClasses.forEach(element => {
        element.textContent = 'All demo classes updated.';
      });
      
      // Access the first element in the NodeList
      demoClasses[0];
      

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

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

      Примечание. Методы getElementsByClassName() и getElementsByTagName() будут возвращать коллекции HTML, которые не имеют доступа к методу forEach(), в отличие от querySelectorAll(). В этих случаях вам нужно будет использовать стандартный цикл for для прохождения по коллекции.

      Изменение атрибутов

      Атрибуты — это значения, которые содержат дополнительную информацию об элементах HTML. Обычно они идут в паре название/значение и могут быть обязательными в зависимости от элемента.

      Среди самых распространенных атрибутов HTML необходимо отметить атрибут src тега img, href для тега a, class, id и style. Полный список атрибутов HTML см. в списке атрибутов в Mozilla Developer Network. Пользовательские элементы, которые не являются частью стандарта HTML, будут сопровождаться префиксом data-.

      В JavaScript есть четыре метода для изменения атрибутов элементов:

      Метод Описание Пример
      hasAttribute() Возвращает true или false element.hasAttribute('href');
      getAttribute() Возвращает значение определенного атрибута или null element.getAttribute('href');
      setAttribute() Добавляет или обновляет заданный атрибут element.setAttribute('href', 'index.html');
      removeAttribute() Удаляет атрибут элемента element.removeAttribute('href');

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

      attributes.html

      <!DOCTYPE html>
      <html lang="en">
      <body>
      
          <img src="https://js-tutorials.nyc3.digitaloceanspaces.com/shark.png">
      
      </body>
      
      </html>
      

      При загрузке указанного выше файла HTML в современном веб-браузере и открытии консоли разработчика, вы должны получить примерно следующий вывод:

      Первый рендеринг classes.html

      Теперь мы можем протестировать все методы атрибутов на ходу.

      // Assign image element
      const img = document.querySelector('img');
      
      img.hasAttribute('src');                // returns true
      img.getAttribute('src');                // returns "...shark.png"
      img.removeAttribute('src');             // remove the src attribute and value
      

      К этому моменту вы удалите атрибут src и значение, связанное с тегом img, но вы можете сбросить этот атрибут и присвоить значение другому изображению с помощью img.setAttribute():

      img.setAttribute('src', 'https://js-tutorials.nyc3.digitaloceanspaces.com/octopus.png');
      

      Второй рендеринг classes.html

      Наконец, мы можем изменить атрибут напрямую, присвоив новое значение атрибуту в качестве свойства элемента, установив src обратно для файла shark.png.

      img.src = 'https://js-tutorials.nyc3.digitaloceanspaces.com/shark.png';
      

      Любой атрибут можно изменить таким образом, а также с помощью описанных выше методов.

      Методы hasAttribute() и getAttribute() обычно используются с условными операторами, а методы setAttribute() и removeAttribute() используются для прямого изменения DOM.

      Изменение классов

      Атрибут class соответствует селекторам класса CSS. Не путайте с классами ES6, особым типом функции JavaScript.

      Классы CSS используются для применения стилей для нескольких элементов, в отличие от идентификаторов, которые могут существовать только один раз на странице. В JavaScript есть свойства className и classList для работы с атрибутом класса.

      Метод/Свойство Описание Пример
      className Получает или устанавливает значение класса element.className;
      classList.add() Добавляет одно или несколько значений класса element.classList.add('active');
      classList.toggle() Включает или отключает класс element.classList.toggle('active');
      classList.contains() Проверяет, существует ли значение класса element.classList.contains('active');
      classList.replace() Заменяет существующее значение класса на новое значение класса element.classList.replace('old', 'new');
      classList.remove() Удаляет значение класса element.classList.remove('active');

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

      classes.html

      <!DOCTYPE html>
      <html lang="en">
      
      <style>
          body {
              max-width: 600px;
              margin: 0 auto;
              font-family: sans-serif;
          }
          .active {
              border: 2px solid blue;
          }
      
          .warning {
              border: 2px solid red;
          }
      
          .hidden {
              display: none;
          }
      
          div {
              border: 2px dashed lightgray;
              padding: 15px;
              margin: 5px;
          }
      </style>
      
      <body>
      
          <div>Div 1</div>
          <div class="active">Div 2</div>
      
      </body>
      
      </html>
      

      При открытии файла classes.html в браузере вы должны получить примерно следующий результат:

      Первый рендеринг classes.html

      Свойство className было введено для предотвращения конфликтов с ключевым словом class в JavaScript и другими языками, которые имеют доступ к DOM. Вы можете использовать className для присвоения значения напрямую в классе.

      // Select the first div
      const div = document.querySelector('div');
      
      // Assign the warning class to the first div
      div.className = 'warning';
      

      Мы присвоили класс warning, определенный в значениях CSS в classes.html, для первого div. Вывод должен выглядеть следующим образом:

      Второй рендеринг classes.html

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

      Другой способ изменения классов — это свойство classList, которое имеет несколько полезных методов. Эти методы аналогичны методами addClass, removeClass и toggleClass в jQuery.

      // Select the second div by class name
      const activeDiv = document.querySelector('.active');
      
      activeDiv.classList.add('hidden');                // Add the hidden class
      activeDiv.classList.remove('hidden');             // Remove the hidden class
      activeDiv.classList.toggle('hidden');             // Switch between hidden true and false
      activeDiv.classList.replace('active', 'warning'); // Replace active class with warning class
      

      После использования описанных выше методов ваша веб-страница будет выглядеть следующим образом:

      Первый рендеринг classes.html

      В отличие от примера с className, использование classList.add() будет добавлять новый класс в список существующих классов. Также вы можете добавить несколько в виде разделенной запятыми строки. Также вы можете использовать setAttribute для изменения класса элемента.

      Изменение стилей

      Свойство style отражает вложенные стили элемента HTML. Часто стили будут применяться к элементам через таблицу стилей, как мы делали ранее в этой статье, но иногда нам будет нужно добавить или изменить вложенный стиль напрямую.

      Мы создадим небольшой пример для демонстрации редактирования стилей с помощью JavaScript. Ниже представлен новый файл HTML с блоком div, который имеет вложенные стили, применяемые для отображения квадрата.

      styles.html

      <!DOCTYPE html>
      <html lang="en">
      
      <body>
      
          <div style="height: 100px;
                      width: 100px;
                      border: 2px solid black;">Div</div>
      
      </body>
      
      </html>
      

      После открытия в браузере, styles.html будет выглядеть примерно следующим образом:

      Первый рендеринг styles.html

      Один из вариантов редактирования стилей подразумевает использование setAttribute().

      // Select div
      const div = document.querySelector('div');
      
      // Apply style to div
      div.setAttribute('style', 'text-align: center');
      

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

      div.style.height = '100px';
      div.style.width = '100px';
      div.style.border = '2px solid black';
      

      Свойства CSS записаны в кебаб-регистре, т.е. в нижнем регистре, разделенные тире. Важно отметить, что свойства CSS в кебаб-регистре не могут использоваться для свойства стиля JavaScript. Вместо этого они будут заменены на их эквивалент в верблюжьем регистре, когда первое слово имеет нижний регистр, а все последующие слова начинаются с заглавной буквы. Иными словами, вместо text-align мы будем использовать textAlign для свойства стиля JavaScript.

      // Make div into a circle and vertically center the text
      div.style.borderRadius = '50%';
      div.style.display = 'flex';
      div.style.justifyContent = 'center';
      div.style.alignItems = 'center';
      

      После внесения описанных выше изменений стиля итоговый рендеринг styles.html будет представлять собой круг:

      Итоговый рендеринг styles.html

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

      Заключение

      HTML-элементы часто содержат дополнительную информацию в форме атрибутов. Активы могут состоять из пар название/значение, а самыми распространенными атрибутами являются атрибуты class и style.

      В этом руководстве мы узнали, как получить доступ, изменять и удалять атрибуты для элемента HTML в DOM с помощью простого JavaScript. Также мы научились добавлять, удалять, переключать и заменять классы CSS для элемента и редактировать вложенные стили CSS. Для получения дополнительной информации ознакомьтесь с документацией по атрибутам в Mozilla Developer Network.



      Source link

      Понимание понятия классов в JavaScript


      Введение

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

      До недавнего времени промышленные разработчики использовали функции конструктора для имитации объектно-ориентированного шаблона в JavaScript. Языковая спецификация ECMAScript 2015 (часто называемая ES6) ввела в язык JavaScript понятие классов. Классы в JavaScript не добавляют дополнительные функции, и представляют собой способ упростить синтаксис при использовании прототипов и наследования и сделать его более элегантным. Поскольку в других языках программирования также используются классы, синтаксис классов в JavaScript упрощает работу для разработчиков, владеющих другими языками.

      Классы — это функции

      Класс JavaScript — это вид функции. Для декларирования классов используется ключевое слово class. Мы используем синтаксис выражения функции для инициализации функции и синтаксис выражения класса для инициализации класса.

      // Initializing a function with a function expression
      const x = function() {}
      
      // Initializing a class with a class expression
      const y = class {}
      

      Мы можем получить доступ к [[Prototype]] объекта с помощью метода Object.getPrototypeOf(). Давайте протестируем созданную нами пустую функцию.

      Object.getPrototypeOf(x);
      

      Output

      ƒ () { [native code] }

      Также мы можем использовать этот метод для только что созданного нами класса.

      Object.getPrototypeOf(y);
      

      Output

      ƒ () { [native code] }

      Программный код, декларированный с помощью function и class, возвращает функцию [[Prototype]]. При использовании прототипов любую функцию можно превратить в экземпляр конструктора с помощью ключевого слова new.

      const x = function() {}
      
      // Initialize a constructor from a function
      const constructorFromFunction = new x();
      
      console.log(constructorFromFunction);
      

      Output

      x {} constructor: ƒ ()

      Это также относится и к классам.

      const y = class {}
      
      // Initialize a constructor from a class
      const constructorFromClass = new y();
      
      console.log(constructorFromClass);
      

      Output

      y {} constructor: class

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

      Определение класса

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

      Функция конструктора инициализируется с рядом параметров, которые назначаются как свойства this, относящиеся к самой функции. Согласно правилам, первая буква идентификатора будет преобразована в заглавную.

      constructor.js

      // Initializing a constructor function
      function Hero(name, level) {
          this.name = name;
          this.level = level;
      }
      

      При трансляции в синтаксис класса, как показано ниже, структура будет очень похожей.

      class.js

      // Initializing a class definition
      class Hero {
          constructor(name, level) {
              this.name = name;
              this.level = level;
          }
      }
      

      Мы знаем, что функция конструктора является планом объекта благодаря тому, что первая буква инициализатора (необязательно) заглавная, и потому что мы знакомы с синтаксисом. Ключевое слово class показывает назначение нашей функции более прямо.

      Единственная разница в синтаксисе инициализации заключается в использовании ключевого слова class вместо function, и в том, что свойства назначаются внутри метода constructor().

      Определение методов

      При использовании функций конструктора методы обычно назначаются непосредственно в prototype вместо инициализации, как показано ниже на примере метода greet().

      constructor.js

      function Hero(name, level) {
          this.name = name;
          this.level = level;
      }
      
      // Adding a method to the constructor
      Hero.prototype.greet = function() {
          return `${this.name} says hello.`;
      }
      

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

      class.js

      class Hero {
          constructor(name, level) {
              this.name = name;
              this.level = level;
          }
      
          // Adding a method to the constructor
          greet() {
              return `${this.name} says hello.`;
          }
      }
      

      Давайте посмотрим на эти свойства и методы в действии. Мы создадим новый экземпляр Hero, используя ключевое слово new, и присвоим некоторые значения.

      const hero1 = new Hero('Varg', 1);
      

      Если мы распечатаем дополнительную информацию о нашем новом объекте с помощью команды console.log(hero1), мы более подробно увидим. что происходит при инициализации класса.

      Output

      Hero {name: "Varg", level: 1} __proto__: ▶ constructor: class Hero ▶ greet: ƒ greet()

      В результатах мы видим, что функции constructor() и greet() functions были применены к прототипу __proto__ или [[Prototype]] объекта hero1, а непосредственно к объекту hero1 как к методу. Хотя при создании функций конструктора это очевидно, при создании классов дело обстоит по другому. Классы позволяют использовать более простой и сжатый синтаксис, но при этом немного теряется понятность процесса.

      Расширение класса

      Функции конструктора и классы можно расширять на новые планы объекта на основе родительского экземпляра. Это позволяет не повторять код для похожих объектов, для которых нужно просто добавить дополнительные или более детальные характеристики.

      Новые функции конструктора можно создавать на основе родительского экземпляра с помощью метода call(). В примере ниже мы создадим более конкретный класс персонажа Mage и присвоим ему свойства Hero с помощью метода call(), а также добавим дополнительное свойство.

      constructor.js

      // Creating a new constructor from the parent
      function Mage(name, level, spell) {
          // Chain constructor with call
          Hero.call(this, name, level);
      
          this.spell = spell;
      }
      

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

      const hero2 = new Mage('Lejon', 2, 'Magic Missile');
      

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

      Output

      Mage {name: "Lejon", level: 2, spell: "Magic Missile"} __proto__: ▶ constructor: ƒ Mage(name, level, spell)

      Для классов ES6 ключевое слово super используется вместо call для доступа к родительским функциям. Мы будем использовать extends для обозначения родительского класса.

      class.js

      // Creating a new class from the parent
      class Mage extends Hero {
          constructor(name, level, spell) {
              // Chain constructor with super
              super(name, level);
      
              // Add a new property
              this.spell = spell;
          }
      }
      

      Теперь мы можем точно так же создать новый экземпляр Mage.

      const hero2 = new Mage('Lejon', 2, 'Magic Missile');
      

      Распечатаем hero2 на консоли и посмотрим результат.

      Output

      Mage {name: "Lejon", level: 2, spell: "Magic Missile"} __proto__: Hero ▶ constructor: class Mage

      Результат практически такой же, но в конструкции класса прототип [[Prototype]] связан с родительским объектом, в данном случае Hero.

      Ниже приводится полное сравнение процесса инициализации, добавления методов и наследования между функцией конструктора и классом.

      constructor.js

      function Hero(name, level) {
          this.name = name;
          this.level = level;
      }
      
      // Adding a method to the constructor
      Hero.prototype.greet = function() {
          return `${this.name} says hello.`;
      }
      
      // Creating a new constructor from the parent
      function Mage(name, level, spell) {
          // Chain constructor with call
          Hero.call(this, name, level);
      
          this.spell = spell;
      }
      

      class.js

      // Initializing a class
      class Hero {
          constructor(name, level) {
              this.name = name;
              this.level = level;
          }
      
          // Adding a method to the constructor
          greet() {
              return `${this.name} says hello.`;
          }
      }
      
      // Creating a new class from the parent
      class Mage extends Hero {
          constructor(name, level, spell) {
              // Chain constructor with super
              super(name, level);
      
              // Add a new property
              this.spell = spell;
          }
      }
      

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

      Заключение

      В этом обучающем модуле мы узнали о сходствах и различиях между функциями конструктора JavaScript и классами ES6. Классы и конструкторы имитируют объектно-ориентированную модель наследования в JavaScript, который представляет собой язык наследования на основе прототипов.

      Понимание принципов наследования прототипов очень важно, если вы хотите стать эффективным разработчиком на JavaScript. Знакомство с классами очень полезно, потому что популярные библиотеки JavaScript, такие как React, часто используют синтаксис class.



      Source link