Зачем нужен метод preventdefault

GET-запрос

Формируя XMLHttpRequest, мы должны формировать запрос «руками», кодируя поля функцией .


Например, для посылки GET-запроса с параметрами и , аналогично форме выше, их необходимо закодировать так:

Прочие заголовки

Браузер автоматически добавит к запросу важнейшие HTTP-заголовки, такие как и .

По спецификации браузер запрещает их явную установку, как и некоторых других низкоуровневых HTTP-заголовков, которые могли бы ввести в заблуждение сервер относительно того, кто и сколько данных ему прислал, например . Это сделано в целях контроля правильности запроса и для безопасности.

Сообщаем про AJAX

Запрос, отправленный кодом выше через , никак не отличается от обычной отправки формы. Сервер не в состоянии их отличить.

Поэтому в некоторых фреймворках, чтобы сказать серверу, что это AJAX, добавляют специальный заголовок, например такой:

Browser compatibility

The compatibility table on this page is generated from structured data. If you’d like to contribute to the data, please check out https://github.com/mdn/browser-compat-data and send us a pull request.

Update compatibility data on GitHub

Chrome Edge Firefox Internet Explorer Opera Safari Android webview Chrome for Android Firefox for Android Opera for Android Safari on iOS Samsung Internet
Chrome Full support 1 Edge Full support 12 Firefox Full support 1 Notes IE Full support Yes Opera Full support Yes Safari Full support 1 WebView Android Full support Yes Chrome Android Full support Yes Firefox Android Full support 4 Notes Opera Android Full support Yes Safari iOS Full support Yes Samsung Internet Android Full support Yes

Реализация

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

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

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

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

Dealing with binary data

If you use a object with a form that includes widgets, the data will be processed automatically. But to send binary data by hand, there’s extra work to do.

There are many sources for binary data, including , , and WebRTC. Unfortunately, some legacy browsers can’t access binary data or require complicated workarounds. To learn more about the API, see Using files from web applications.


The least complicated way of sending binary data is by using ‘s method, demonstrated above. If you have to do it by hand, it’s trickier.

In the following example, we use the API to access binary data and then build the multi-part form data request by hand:

<form id="theForm">
  <p>
    <label for="theText">text data:</label>
    <input id="theText" name="myText" value="Some text data" type="text">
  </p>
  <p>
    <label for="theFile">file data:</label>
    <input id="theFile" name="myFile" type="file">
  </p>
  <button>Send Me!</button>
</form>

As you see, the HTML is a standard . There’s nothing magical going on. The «magic» is in the JavaScript:

// Because we want to access DOM nodes,
// we initialize our script at page load.
window.addEventListener( 'load', function () {

  // These variables are used to store the form data
  const text = document.getElementById( "theText" );
  const file = {
        dom    : document.getElementById( "theFile" ),
        binary : null
      };
 
  // Use the FileReader API to access file content
  const reader = new FileReader();

  // Because FileReader is asynchronous, store its
  // result when it finishes to read the file
  reader.addEventListener( "load", function () {
    file.binary = reader.result;
  } );

  // At page load, if a file is already selected, read it.
  if( file.dom.files ) {
    reader.readAsBinaryString( file.dom.files );
  }

  // If not, read the file once the user selects it.
  file.dom.addEventListener( "change", function () {
    if( reader.readyState === FileReader.LOADING ) {
      reader.abort();
    }
    
    reader.readAsBinaryString( file.dom.files );
  } );

  // sendData is our main function
  function sendData() {
    // If there is a selected file, wait it is read
    // If there is not, delay the execution of the function
    if( !file.binary && file.dom.files.length > 0 ) {
      setTimeout( sendData, 10 );
      return;
    }

    // To construct our multipart form data request,
    // We need an XMLHttpRequest instance
    const XHR = new XMLHttpRequest();

    // We need a separator to define each part of the request
    const boundary = "blob";

    // Store our body request in a string.
    let data = "";

    // So, if the user has selected a file
    if ( file.dom.files ) {
      // Start a new part in our body's request
      data += "--" + boundary + "\r\n";

      // Describe it as form data
      data += 'content-disposition: form-data; '
      // Define the name of the form data
            + 'name="'         + file.dom.name          + '"; '
      // Provide the real name of the file
            + 'filename="'     + file.dom.files.name + '"\r\n';
      // And the MIME type of the file
      data += 'Content-Type: ' + file.dom.files.type + '\r\n';

      // There's a blank line between the metadata and the data
      data += '\r\n';
      
      // Append the binary data to our body's request
      data += file.binary + '\r\n';
    }

    // Text data is simpler
    // Start a new part in our body's request
    data += "--" + boundary + "\r\n";

    // Say it's form data, and name it
    data += 'content-disposition: form-data; name="' + text.name + '"\r\n';
    // There's a blank line between the metadata and the data
    data += '\r\n';

    // Append the text data to our body's request
    data += text.value + "\r\n";

    // Once we are done, "close" the body's request
    data += "--" + boundary + "--";

    // Define what happens on successful data submission
    XHR.addEventListener( 'load', function( event ) {
      alert( 'Yeah! Data sent and response loaded.' );
    } );

    // Define what happens in case of error
    XHR.addEventListener( 'error', function( event ) {
      alert( 'Oops! Something went wrong.' );
    } );

    // Set up our request
    XHR.open( 'POST', 'https://example.com/cors.php' );

    // Add the required HTTP header to handle a multipart form data POST request
    XHR.setRequestHeader( 'Content-Type','multipart/form-data; boundary=' + boundary );

    // And finally, send our data.
    XHR.send( data );
  }

  // Access our form...
  const form = document.getElementById( "theForm" );

  // ...to take over the submit event
  form.addEventListener( 'submit', function ( event ) {
    event.preventDefault();
    sendData();
  } );
} );

Here’s the live result:

Example HTML code 2:

This example and the next one use AJAX to submit a form without reloading the page. The two examples are similar, but the first one uses synchronous while the second one uses asynchronous data transfer. In synchronous mode, the send method of the XMLHttpRequest object waits for a reply, so the user cannot interact with the browser until the response has completed. In asynchronous mode, the send method does not wait for a reply but instead returns immediately, so it allows you to perform other operations while a time-consuming task is being performed in the background.

Code ajax_form.js register.php
<head><scripttype="text/javascript"src="ajax_form.js"></script><style>.error {
            display none;
            color #a00000;
            font-weight bold;
        }
    </style><scripttype="text/javascript">function HideAllErrorFields () {
            for (var i = 1; i <= 4; i++) {
                var field = document.getElementById ("error" + i);
                field.style.display = "none";
            }
        }

        function ShowErrorFields (idsStr) {
            var ids = idsStr.split (",");
            for (var i = ; i < ids.length; i++) {
                var field = document.getElementById ("error" + ids);
                if (field) {
                    field.style.display = "block";
                }
            }
        }

        function AjaxSend (form, url, method) {
                // hide all error fields
            HideAllErrorFields ();
            
                // get message data
var data = GetMessageBody (form);   // defined in ajax_form.js
// send the request
var httpRequest = CreateRequestObj ();  // defined in ajax_form.js
// try..catch is required if working offline
try {
                httpRequest.open (method, url, false);  // synchron
                httpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
                httpRequest.send (data);
            }
            catch (e) {
                alert ("Cannot connect to the server!");
                return;
            }

                // handle the response
if (IsRequestSuccessful (httpRequest)) {    // defined in ajax_form.js
if (httpRequest.responseText === "ok") {    // registration is successful
alert ("Thank you for registering");
                    /*
                        // if redirection is required
                    location.href = "/index.php";
                    */
                }
                else {  // some fields are invalid
                    ShowErrorFields (httpRequest.responseText);
                }
            }
            else {
                alert ("An error occurred while registering. Please try it again.");
            }
        }
    </script></head><body>
    This is a sample registration form.
    The username must be between 2 and 20 characters, the password must be between 6 and 20 characters.
    A user named Dottoro is already registered.
    <br/>
    Try to register both valid and invalid values!
    <br/><br/><formonsubmit="AjaxSend (this, 'register.php', 'post'); return false;">
        User Name: <inputtype="text"name="userName"/><divclass="error"id="error1">Must be between 2 and 20 characters.</div><divclass="error"id="error2">A user already exists with the same name.</div><br/><br/>
        Password: <inputtype="password"name="password"/><divclass="error"id="error3">Must be between 6 and 20 characters.</div><br/><br/>
        Repeat Password: <inputtype="password"name="repassword"/><divclass="error"id="error4">Must be the same as the password.</div><br/><br/><inputtype="submit"value="Register"/></form></body>
Did you find this example helpful? yes no

Основы работы с формами

Пусть у нас в this.state.value хранится текст ‘привет’:

Теперь в методе render сделаем инпут, пока просто выведем его на экран:

Давайте теперь сделаем так, чтобы в value инпута записалось значение из this.state.value:

Запустите этот код — на экране вы увидите инпут с текстом ‘привет’. Однако, вас ждет сюрприз: вы не сможете поменять текст нашего инпута. Попробуйте сами — повводите что-нибудь в этот инпут — текст просто не будет меняться.

Почему так? Потому что мы четко сказали, что в value инпута должно быть значение из this.state.value. Это значение не меняется — и значит value инпута тоже не будет меняться, даже если вы вручную что-то попытаетесь туда написать.

Понятно, что такое поведение не очень удобно и нам нужно что-то с этим сделать. Что именно: нужно организовать двухстороннее связываниеthis.state.value и value инпута должны зависеть друг от друга: при изменении одного должен меняться и другой.

Первый шаг для этого следующий: нужно к нашему инпуту добавить событие onChange и привязать к нему какой-нибудь метод, назовем его, к примеру, handleChange.

Сделаем это:

Как работает событие onChange — оно срабатывает при попытке любого изменения инпута. Например, если мы пытаемся ввести в него какой-то текст, то onChange будет срабатывать при каждом вводе символа.

И, хотя текст инпута не будет меняться из-за привязанного this.state.value, событие onChange будет срабатывать и каждый раз вызывать метод handleChange.

Убедимся в этом — сделаем так, чтобы handleChange при каждом своем вызове выводил что-нибудь в браузер. Запустите следующий код, повводите что-нибудь в инпут и посмотрите в консоль — вы увидите, как при каждом вводе символа вызывается handleChange:

Давайте теперь сделаем так, чтобы содержимое инпута могло изменяться. Для этого в методе handleChange нужно в свойство this.state.value записывать содержимое атрибута value нашего инпута.

Однако, нас ждет некоторая неожиданность — мы не сможем получить value инпута так, как мы привыкли: такое — this.value — не будет работать, ведь this сейчас привязан с помощью bind к объекту нашего класса App и не указывает на инпут, в котором происходит событие.

Но как тогда обратиться к нашему инпуту? Ответ такой: с помощью объекта Event, вот так:

То есть: на наш инпут ссылается event.target, а значение инпута можно достать из event.target.value.

Вооружившись этим знаниями, привяжем теперь значение нашего инпута event.target.value к this.state.value с помощью метода this.setState:

Давайте соберем все вместе и запустим наш код (сделайте это) — теперь данные в инпут можно будет вводить:

Итак, сейчас любые изменения инпута мгновенно приводят к изменению this.state.value. Поэтому, если мы где-нибудь в JSX коде выведем содержимое this.state.value — оно мгновенно будет изменятся при вводе текста в инпут.

Давайте сделаем над нашим инпутом абзац, в который будем выводить содержимое this.state.value, вот так:

Добавим это изменение в наш класс:

HTML Ссылки

HTML по АлфавитуHTML по КатегориямHTML Атрибуты ТеговHTML Атрибуты ГлобалHTML Атрибуты СобытийHTML ЦветаHTML ХолстыHTML Аудио / ВидеоHTML Наборы символовHTML DOCTYPEsHTML Кодирование URLHTML Языковые кодыHTML Коды странHTTP Ответы сервераHTTP МетодыPX в EM конвертерГорячие клавиши

HTML Теги

<!—> <!DOCTYPE> <a> <abbr> <acronym> <address> <applet> <area> <article> <aside> <audio> <b> <base> <basefont> <bdi> <bdo> <big> <blockquote> <body> <br> <button> <canvas> <caption> <center> <cite> <code> <col> <colgroup> <data> <datalist> <dd> <del> <details> <dfn> <dialog> <dir> <div> <dl> <dt> <em> <embed> <fieldset> <figcaption> <figure> <font> <footer> <form> <frame> <frameset> <h1> — <h6> <head> <header> <hr> <html> <i> <iframe> <img> <input> <ins> <kbd> <label> <legend> <li> <link> <main> <map> <mark> <menu> <menuitem> <meta> <meter> <nav> <noframes> <noscript> <object> <ol> <optgroup> <option> <output> <p> <param> <picture> <pre> <progress> <q> <rp> <rt> <ruby> <s> <samp> <script> <section> <select> <small> <source> <span> <strike> <strong> <style> <sub> <summary> <sup> <svg> <table> <tbody> <td> <template> <textarea> <tfoot> <th> <thead> <time> <title> <tr> <track> <tt> <u> <ul> <var> <video> <wbr>

addEventListener

Фундаментальный недостаток описанных выше способов назначения обработчика –- невозможность повесить несколько обработчиков на одно событие.

Например, одна часть кода хочет при клике на кнопку делать её подсвеченной, а другая – выдавать сообщение.

Мы хотим назначить два обработчика для этого. Но новое DOM-свойство перезапишет предыдущее:

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

Синтаксис добавления обработчика:

Имя события, например .
Ссылка на функцию-обработчик.
Дополнительный объект со свойствами:
  • : если , тогда обработчик будет автоматически удалён после выполнения.
  • : фаза, на которой должен сработать обработчик, подробнее об этом будет рассказано в главе Всплытие и погружение. Так исторически сложилось, что может быть , это тоже самое, что .
  • : если , то указывает, что обработчик никогда не вызовет , подробнее об этом будет рассказано в главе Действия браузера по умолчанию.

Для удаления обработчика следует использовать :

Удаление требует именно ту же функцию

Для удаления нужно передать именно ту функцию-обработчик которая была назначена.

Вот так не сработает:


Обработчик не будет удалён, т.к

в передана не та же функция, а другая, с одинаковым кодом, но это не важно

Вот так правильно:

Обратим внимание – если функцию обработчик не сохранить где-либо, мы не сможем её удалить. Нет метода, который позволяет получить из элемента обработчики событий, назначенные через

Метод позволяет добавлять несколько обработчиков на одно событие одного элемента, например:

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

Обработчики некоторых событий можно назначать только через

Существуют события, которые нельзя назначить через DOM-свойство, но можно через .

Например, таково событие , которое срабатывает, когда завершена загрузка и построение DOM документа.

Так что более универсален. Хотя заметим, что таких событий меньшинство, это скорее исключение, чем правило.

JavaScript

JS Array concat() constructor copyWithin() entries() every() fill() filter() find() findIndex() forEach() from() includes() indexOf() isArray() join() keys() length lastIndexOf() map() pop() prototype push() reduce() reduceRight() reverse() shift() slice() some() sort() splice() toString() unshift() valueOf()

JS Boolean constructor prototype toString() valueOf()

JS Classes constructor() extends static super

JS Date constructor getDate() getDay() getFullYear() getHours() getMilliseconds() getMinutes() getMonth() getSeconds() getTime() getTimezoneOffset() getUTCDate() getUTCDay() getUTCFullYear() getUTCHours() getUTCMilliseconds() getUTCMinutes() getUTCMonth() getUTCSeconds() now() parse() prototype setDate() setFullYear() setHours() setMilliseconds() setMinutes() setMonth() setSeconds() setTime() setUTCDate() setUTCFullYear() setUTCHours() setUTCMilliseconds() setUTCMinutes() setUTCMonth() setUTCSeconds() toDateString() toISOString() toJSON() toLocaleDateString() toLocaleTimeString() toLocaleString() toString() toTimeString() toUTCString() UTC() valueOf()

JS Error name message

JS Global decodeURI() decodeURIComponent() encodeURI() encodeURIComponent() escape() eval() Infinity isFinite() isNaN() NaN Number() parseFloat() parseInt() String() undefined unescape()

JS JSON parse() stringify()

JS Math abs() acos() acosh() asin() asinh() atan() atan2() atanh() cbrt() ceil() cos() cosh() E exp() floor() LN2 LN10 log() LOG2E LOG10E max() min() PI pow() random() round() sin() sqrt() SQRT1_2 SQRT2 tan() tanh() trunc()

JS Number constructor isFinite() isInteger() isNaN() isSafeInteger() MAX_VALUE MIN_VALUE NEGATIVE_INFINITY NaN POSITIVE_INFINITY prototype toExponential() toFixed() toLocaleString() toPrecision() toString() valueOf()

JS OperatorsJS RegExp constructor compile() exec() g global i ignoreCase lastIndex m multiline n+ n* n? n{X} n{X,Y} n{X,} n$ ^n ?=n ?!n source test() toString() (x|y) . \w \W \d \D \s \S \b \B \0 \n \f \r \t \v \xxx \xdd \uxxxx

JS Statements break class continue debugger do…while for for…in for…of function if…else return switch throw try…catch var while

JS String charAt() charCodeAt() concat() constructor endsWith() fromCharCode() includes() indexOf() lastIndexOf() length localeCompare() match() prototype repeat() replace() search() slice() split() startsWith() substr() substring() toLocaleLowerCase() toLocaleUpperCase() toLowerCase() toString() toUpperCase() trim() valueOf()

Пример: поле с контролем СМС

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

Посмотрим, как их использовать, на примере.

Сделаем поле для СМС, рядом с которым должно показываться число символов, обновляющееся при каждом изменении поля.

Как такое реализовать?

Событие идеально решит задачу во всех браузерах, кроме IE9-. Собственно, если IE9- нам не нужен, то на этом можно и остановиться.

В IE8- событие не поддерживается, но, как мы видели ранее, есть , которое может заменить его.

Что же касается IE9 – там поддерживаются и и , но они оба не работают при удалении символов. Поэтому мы будем отслеживать удаление при помощи на Delete и BackSpace . А вот удаление командой «вырезать» из меню – сможет отловить лишь .


Получается вот такая комбинация:

Здесь мы добавили вызов на все события, которые могут приводить к изменению значения. Да, иногда изменение будет обрабатываться несколько раз, но зато с гарантией. А лишние вызовы легко убрать, например, при помощи -декоратора, описанного в задаче Тормозящий (throttling) декоратор.

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

Чтобы сэкономить ресурсы браузера, мы можем начинать отслеживание по , а прекращать – по , вот так:

Обратим внимание – весь этот «танец с бубном» нужен только для поддержки IE8-, в которых не поддерживается и IE9, где не работает при удалении

Методы объекта FormData

С помощью указанных ниже методов мы можем изменять поля в объекте :

  • – добавляет к объекту поле с именем и значением ,
  • – добавляет поле, как будто в форме имеется элемент , третий аргумент устанавливает имя файла (не имя поля формы), как будто это имя из файловой системы пользователя,
  • – удаляет поле с заданным именем ,
  • – получает значение поля с именем ,
  • – если существует поле с именем , то возвращает , иначе

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

Ещё существует метод , его синтаксис такой же, как у . Разница в том, что удаляет все уже имеющиеся поля с именем и только затем добавляет новое. То есть этот метод гарантирует, что будет существовать только одно поле с именем , в остальном он аналогичен :

  • ,
  • .

Поля объекта можно перебирать, используя цикл :

Пример использования

<!DOCTYPE html>
<html>
	<head>
		<title>Использование jQuery метода .submit() (без параметров и с функцией)</title>
		<script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
		<script>
	$( document ).ready(function(){
	  $( "button" ).click(function(){ // задаем функцию при нажатиии на элемент <button>
	    $( "form" ).submit(); // вызываем событие submit на элементе <form>
	  });
	  $( "form" ).submit(function( event ){ // задаем функцию при срабатывании события "submit" на элементе <form>
	    event.preventDefault(); // действие события по умолчанию не будет срабатывать
	    $( "span" ).text( "Form submitted" ) // добавляем текстовое содержимое в элемент <span>
	               .css({ 
	                 "display": "inline", // элемент <span> отображается как строчный
	                 "color": "forestgreen" // цвет текста светло-зеленый
	               })
	               .fadeOut( 1000 ); //  плавно изменяем прозрачность элемента <span> за 1 секунду 
	  });
	});
		</script>
	</head>
	<body>
		<button>Trigger submit</button><br><br>
		<form>
			<input type = "text" name = "login"  placeholder = "Login" required>
			<input type = "password" name = "password"  placeholder = "Password" required>
			<input type = "submit">
		</form>
	</body>
</html>

В этом примере с использованием jQuery метода .submit() мы при нажатии на элемент <button> (кнопка) вызываем событие «submit» на элементе <form>, которому задали, что при срабатывании события «submit» необходимо добавить с использованием jQuery метода .text() текстовое содержимое в элемент <span>, с использованием метода .css() установить этому элементу цвет текста светло-зеленый и строчное отображение, после этого с использованием эффекта .fadeOut() плавно изменить прозрачность элемента для его скрытия.

Обратите внимание, что эффект .fadeOut() устанавливает по завершению элементу свойство display в значение none (элемент не отображается), по этой причине мы каждый раз устанавливаем, что элемент должен быть строковый, для его отображения при следующем срабатывании события «submit». Кроме того, мы указали метод .preventDefault() объекта Event, благодаря которому, действие события по умолчанию не будет срабатывать (отправка данных формы в адресной строке — метод GET)

Обратите внимание, что при использовании метода .submit() без параметров мы можем инициировать событие «submit» и с пустыми полями не смотря на наличие атрибутов required. Результат нашего примера:

Результат нашего примера:

Пример использования jQuery метода .scroll() (без параметров и с функцией)jQuery события

HTML Reference

HTML by AlphabetHTML by CategoryHTML Browser SupportHTML AttributesHTML Global AttributesHTML EventsHTML ColorsHTML CanvasHTML Audio/VideoHTML Character SetsHTML DoctypesHTML URL EncodeHTML Language CodesHTML Country CodesHTTP MessagesHTTP MethodsPX to EM ConverterKeyboard Shortcuts

HTML Tags

<!—> <!DOCTYPE> <a> <abbr> <acronym> <address> <applet> <area> <article> <aside> <audio> <b> <base> <basefont> <bdi> <bdo> <big> <blockquote> <body> <br> <button> <canvas> <caption> <center> <cite> <code> <col> <colgroup> <data> <datalist> <dd> <del> <details> <dfn> <dialog> <dir> <div> <dl> <dt> <em> <embed> <fieldset> <figcaption> <figure> <font> <footer> <form> <frame> <frameset> <h1> — <h6> <head> <header> <hr> <html> <i> <iframe> <img> <input> <ins> <kbd> <label> <legend> <li> <link> <main> <map> <mark> <meta> <meter> <nav> <noframes> <noscript> <object> <ol> <optgroup> <option> <output> <p> <param> <picture> <pre> <progress> <q> <rp> <rt> <ruby> <s> <samp> <script> <section> <select> <small> <source> <span> <strike> <strong> <style> <sub> <summary> <sup> <svg> <table> <tbody> <td> <template> <textarea> <tfoot> <th> <thead> <time> <title> <tr> <track> <tt> <u> <ul> <var> <video> <wbr>

Немного спорный пример с использованием

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

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

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

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


С этим читают