Элемент 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>
Заметьте, что мы используем стандартное событие 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>
Ничего слишком сложного не происходит. На самом деле скрипты настолько простые, что даже я могу их сделать.
Немного спорный пример с использованием <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>
Использование <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>? Дайте знать в комментариях!
Что ещё почитать
- WHATWG HTML Specification for <output>
- W3C Elements Wiki Page for <output>
- Wufoo HTML5 Forms Tests for <output>
- Mozilla Developer Network docs on <output>
- Is onforminput Deprecated in HTML5 Forms? (And Why Should I Care Anyways?) by Zoltan Hawryluk
- A HTML5 Browser Maze: oninput Support by Daniel Friessen
- Fixing oninput in IE Using html5Widgets by Zoltan Hawryluk