Статьи

Управление пользовательскими данными с помощью API набора данных HTML5

В течение долгого времени веб-разработчикам приходилось хранить данные об элементах DOM. Одним из наиболее распространенных методов было добавление данных в качестве имен классов. Пуристы, как и я, всегда чувствовали себя неправильно, потому что это не место для данных. Альтернативным способом было добавление пользовательских атрибутов к интересующим элементам. Эта практика приводит к неверной разметке, поскольку пользовательские атрибуты не поддерживаются спецификацией. Итак, вы в конечном итоге пожертвовали валидацией для достижения своей цели. Эта ситуация была очень расстраивающей. К счастью, HTML5 это исправил. Фактически, HTML5 не только представил возможность добавления пользовательских атрибутов через атрибуты данных , но также предоставил API для работы с ними, называемый API набора данных. В этой статье мы узнаем, как работает этот API и что он может сделать для нас.

Что такое API набора данных?

Среди всех новых элементов (таких как articlesectionheaderfooterHigh Resolution Time , User Timing , getUserMedia и Page Visility ), HTML5 также представил атрибуты данных и API набора данных. Прежде чем углубляться в наше обсуждение API набора данных, я хочу дать вам краткое представление о том, что такое атрибуты данных.

Атрибуты данных получают свое имя из префикса data- Это также объясняет, почему иногда их называют атрибутами data-* Пример элемента, использующего атрибуты данных, показан ниже.

 <span id="element" data-level="1" data-points="100" data-opponent="Dragon"></span>

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

 <span id="element" data-level="1" data-points="100" data-final-opponent="Dragon"></span>

Теперь у вас должно быть четкое представление о том, что такое атрибуты данных, поэтому давайте начнем обсуждать API. API набора данных предоставляет нам простой способ работы с атрибутами данных. Этот API позволяет нам устанавливать, получать или даже удалять значения атрибутов данных. API набора данных предоставляет атрибут элемента DOM с именем datasetDOMStringMap Ключи этого объекта — это имена атрибутов данных без префикса data- Соответствующие значения являются значениями атрибутов данных. Если имя атрибута состоит из нескольких слов, разделенных дефисом, оно преобразуется в camelCase. Давайте посмотрим на следующий пример:

 var obj = document.getElementById("element").dataset

Предыдущий оператор будет следующим объектом в переменной obj

 {
  level: "1",
  points: "100",
  finalOpponent: "Dragon"
}

Доступ к отдельным атрибутам данных можно получить с помощью setAttribute()getAttribute()removeAttribute() Однако API набора данных предоставляет удобный и прямой способ доступа к пользовательским данным. Если API не поддерживается, вы должны получить все атрибуты, а затем отфильтровать те, которые не начинаются с data- И хотя API набора данных проще, он также медленнее, чем ранее упомянутые методы, что доказано этим JSperf . Однако, если вы не обращаетесь к тысячам атрибутов в секунду, вы не заметите никакой разницы.

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

Установка значений

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

 document.getElementById("element").dataset.media = "song";

Получение ценностей

Создание атрибутов совершенно бесполезно, если мы не можем их получить. Допустим, мы хотим вывести значение атрибута data-final-opponent Код для этого будет выглядеть так:

 console.log(document.getElementById("element").dataset.finalOpponent);
// prints "Dragon"

Удаление атрибутов

Чтобы удалить значение, просто перезапишите его, используя пустую строку. Однако для фактического удаления атрибута мы можем использовать оператор delete Пример, который удаляет атрибут data-final-opponent

 delete document.getElementById("element").dataset.finalOpponent;

После выполнения предыдущего оператора попытка получить значение атрибута приведет к undefined

Совместимость браузера

API набора данных широко поддерживается в настольных и мобильных браузерах, за исключением Internet Explorer, который реализует API только в IE11. Кроме того, есть некоторые старые мобильные браузеры, которые не поддерживают его, но в целом поддержка отличная. Для тех браузеров, которые не поддерживают этот API, доступна поддержка полифилла с именем HTML 5 . Если вы не хотите добавлять polyfill для такого простого API, вы можете использовать setAttribute()getAttribute()removeAttribute()

демонстрация

Учиться чему-то новому — это здорово, но еще лучше, если мы сможем поиграть с этим. Итак, мы создадим небольшую демонстрацию, которая позволит нам увидеть, как работает API набора данных. Общая идея состоит в том, чтобы иметь элемент, с помощью которого мы можем получать, устанавливать и удалять атрибуты данных. Чтобы увидеть, что происходит, и следить за текущим состоянием элемента, у нас будет небольшое окно, в которое мы будем записывать сделанные нами изменения. Кроме того, у нас будет область с необработанным HTML-кодом элемента, представляющего его текущее состояние.

Чтобы поиграть с его атрибутами данных, нам нужны два поля ввода: ключ и значение. Первый позволяет нам установить имя атрибута, который мы хотим сохранить, а второй — где мы напишем значение атрибута. Поскольку мы хотим разрешить три различных действия (получить, установить и удалить), нам также понадобятся три кнопки, к которым мы добавим обработчики. Как всегда, мы также проверим поддержку браузера, а если тест не пройден, мы покажем сообщение «API не поддерживается».

Прежде чем показывать вам демонстрационный код, я хочу поделиться с вами двумя соображениями. Демо предполагает, что вы прочитали всю статью. Следовательно, вы знаете, что для выполнения действия с атрибутом данных, имя которого содержит более одного слова, вам необходимо преобразовать это имя в camelCase. Если вы хотите изменить это поведение и иметь возможность писать «конечный оппонент» вместо «конечный оппонент», я написал две служебные функции для вас. Чтобы использовать эти функции, вам нужно добавить их в демонстрационную версию и изменить код, чтобы вы вызывали их внутри обработчиков перед выполнением действия. Исходный код этих функций приведен ниже.

 function hyphenToCamelCase(string) {
  return string.replace(/-([a-z])/g, function(string) {
    return string[1].toUpperCase();
  });
}

function camelCaseToHyphen(string) {
  return string.replace(/([A-Z])/g, function(string) {
    return '-' + string.toLowerCase();
  });
}

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

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

 <!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Dataset API Demo</title>
    <style>
      body
      {
        max-width: 500px;
        margin: 2em auto;
        font-size: 20px;
      }

      h1
      {
        text-align: center;
      }

      .hidden
      {
        display: none;
      }

      #log
      {
        height: 200px;
        width: 100%;
        overflow-y: scroll;
        border: 1px solid #333333;
        line-height: 1.3em;
      }

      .buttons-demo-wrapper
      {
        text-align: center;
      }

      .button-demo
      {
        padding: 0.5em;
        margin: 1em;
      }

      .author
      {
        display: block;
        margin-top: 1em;
      }
    </style>
  </head>
  <body>
    <h1>Dataset API</h1>

    <h3>Live sample element</h3>
    <div id="showcase">
      &lt;span id="play-element" class="hidden" data-level="1" data-points="100" data-final-opponent="Dragon"&gt;&lt;/span&gt;
    </div>

    <h3>Play area</h3>
    <div>
      <label for="key">Key:</label>
      <input type="text" id="key"></input>
      <label for="value">Value:</label>
      <input type="text" id="value"></input>

      <div class="buttons-demo-wrapper">
        <button id="set-data" class="button-demo">Set data</button>
        <button id="get-data" class="button-demo">Get data</button>
        <button id="delete-data" class="button-demo">Delete data</button>
      </div>
    </div>

    <span id="d-unsupported" class="hidden">API not supported</span>

    <h3>Log</h3>
    <div id="log"></div>
    <button id="clear-log" class="button-demo">Clear log</button>

    <span id="play-element" class="hidden" data-level="1" data-points="100" data-final-opponent="Dragon"></span>

    <script>
      if (!"dataset" in document.createElement("span")) {
        document.getElementById("d-unsupported").classList.remove("hidden");
        ["set-data", "get-data", "delete-data"].forEach(function(elementId, index) {
          document.getElementById(elementId).setAttribute("disabled", "disabled");
        });
      } else {
        var playElement = document.getElementById("play-element");
        var key = document.getElementById("key");
        var value = document.getElementById("value");
        var log = document.getElementById("log");
        var showcase = document.getElementById("showcase");

        document.getElementById("clear-log").addEventListener("click", function() {
          log.innerHTML = "";
        });
        document.getElementById("set-data").addEventListener("click", function() {
          if (key.value.indexOf("-") !== -1) {
            log.innerHTML = "Warning! Hyphen not allowed. Use camelCase instead.\n" + log.innerHTML;
          } else {
            playElement.dataset[key.value] = value.value;
            showcase.textContent = playElement.outerHTML;
            log.innerHTML = "Set data-" + key.value + " attribute to '" + value.value + "'<br />" + log.innerHTML;
          }
        });
        document.getElementById("get-data").addEventListener("click", function() {
          if (key.value.indexOf("-") !== -1) {
            log.innerHTML = "Warning! Hyphen not allowed. Use camelCase instead.<br />" + log.innerHTML;
          } else {
            log.innerHTML = "Get data-" + key.value + " attribute. Value: '" + playElement.dataset[key.value] + "'<br />" + log.innerHTML;
          }
        });
        document.getElementById("delete-data").addEventListener("click", function() {
          if (key.value.indexOf("-") !== -1) {
            log.innerHTML = "Warning! Hyphen not allowed. Use camelCase instead.<br />" + log.innerHTML;
          } else {
            delete playElement.dataset[key.value];
            showcase.textContent = playElement.outerHTML;
            log.innerHTML = "Deleted data-" + key.value + " attribute<br />" + log.innerHTML;
          }
        });
      }
    </script>
  </body>
</html>

Выводы

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