Элемент output

Ричард Кларк

Оригинал: http://html5doctor.com/the-output-element/

Перевод: Влад Мержевич

Посещая Интернет вы увидите ряд сайтов, которые используют калькулятор для расчёта разных вещей, таких как: погашение ссуды, ставки по ипотечным кредитам, налоги, страхование и многое другое. До сегодняшнего дня у вас не было способа семантической разметки результата таких вычислений. Встречайте — элемент <output>! В этой статье мы расскажем об этом элементе и некоторых связанных с ним трюках JavaScript. Расщёлкнем этот орешек.

Определение

<output>, новый элемент в HTML5, применяется в формах. Спецификации WHATWG HTML описывает <output> очень просто.

Элемент output представляет собой результат вычислений. Спецификация WHATWG HTML.

Наряду со стандартными глобальными атрибутами <output> понимает следующие.

for

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

form

Форма связанная с элементом <output>. Значение должно быть идентификатором формы в том же самом документе. Это позволяет размещать <output> за пределами <form> с которой он связан.

name

Имя элемента.

Реализация <output>

Начнём с создания простого примера, который складывает два целых числа (пример 1). Будем использовать новый в HTML5 тип number и функцию parseInt для преобразования строк в целое число.

Пример 1. Простой калькулятор в Chrome

<form onsubmit="return false" oninput="o.value = 
  parseInt(a.value) + parseInt(b.value)">
  <input name="a" type="number" step="any"> +
  <input name="b" type="number" step="any"> =
  <output name="o"></output>
</form>

Простой калькулятор в Chrome

Заметьте, что мы используем стандартное событие oninput, которое заменило устаревшие событие onforminput. Даниэль Фризен написал подробную статью о текущей поддержке oninput; oninput не поддерживается в IE8 и ниже, а его поддержка в IE9 несколько странная, но вы можете обойти эти проблемы с помощью html5Widgets.

См. живой пример кода

Как и следовало ожидать, если ввести только одно значение, функция возвращает NaN. Она пытается сложить число и значение undefined, в итоге 1 + undefined = undefined.

Использование атрибута for

Возьмём за основу предыдущий пример и добавим к <output> атрибут for (пример 2). Нам нужно добавить идентификаторы каждого связанного <input>, это аналогично атрибуту for для <label>.

Пример 2. Использование атрибута for для элемента <output>

<form onsubmit="return false" oninput="o.value = 
  parseInt(a.value) + parseInt(b.value)">
  <input name="a" id="a" type="number" step="any"> +
  <input name="b" id="b" type="number" step="any"> =
  <output name="o" for="a b"></output>
</form>

См. живой пример

Свойство valueAsNumber

В HTML5 представлено свойство JavaScript valueAsNumber для полей формы (в частности: number, date, range). Оно возвращает значение в виде числа, а не строки, то есть нам больше не нужно использовать parseInt или parseFloat, и оператор + складывает, а не склеивает.

Пример 3. Использование свойства valueAsNumber для получения числового значения из полей

<form onsubmit="return false" oninput="o.value = 
  a.valueAsNumber + b.valueAsNumber">
  <input name="a" id="a" type="number" step="any"> +
  <input name="b" id="b" type="number" step="any"> =
  <output name="o" for="a b"></output>
</form>

См. живой пример

Финансовый калькулятор: подробный пример

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

Пример 4. Финансовый калькулятор отображает результат в элементе <output>

<form onsubmit="return false" oninput="amount.value = 
    (hours.valueAsNumber * rate.valueAsNumber) + 
    ((hours.valueAsNumber * rate.valueAsNumber) * 
    vat.valueAsNumber)">
 <legend>Invoice</legend>
 <p><label for="hours">Number of hours</label>
  <input type="number" min="0" id="hours" name="hours"></p>
 <p><label for="rate">Rate</label>
  <span>£</span><input type="number" min="0" id="rate" name="rate"></p>
 <p><label for="vat">VAT</label>
  <input type="number" min="0" id="vat" value="0.20" name="vat"></p>
 <p>Total: <strong>£<output name="amount" for="hours rate vat">0</output></strong></p>
</form>

Финансовый калькулятор отображает результат в элементе <output>

См. живой пример

Ничего слишком сложного не происходит. На самом деле скрипты настолько простые, что даже я могу их сделать.

Немного спорный пример с использованием <input type="range">

В HTML5 также введён тип поля формы range, который в поддерживаемых браузеах отображается как ползунок. С помощью этого типа пользователь может ввести примерное значение в заданном диапазоне без необходимости быть совершенно точным или непосредственно вводить числовое значение. Для кроссбраузерности смотрите статью Реми Шарпа.

Пока писалась эта статья я нашёл ряд примеров использования элемента <output> в сочетании с <input type="range">, как показано в примере 5.

Пример. 5. Использование <input type="range"> с элементом <output>

<form onsubmit="return false" oninput="level.value = flevel.valueAsNumber">
  <label for="flying">Flying Skill Level</label>
  <input name="flevel" id="flying" type="range" min="0" max="100" value="0"> 
  <output for="flying" name="level">0</output>/100
</form>

Использование <input type="range"> с элементом <output>

См. живой пример

Использование <output> для показа текущего значения пользователю кажется мне вполне разумным применением, но это не результат вычислений как описано в спецификации. Несколько человек на канале IRC согласились со мной, поэтому я подал отчёт об ошибке, где просил внести поправки в определение. С момента написания этой статьи ошибка была решена и определение расширили, так что использование <output>, как показано выше, теперь корректно. Ура!

Поддержка в браузерах

Хорошая новость — все современные браузеры поддерживают в некоторой степени элемент <output>. Плохая новость в том, что есть несколько подводных камней.

Поддержка в браузерах
Браузер Поддержка
Chrome 13+
Safari 5.1+
Firefox 6+
Opera 9.20+
Internet Explorer 10+

Все примеры, которые мы видели до сих пор, должны безупречно работать в Opera 11.5 +, Safari 5.1+ и Chrome 13 +. IE, как и следовало ожидать, несколько отстаёт, <output> поддерживается в IE10 Platform Preview 2, а oninput поддерживается уже в IE9. Чтобы обойти это в наших простых примерах, мы должны вернуться к надёжному и проверенному getElementById и parseFloat (пример 6).

Пример. 6. Использование getElementById для поддержки старых браузеров

<form onsubmit="return false" oninput="document.getElementById('o').innerHTML = 
      parseFloat(document.getElementById('a').value) + 
      parseFloat(document.getElementById('b').value)">
  <input name="a" id="a" type="number" step="any"> +
  <input name="b" id="b" type="number" step="any"> =
  <output name="o" id="o" for="a b"></output>
</form>

См. живой пример

Это всё не идеально, зато будет работать до тех пор, пока отстающие браузеры не умрут медленной и мучительной смертью.

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

Виджеты

Для поддержки отстающих браузеров есть виджеты вроде HTML5 Widgets созданным Золтаном «Du Lac» Хорилюк. Золтан проведёт вас через процесс в своей подробной статье о создании кроссбраузерных форм с помощью html5Widgets.

Резюме

Вероятно вы не будете использовать элемент <output> всё время, но в ряде ситуаций он полезен. Вычисление значения на финансовых сайтах на лету или вывод текущей позиции курсора мыши, или, возможно, разница голов в спортивной таблице. Какие ещё варианты вы можете придумать для <output>? Дайте знать в комментариях!

Что ещё почитать

Статьи по теме

Не выкладывайте свой код напрямую в комментариях, он отображается некорректно. Воспользуйтесь сервисом cssdeck.com или jsfiddle.net, сохраните код и в комментариях дайте на него ссылку. Так и результат сразу увидят.