Использование XMLHttpRequest - Интерфейсы веб API

Использование XMLHttpRequest
============================

Это инструкция по использованию `XMLHttpRequest` для обмена информацией между сайтом и сервером по HTTP-протоколу.

Мы разберём как частые примеры использования `XMLHttpRequest`, так и более редкие.

Для отправки HTTP-запроса нужно создать `XMLHttpRequest`-объект, указать URL и отправить запрос. В результате запроса мы получим от сервера объект с подробной информацией, вроде тела ответа и HTTP-статуса.

```js
function reqListener() {
  console.log(this.responseText);
}

const req = new XMLHttpRequest();
req.addEventListener("load", reqListener);
req.open("GET", "http://www.example.org/example.txt");
req.send();
```

Типы запросов
-------------

Запрос, сделанный посредством `XMLHttpRequest`, может загружать данные синхронно или асинхронно. Тип запроса определяется опциональным `async` аргументом (третий по счёту) метода `XMLHttpRequest.open()`. Если он равен `true` или не задан, запрос выполнится асинхронно, в противном случае — синхронно.

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

>
> **Обратите внимание:** Название `XMLHttpRequest` не означает, что вы можете передавать только XML документы. **"XML"** в названии остался из времён, когда основным форматом для обмена информацией был XML.
>
>
>

Обработка запросов
------------------

Конструктором `XMLHttpRequest()` определены несколько типов ответа. В ответе содержится важная информация о статусе запроса. При указании некоторых типов ответа могут потребоваться дополнительные действия для обработки и получения результата, рассмотрим эти случаи.

### Обработка и получение результата из responseXML

Если с помощью `XMLHttpRequest` загрузить XML-документ, в свойстве `responseXML` будет DOM-объект, содержащий распарсенный XML-документ, работать напрямую с которым будет сложно. Есть четыре основных способа анализа этого документа:

1. Использовать XPath (en-US) для обращения (или указания на) к части XML-документа.
2. Вручную конвертировать XML в строку или объект.
3. Использовать `XMLSerializer` для сериализации **DOM-дерева в строку**.
4. Использовать `RegExp`, если вам заранее известна структура документа. Возможно, потребуется удалить переносы строк из документа или учитывать их в `RegExp`. Однако, этот способ стоит использовать только в крайнем случае, ведь если XML-документ изменится хотя бы чуть-чуть, то регулярное выражение, скорее всего, уже не подойдёт.

>
> **Обратите внимание:** Теперь с помощью `responseXML` можно парсить HTML. Подробнее читайте в статье HTML в XMLHttpRequest (en-US).
>
>
>

### Получение HTML из responseText

Если вы используете `XMLHttpRequest` для получения содержимого HTML-страницы, в свойстве `responseText` будет "сырой" HTML, работать с которым неудобно. Есть три способа упростить работу с этим "сырым" HTML:

1. Использовать свойство `XMLHttpRequest.responseXML`, как показано в статье HTML в XMLHttpRequest (en-US).
2. Вставить содержимое в фрагмент с помощью `fragment.body.innerHTML` и работать уже с содержимым фрагмента как с DOM-деревом.
3. Использовать `RegExp`, если вам заранее известна структура HTML. Возможно, потребуется удалить переносы строк из содержимого или учитывать их в `RegExp`. Однако, этот способ стоит использовать только в крайнем случае, ведь если HTML изменится хотя бы чуть-чуть, то регулярное выражение, скорее всего, уже не подойдёт.
Работа с двоичными данными
--------------------------

Хотя обычно `XMLHttpRequest` используется для отправки и получения текстового содержимого, с его помощью можно обмениваться и двоичными данными. Есть несколько проверенных способов заставить `XMLHttpRequest` посылать двоичные данные. Они заключаются в использовании метода `overrideMimeType()` (en-US).

```js
const req = new XMLHttpRequest();
req.open("GET", url);
// просим извлечь данные в виде двоичной строки без обработки
req.overrideMimeType("text/plain; charset=x-user-defined");
/\* ... \*/
```

Однако, существуют и более современные способы, так как атрибут `responseType` теперь поддерживает ряд дополнительных типов содержимого, что существенно упрощает отправку и получение двоичных данных.

Для примера рассмотрим фрагмент, где используется "`arraybuffer`" как значение `responseType` для загрузки содержимого как объекта `ArrayBuffer`, в котором хранятся сырые двоичные данные.

```js
const req = new XMLHttpRequest();

req.onload = (e) => {
  const arraybuffer = req.response; // именно response, не responseText
  /\* ... \*/
};
req.open("GET", url);
req.responseType = "arraybuffer";
req.send();
```

Больше примеров в статье Отправка и получение бинарных данных.

Отслеживание прогресса загрузки
-------------------------------

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

Следуя спецификации `XMLHttpRequest` поддерживает событие `progress` (en-US) и реализует интерфейс `ProgressEvent` (en-US). Для получения информации о прогрессе загрузки используйте события:

`progress` (en-US)

Наступает каждый раз при изменении объёма переданных данных.

`load` (en-US)

Наступает по завершению передачи, когда все данные доступны в `response`.

```js
const req = new XMLHttpRequest();

req.addEventListener("progress", updateProgress);
req.addEventListener("load", transferComplete);
req.addEventListener("error", transferFailed);
req.addEventListener("abort", transferCanceled);

req.open();

// ...

// отслеживание прогресса передачи от сервера к клиенту (загрузка)
function updateProgress(event) {
  if (event.lengthComputable) {
    const percentComplete = (event.loaded / event.total) \* 100;
    // ...
  } else {
    // невозможно вычислить состояние загрузки, так как размер неизвестен
  }
}

function transferComplete(evt) {
  console.log("Загрузка завершена.");
}

function transferFailed(evt) {
  console.log("При загрузке произошла ошибка.");
}

function transferCanceled(evt) {
  console.log("Пользователь отменил загрузку.");
}
```

В 3-6 строках добавляются обработчики для различных событий, происходящих при передаче данных с помощью `XMLHttpRequest`.

>
> **Важно:** Обработчики нужно добавлять до вызова метода `open()`. В противном случае `progress`-события не будут обработаны.
>
>
>

Обработчик события `progress`, представленный функцией `updateProgress()` в этом примере, получает количество байт, которое должно быть передано, и количество уже переданных байт в полях `total` и `loaded.` Но если длина сообщения неизвестна, поле `lengthComputable` будет равно `false`.

События о ходе выполнения есть как у входящих, так и у исходящих передач. Обработчики событий входящих передач задаются для объекта `XMLHttpRequest`, как в примере выше, а для исходящих — на `XMLHttpRequest.upload`:

```js
const req = new XMLHttpRequest();

req.upload.addEventListener("progress", updateProgress);
req.upload.addEventListener("load", transferComplete);
req.upload.addEventListener("error", transferFailed);
req.upload.addEventListener("abort", transferCanceled);

req.open();
```

>
> **Обратите внимание:** отслеживание прогресса недоступно для протокола `file:`.
>
>
>

События о ходе выполнения наступают для каждого полученного пакета данных, включая последний, поэтому в случае, когда последний пакет получен и соединение закрыто, событие `progress` всё равно наступит. Это позволяет нам отслеживать прогресс, добавляя обработчик только для `progress`-события.

Также можно обработать все три события, завершающие загрузку (`abort`, `load`, or `error`) через событие `loadend`:

```js
req.addEventListener("loadend", loadEnd);

function loadEnd(e) {
  console.log("Передача данных завершена (но мы не знаем, успешно ли).");
}
```

Заметьте, что событие `loadend` никак не сообщает, что вызвало конец передачи. Впрочем, это никак не мешает использовать его, если нужно сделать что-то вне зависимости от причины.

Отправка форм и загрузка файлов
-------------------------------

Есть два способа передать данные форм с помощью `XMLHttpRequest`:

* без помощи других API, используя только XHR;
* с помощью `FormData` API.

FormData API – самый простой и быстрый способ, но данные, полученные с его помощью, нельзя превратить в строку с помощью JSON.stringify. Использование только XHR сложнее, но этот способ самый гибкий и мощный.

### Используя только `XMLHttpRequest`

Отправка формы без FormData API в большинстве случаев не требует других API. Единственное исключение, *если вам нужно отправить один или несколько файлов*, тогда придётся использовать `FileReader` API.

#### Краткое введение в методы отправки

HTML-форму `<form>` можно отправить четырьмя способами:

* использовать метод `POST` и установить атрибут `enctype` в значении `application/x-www-form-urlencoded` (способ по умолчанию);
* использовать метод `POST` и установить атрибут `enctype` в значении `text/plain`;
* использовать метод `POST` и установить атрибут `enctype` в значении `multipart/form-data`;
* использовать метод `GET` (в этом случае атрибут `enctype` будет проигнорирован).

Рассмотрим отправку формы с двумя полями: `foo` и `baz`. Если использовать метод `POST`, сервер получит строку, похожую на одну из показанных ниже, в зависимости от типа кодирования, который вы используете:

* Метод: `POST`; тип кодирования: `application/x-www-form-urlencoded` (по умолчанию):
```

Content-Type: application/x-www-form-urlencoded

foo=bar&baz=The+first+line.%0D%0AThe+second+line.%0D%0A
```

* Метод: `POST`; тип кодирования: `text/plain`:
```

Content-Type: text/plain

foo=bar
baz=The first line.
The second line.
```

* Метод: `POST`; тип кодирования: `multipart/form-data`:
```

Content-Type: multipart/form-data; boundary=---------------------------314911788813839

-----------------------------314911788813839
Content-Disposition: form-data; name="foo"

bar
-----------------------------314911788813839
Content-Disposition: form-data; name="baz"

The first line.
The second line.

-----------------------------314911788813839--
```

А если вы решите использовать метод `GET`, к адресу формы будет добавлена строка вида:
```

?foo=bar&baz=The%20first%20line.%0AThe%20second%20line.
```

#### Небольшой классический фреймворк

Всё это возможно благодаря браузеру и тегу `<form>`. Но если вам требуется выполнить все операции только с помощью JavaScript, вам придётся проинструктировать интерпретатор обо *всех* выполняемых операциях. Отправка формы с помощью *чистого* XHR слишком сложна, чтобы рассказать вам о ней во всех деталях. Поэтому мы решили опубликовать здесь **целый (пусть и учебный) фреймворк**, который поддерживает все четыре способа отправки и даже **загрузку файлов**:

```html
<!doctype html>
<html lang="en-US">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Sending forms with pure AJAX – MDN</title>
    <script>
 "use strict";

 // :: XHR Form Submit Framework ::
 //
 // https://developer.mozilla.org/ru/docs/DOM/XMLHttpRequest/Using\_XMLHttpRequest
 //
 // This framework is released under the GNU Public License, version 3 or later.
 // https://www.gnu.org/licenses/gpl-3.0-standalone.html
 //
 // Syntax:
 //
 // XHRSubmit(HTMLFormElement);
 const XHRSubmit = (function () {
 function xhrSuccess() {
 console.log(this.responseText);
 // you can get the serialized data through the "submittedData" custom property:
 // console.log(JSON.stringify(this.submittedData));
 }

 function submitData(data) {
 const req = new XMLHttpRequest();
 req.submittedData = data;
 req.onload = xhrSuccess;
 if (data.technique === 0) {
 // method is GET
 req.open(
 "get",
 data.receiver.replace(
 /(?:\?.\*)?$/,
 data.segments.length > 0 ? `?${data.segments.join("&")}` : "",
 ),
 true,
 );
 req.send(null);
 } else {
 // method is POST
 req.open("post", data.receiver, true);
 if (data.technique === 3) {
 // enctype is multipart/form-data
 const boundary =
 "---------------------------" + Date.now().toString(16);
 req.setRequestHeader(
 "Content-Type",
 `multipart\/form-data; boundary=${boundary}`,
 );
 req.sendAsBinary(
 `--${boundary}\r\n` +
 data.segments.join(`--${boundary}\r\n`) +
 `--${boundary}--\r\n`,
 );
 } else {
 // enctype is application/x-www-form-urlencoded or text/plain
 req.setRequestHeader("Content-Type", data.contentType);
 req.send(data.segments.join(data.technique === 2 ? "\r\n" : "&"));
 }
 }
 }

 function processStatus(data) {
 if (data.status > 0) {
 return;
 }
 // the form is now totally serialized! do something before sending it to the server…
 // doSomething(data);
 // console.log("XHRSubmit - The form is now serialized. Submitting...");
 submitData(data);
 }

 function pushSegment(segment) {
 this.owner.segments[this.segmentIdx] +=
 segment.target.result + "\r\n";
 this.owner.status--;
 processStatus(this.owner);
 }

 function plainEscape(text) {
 // How should I treat a text/plain form encoding?
 // What characters are not allowed? this is what I suppose…:
 // "4\3\7 - Einstein said E=mc2" ----> "4\\3\\7\ -\ Einstein\ said\ E\=mc2"
 return text.replace(/[\s\=\\]/g, "\\$&");
 }

 function SubmitRequest(target) {
 const isPost = target.method.toLowerCase() === "post";
 this.contentType =
 isPost && target.enctype
 ? target.enctype
 : "application\/x-www-form-urlencoded";
 this.technique = isPost
 ? this.contentType === "multipart\/form-data"
 ? 3
 : this.contentType === "text\/plain"
 ? 2
 : 1
 : 0;
 this.receiver = target.action;
 this.status = 0;
 this.segments = [];
 const filter = this.technique === 2 ? plainEscape : escape;
 for (const field of target.elements) {
 if (!field.hasAttribute("name")) {
 continue;
 }
 const fieldType =
 field.nodeName.toUpperCase() === "INPUT" &&
 field.hasAttribute("type")
 ? field.getAttribute("type").toUpperCase()
 : "TEXT";
 if (fieldType === "FILE" && field.files.length > 0) {
 if (this.technique === 3) {
 // enctype is multipart/form-data
 for (const file of field.files) {
 const segmReq = new FileReader();

 // Custom properties:
 segmReq.segmentIdx = this.segments.length;
 segmReq.owner = this;

 segmReq.onload = pushSegment;
 this.segments.push(
 'Content-Disposition: form-data; name="' +
 field.name +
 '"; filename="' +
 file.name +
 '"\r\nContent-Type: ' +
 file.type +
 "\r\n\r\n",
 );
 this.status++;
 segmReq.readAsBinaryString(file);
 }
 } else {
 // enctype is application/x-www-form-urlencoded or text/plain or
 // method is GET: files will not be sent!
 for (const file of field.files) {
 this.segments.push(
 `${filter(field.name)}=${filter(file.name)}`,
 );
 }
 }
 } else if (
 (fieldType !== "RADIO" && fieldType !== "CHECKBOX") ||
 field.checked
 ) {
 // NOTE: this will submit \_all\_ submit buttons. Detecting the correct one is non-trivial.
 // field type is not FILE or is FILE but is empty.
 if (this.technique === 3) {
 // enctype is multipart/form-data
 this.segments.push(
 `Content-Disposition: form-data; name="${field.name}"\r\n\r\n${field.value}\r\n`,
 );
 } else {
 // enctype is application/x-www-form-urlencoded or text/plain or method is GET
 this.segments.push(
 `${filter(field.name)}=${filter(field.value)}`,
 );
 }
 }
 }
 processStatus(this);
 }

 return (formElement) => {
 if (!formeElement.action) {
 return;
 }
 new SubmitRequest(formElement);
 };
 })();
 </script>
  </head>
  <body>
    <h1>Sending forms with XHR</h1>

    <h2>Using the GET method</h2>

    <form
 action="register.php"
 method="get"
 onsubmit="AJAXSubmit(this); return false;">
      <fieldset>
        <legend>Registration example</legend>
        <p>
          <label>First name: <input type="text" name="firstname" /></label
 ><br />
          <label>Last name: <input type="text" name="lastname" /></label>
        </p>
        <p>
          <input type="submit" value="Submit" />
        </p>
      </fieldset>
    </form>

    <h2>Using the POST method</h2>
    <h3>Enctype: application/x-www-form-urlencoded (default)</h3>

    <form
 action="register.php"
 method="post"
 onsubmit="AJAXSubmit(this); return false;">
      <fieldset>
        <legend>Registration example</legend>
        <p>
          <label>First name: <input type="text" name="firstname" /></label>
          <br />
          <label>Last name: <input type="text" name="lastname" /></label>
        </p>
        <p>
          <input type="submit" value="Submit" />
        </p>
      </fieldset>
    </form>

    <h3>Enctype: text/plain</h3>

    <form
 action="register.php"
 method="post"
 enctype="text/plain"
 onsubmit="AJAXSubmit(this); return false;">
      <fieldset>
        <legend>Registration example</legend>
        <p>
          <label
 >Your name:
            <input type="text" name="user" />
          </label>
        </p>
        <p>
          <label
 >Your message:<br />
            <textarea name="message" cols="40" rows="8"></textarea>
          </label>
        </p>
        <p>
          <input type="submit" value="Submit" />
        </p>
      </fieldset>
    </form>

    <h3>Enctype: multipart/form-data</h3>

    <form
 action="register.php"
 method="post"
 enctype="multipart/form-data"
 onsubmit="AJAXSubmit(this); return false;">
      <fieldset>
        <legend>Upload example</legend>
        <p>
          <label>First name: <input type="text" name="firstname" /></label
 ><br />
          <label>Last name: <input type="text" name="lastname" /></label><br />
          Sex:
          <input id="sex\_male" type="radio" name="sex" value="male" />
          <label for="sex\_male">Male</label>
          <input id="sex\_female" type="radio" name="sex" value="female" />
          <label for="sex\_female">Female</label><br />
          Password: <input type="password" name="secret" /><br />
          <label
 >What do you prefer:
            <select name="image\_type">
              <option>Books</option>
              <option>Cinema</option>
              <option>TV</option>
            </select>
          </label>
        </p>
        <p>
          <label
 >Post your photos:
            <input type="file" multiple name="photos[]" />
          </label>
        </p>
        <p>
          <input
 id="vehicle\_bike"
 type="checkbox"
 name="vehicle[]"
 value="Bike" />
          <label for="vehicle\_bike">I have a bike</label><br />
          <input
 id="vehicle\_car"
 type="checkbox"
 name="vehicle[]"
 value="Car" />
          <label for="vehicle\_car">I have a car</label>
        </p>
        <p>
          <label
 >Describe yourself:<br />
            <textarea name="description" cols="50" rows="8"></textarea>
          </label>
        </p>
        <p>
          <input type="submit" value="Submit" />
        </p>
      </fieldset>
    </form>
  </body>
</html>
```

Чтобы воспользоваться фреймворком, создайте страницу с названием **register.php** (и укажите его в атрибуте `action` одной из форм в примере) с *минимальным* содержимым:

```php
<?php
 /\* register.php \*/

 header("Content-type: text/plain");

 /\*
 NOTE: You should never use `print\_r()` in production scripts, or
 otherwise output client-submitted data without sanitizing it first.
 Failing to sanitize can lead to cross-site scripting vulnerabilities.
 \*/

 echo ":: data received via GET ::\n\n";
 print\_r($\_GET);

 echo "\n\n:: Data received via POST ::\n\n";
 print\_r($\_POST);

 echo "\n\n:: Data received as \"raw\" (text/plain encoding) ::\n\n";
 if (isset($HTTP\_RAW\_POST\_DATA)) { echo $HTTP\_RAW\_POST\_DATA; }

 echo "\n\n:: Files received ::\n\n";
 print\_r($\_FILES);
>
```

Для активации выполните код:

```js
XHRSubmit(myForm);
```

>
> **Важно:** Наш фреймворк использует `FileReader` API для передачи файлов. Это новый API и его невозможно использовать в IE9 и ниже. В связи с этим, загрузки только с использованием AJAX воспринимаются лишь как **экспериментальные**. Если вам не требуется загружать бинарные файлы, то данный фреймворк работает в большинстве современных браузеров.
>
>
>

>
> **Обратите внимание:** Лучший способ отправить бинарные данные – использовать `ArrayBuffers` или `Blobs` в связке с методом `send()` и методом `readAsArrayBuffer()` из `FileReader` API. Но так как цель нашего примера – поддержка возможности представить сырые данные в виде строки, мы использовали метод `sendAsBinary()` в связке с `readAsBinaryString()` из `FileReader` API. Таким образом, приведенный выше код имеет смысл использовать только в том случае, если вы имеете дело с небольшими файлами. Если вы не планируете загружать двоичное содержимое, вместо этого воспользуйтесь `FormData` API.
>
>
>

### Используя FormData

 The `FormData` constructor lets you compile a
 set of key/value pairs to send using `XMLHttpRequest`. Its primary use is in
 sending form data, but can also be used independently from a form in order to transmit
 user keyed data. The transmitted data is in the same format the form's
 `submit()` method uses to send data, if the form's encoding type were set to
 "multipart/form-data". FormData objects can be utilized in a number of ways with an
 `XMLHttpRequest`. For examples, and explanations of how one can utilize
 FormData with XMLHttpRequests, see the Using FormData Objects page. For didactic purposes here is **a *translation* of the previous example transformed to use the
`FormData` API**. Note the brevity of the code:

```html
<!doctype html>
<html lang="en-US">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Sending forms with FormData – MDN</title>
    <script>
 "use strict";

 function xhrSuccess () {
 console.log(this.responseText);
 }

 function XHRSubmit (formElement) {
 if (!formElement.action) { return; }
 const req = new XMLHttpRequest();
 req.onload = xhrSuccess;
 if (fFormElement.method.toLowerCase() === "post") {
 req.open("post", formElement.action);
 req.send(new FormData(formElement));
 } else {
 let search = "";
 for (const field of formElement.elements) {
 if (!field.hasAttribute("name")) { continue; }
 const fieldType = field.nodeName.toUpperCase() === "INPUT" && oField.hasAttribute("type")
 ? field.getAttribute("type").toUpperCase()
 : "TEXT";
 if (fieldType === "FILE") {
 for (const file of field.files) {
 search += `&${escape(field.name)}=${escape(file.name)}`;
 } else if ((fieldType !== "RADIO" && fieldType !== "CHECKBOX") || field.checked) {
 search += `&${escape(field.name)}=${escape(field.value)}`;
 }
 }
 req.open("get", formElement.action.replace(/(?:\?.\*)?$/, search.replace(/^&/, "?")), true);
 req.send(null);
 }
 }
 </script>
  </head>
  <body>
    <h1>Sending forms with FormData</h1>

    <h2>Using the GET method</h2>

    <form
 action="register.php"
 method="get"
 onsubmit="AJAXSubmit(this); return false;">
      <fieldset>
        <legend>Registration example</legend>
        <p>
          First name: <input type="text" name="firstname" /><br />
          Last name: <input type="text" name="lastname" />
        </p>
        <p>
          <input type="submit" value="Submit" />
        </p>
      </fieldset>
    </form>

    <h2>Using the POST method</h2>
    <h3>Enctype: application/x-www-form-urlencoded (default)</h3>

    <form
 action="register.php"
 method="post"
 onsubmit="AJAXSubmit(this); return false;">
      <fieldset>
        <legend>Registration example</legend>
        <p>
          First name: <input type="text" name="firstname" /><br />
          Last name: <input type="text" name="lastname" />
        </p>
        <p>
          <input type="submit" value="Submit" />
        </p>
      </fieldset>
    </form>

    <h3>Enctype: text/plain</h3>

    <p>The text/plain encoding is not supported by the FormData API.</p>

    <h3>Enctype: multipart/form-data</h3>

    <form
 action="register.php"
 method="post"
 enctype="multipart/form-data"
 onsubmit="AJAXSubmit(this); return false;">
      <fieldset>
        <legend>Upload example</legend>
        <p>
          First name: <input type="text" name="firstname" /><br />
          Last name: <input type="text" name="lastname" /><br />
          Sex:
          <input id="sex\_male" type="radio" name="sex" value="male" />
          <label for="sex\_male">Male</label>
          <input id="sex\_female" type="radio" name="sex" value="female" />
          <label for="sex\_female">Female</label><br />
          Password: <input type="password" name="secret" /><br />
          What do you prefer:
          <select name="image\_type">
            <option>Books</option>
            <option>Cinema</option>
            <option>TV</option>
          </select>
        </p>
        <p>
          Post your photos:
          <input type="file" multiple name="photos[]" />
        </p>
        <p>
          <input
 id="vehicle\_bike"
 type="checkbox"
 name="vehicle[]"
 value="Bike" />
          <label for="vehicle\_bike">I have a bike</label><br />
          <input
 id="vehicle\_car"
 type="checkbox"
 name="vehicle[]"
 value="Car" />
          <label for="vehicle\_car">I have a car</label>
        </p>
        <p>
          Describe yourself:<br />
          <textarea name="description" cols="50" rows="8"></textarea>
        </p>
        <p>
          <input type="submit" value="Submit" />
        </p>
      </fieldset>
    </form>
  </body>
</html>
```

>
>
> **Note:** As we said, **`FormData`
> objects are not stringifiable objects**. If you want to stringify a submitted data, use the previous *pure*-AJAX example. Note
>  also that, although in this example there are some `file` `<input>` fields, **when you submit a form through the
> `FormData` API you do not need to use the `FileReader` API
> also**: files are automatically loaded and uploaded.
>
>
>
>

Получаем дату последнего изменения
----------------------------------

```js
function getHeaderTime() {
  console.log(this.getResponseHeader("Last-Modified")); // Дата вида GMTString или null
}

const req = new XMLHttpRequest();
req.open(
  "HEAD", // используется HEAD только если сервер требует заголовки
  "yourpage.html",
);
req.onload = getHeaderTime;
req.send();
```

### Do something when last modified date changes

Let's create two functions:

```js
function getHeaderTime() {
  const lastVisit = parseFloat(
    window.localStorage.getItem(`lm\_${this.filepath}`),
  );
  const lastModified = Date.parse(this.getResponseHeader("Last-Modified"));

  if (isNaN(lastVisit) || lastModified > lastVisit) {
    window.localStorage.setItem(`lm\_${this.filepath}`, Date.now());
    isFinite(lastVisit) && this.callback(lastModified, lastVisit);
  }
}

function ifHasChanged(URL, callback) {
  const req = new XMLHttpRequest();
  req.open("HEAD" /\* use HEAD - we only need the headers! \*/, URL);
  req.callback = callback;
  req.filepath = URL;
  req.onload = getHeaderTime;
  req.send();
}
```

And to test:

```js
// Let's test the file "yourpage.html"
ifHasChanged("yourpage.html", function (modified, visit) {
  console.log(
    `The page '${this.filepath}' has been changed on ${new Date(
 nModified,
 ).toLocaleString()}!`,
  );
});
```

If you want to know if the current page has changed, refer to the article about `document.lastModified` (en-US).

Межсайтовые XMLHttpRequest
--------------------------

Современные браузеры поддерживают межсайтовые запросы по стандарту Cross-Origin Resource Sharing (CORS). Для этого серверу необходимо дополнительно указывать заголовок `origin`. В противном случае, выбрасывается исключение `INVALID_ACCESS_ERR`.

Обход кеширования
-----------------

Для межсайтового обхода кеширования в конец URL-запроса достаточно добавить случайную строку в GET-параметры, то есть сразу после «?», например:
```

http://foo.com/bar.html -> http://foo.com/bar.html?12345
http://foo.com/bar.html?foobar=baz -> http://foo.com/bar.html?foobar=baz&12345
```

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

Автоматизировать этот подход можно следующим образом:

```js
const req = new XMLHttpRequest();

req.open("GET", url + (/\?/.test(url) ? "&" : "?") + new Date().getTime());
req.send(null);
```

Безопасность
------------

Рекомендуемый способ разрешить межсайтовые запросы - использовать HTTP-заголовок `Access-Control-Allow-Origin` в ответе на XMLHttpRequest.

### XMLHttpRequests был остановлен

Если в завершение XMLHttpRequest вы получаете `status=0` и `statusText=null` – это означает, что запрос не был разрешен к выполнению. Его статус остался `UNSENT`. Частая причина, что указанный `XMLHttpRequest` origin (во время создания XMLHttpRequest) был изменён в следствии вызова `open()`. Такое может произойти, например, когда есть XMLHttpRequest, который запускается при событии onunload окна. XMLHttpRequest создается, когда окно, которое должно быть закрыто, всё ещё существует, но отправка запроса (другими словами, вызов `open()`) происходит, когда это окно уже потеряло свой фокус, а другое – получило. Наиболее эффективный способ избежать этой проблемы - установить слушателя на событие нового окна `DOMActivate` (en-US), которое устанавливается, как только у закрытого окна срабатывает событие `unload`.

Спецификации
------------

| Specification |
| --- |
| XMLHttpRequest Standard # interface-xmlhttprequest |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* Использование Fetch API
* HTML в XMLHttpRequest (en-US)
* Контроль доступа в HTTP
* XMLHttpRequest - REST and the Rich User Experience
* Объект `XMLHttpRequest`: спецификация WHATWG


Использование Объектов FormData - Интерфейсы веб API

Использование Объектов FormData
===============================

Объект `FormData` позволяет создать набор пар ключ/значение и передать их, используя `XMLHttpRequest.` Объект `FormData` предназначен для передачи данных форм, однако может быть использован для передачи пар ключ/значение независимо от форм. Данные передаются в том же формате, как и данные, передаваемые методом ``submit()`` формы, с установленной кодировкой `enctype="multipart/form-data"`.

Создание объекта FormData
-------------------------

Вы можете самостоятельно создать пустой объект `FormData`, наполнив его затем данными, используя его метод ``append()`:`

```js
var formData = new FormData();

formData.append("username", "Groucho");
formData.append("accountnum", 123456); // число 123456 немедленно преобразуется в строку "123456"

// Файл, выбранный пользователем
formData.append("userfile", fileInputElement.files[0]);

// JavaScript Blob объект
var content = '<a id="a"><b id="b">hey!</b></a>'; // содержимое нового файла...
var blob = new Blob([content], { type: "text/xml" });

formData.append("webmasterfile", blob);

var request = new XMLHttpRequest();
request.open("POST", "http://foo.com/submitform.php");
request.send(formData);
```

**Примечание:** Поля "userfile" и "webmasterfile" оба содержат файлы. Число, переданное полю "accountnum" немедленно преобразуется в строку. Преобразование осуществляется методом `FormData.append()` (Значение поля может быть `Blob`, `File`, или строкой: **если значение не является ни Blob, ни File, то оно автоматически преобразуется в строку).**

Данный пример показывает создание экземпляра `FormData`, содержащего поля "username", "accountnum", "userfile" и "webmasterfile". Экземпляр `FormData` затем отправляется при помощи метода `send()` объекта `XMLHttpRequest`. Поле "webmasterfile" является экземпляром класса ``Blob``. Объект класса `Blob` является файлом-подобным объектом, содержащим "сырые" данные. Определение данных как `Blob` не является обязательным в нативном javascript. Интерфейс``File``базируется на `Blob`, наследуя его функциональность и расширяя его для поддержки файлов в ОС пользователя. Для создания объектов класса `Blob` используйте ``Blob() constructor``.

Получение объекта FormData из HTML формы
----------------------------------------

Для создания объекта `FormDatа`, содержащего данные существующей формы (`<form>`) передайте форму в качестве аргумента при создании объекта `FormData:`

>
> \*\*Примечание:\*\*FormData будет использовать только те поля ввода, которые используют атрибут name.
>
>
>

```js
var formData = new FormData(someFormElement);
```

Например:

```js
var formElement = document.querySelector("form");
var request = new XMLHttpRequest();
request.open("POST", "submitform.php");
request.send(new FormData(formElement));
```

Вы так же можете добавить дополнительные данные в объект `FormData` после его создания и до отправки данных:

```js
var formElement = document.querySelector("form");
var formData = new FormData(formElement);
var request = new XMLHttpRequest();
request.open("POST", "submitform.php");
formData.append("serialnumber", serialNumber++);
request.send(formData);
```

Такой приём позволяет включать в форму дополнительную информацию, которая, например, не нуждается в демонстрации пользователю.

Отправка файлов при помощи объекта FormData
-------------------------------------------

Вы так же можете отправлять файлы при помощи `FormData`. Просто включите `<input>` с типом `file` в форму.

```html
<form enctype="multipart/form-data" method="post" name="fileinfo">
  <label>Your email address:</label>
  <input
 type="email"
 autocomplete="on"
 autofocus
 name="userid"
 placeholder="email"
 required
 size="32"
 maxlength="64" /><br />
  <label>Custom file label:</label>
  <input type="text" name="filelabel" size="12" maxlength="32" /><br />
  <label>File to stash:</label>
  <input type="file" name="file" required />
  <input type="submit" value="Stash the file!" />
</form>
<div></div>
```

Затем вы сможете отправить выбранный файл следующим образом:

```js
var form = document.forms.namedItem("fileinfo");
form.addEventListener(
  "submit",
  function (ev) {
    var oOutput = document.querySelector("div"),
      oData = new FormData(form);

    oData.append("CustomField", "This is some extra data");

    var oReq = new XMLHttpRequest();
    oReq.open("POST", "stash.php", true);
    oReq.onload = function (oEvent) {
      if (oReq.status == 200) {
        oOutput.innerHTML = "Uploaded!";
      } else {
        oOutput.innerHTML =
          "Error " +
          oReq.status +
          " occurred when trying to upload your file.<br />";
      }
    };

    oReq.send(oData);
    ev.preventDefault();
  },
  false,
);
```

**Примечание:** Если для формы указан атрибут `method`, то будет использован именно этот метод для отправки данных на сервер, а не метод, указанный в вызове `open()`

Вы так же можете добавить ``File`` или ``Blob`` непосредственно к объекту ``FormData`:`

```js
data.append("myfile", myBlob, "filename.txt");
```

Метод `append()` принимает 3й опциональный параметр - название файла, которое добавляется в заголовок `Content-Disposition` при отправке на сервер. Если название файла не указано (или данный параметр не поддерживается) используется имя "blob".

Вы так же можете использовать `FormData` с jQuery:

```js
var fd = new FormData(document.querySelector("form"));
fd.append("CustomField", "This is some extra data");
$.ajax({
  url: "stash.php",
  type: "POST",
  data: fd,
  processData: false, // Сообщить jQuery не передавать эти данные
  contentType: false, // Сообщить jQuery не передавать тип контента
});
```

Отправка форм и файлов при помощи AJAX *без использования* объекта `FormData`
-----------------------------------------------------------------------------

Если вы заинтересованы в отправке форм и файлов при помощи AJAX *без использования* FormData, прочитайте /ru/docs/Web/API/XMLHttpRequest\_API/Using\_XMLHttpRequest#Submitting\_forms\_and\_uploading\_files

See also
--------

* Using XMLHttpRequest
* `HTMLFormElement` (en-US)
* `Blob`
* Typed Arrays


ValidityState.patternMismatch - Интерфейсы веб API

ValidityState.patternMismatch
=============================

Baseline 2023
-------------

Newly availableSince March 2023, this feature works across the latest devices and browser versions. This feature might not work in older devices or browsers.

* Learn more
* See full compatibility
* Report feedback
Доступное только для чтения свойство **`patternMismatch`** объекта **`ValidityState`** указывает, соответствует ли значение `<input>` шаблону, указанному в атрибуте `pattern`.

Если поле поддерживает атрибут `pattern`, это значит, что `<input>` содержит `type` text (en-US), tel, email (en-US), url (en-US), password или search (en-US) и в значении атрибута задано валидное регулярное выражение. Если значение не соответствует ограничениям, заданным в `pattern`, свойство `patternMismatch` будет `true`.

Примеры
-------

Учитывая следующее:

```html
<p>
  <label
 >Enter your phone number in the format (123)456-7890 (<input
 name="tel1"
 type="tel"
 pattern="[0-9]{3}"
 placeholder="###"
 aria-label="3-digit area code"
 size="2" />)-
    <input
 name="tel2"
 type="tel"
 pattern="[0-9]{3}"
 placeholder="###"
 aria-label="3-digit prefix"
 size="2" />
    -
    <input
 name="tel3"
 type="tel"
 pattern="[0-9]{4}"
 placeholder="####"
 aria-label="4-digit number"
 size="3" />
  </label>
</p>
```

Здесь у нас есть 3 поля для номера телефона северной Америки, помещённых внутрь `label`. В каждом поле, как определено в атрибуте `pattern`, ожидается ввод 3, 3 и 4 символов соответственно.

Если значения слишком длинные, слишком короткие или содержат не цифровые символы, `patternMismatch` будет `true`. Если `true`, элемент соответствует CSS-псевдоклассу`:invalid`.

```css
input:invalid {
  border: red solid 3px;
}
```

Обратите внимание, что в данном примере мы получаем значение свойства `patternMismatch`, а не `validityState.tooLong` или `validityState.tooShort`, потому что ограничения заданы именно с помощью атрибута `pattern`. Если бы вместо него использовались атрибуты `minlength` (en-US) и `maxlength` (en-US), для валидации можно было использовать `validityState.tooLong` или `validityState.tooShort`.

**Примечание:** Примечание: Если атрибут `pattern` не используется, поле `email (en-US)` требует, соответствия значения хотя бы формату `x@y`, а поле `url (en-US)` — хотя бы формату `x:`. Если поле не валидно, свойство `validityState.typeMismatch` будет `true`, если не используется атрибут `pattern`.

Спецификации
------------

| Specification |
| --- |
| HTML Standard # dom-validitystate-patternmismatch |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Также смотрите
--------------

* Валидация ограничений (en-US)
* Формы: Валидация форм
* Регулярные выражения


validityState.badInput - Интерфейсы веб API

validityState.badInput
======================

Baseline 2023
-------------

Newly availableSince March 2023, this feature works across the latest devices and browser versions. This feature might not work in older devices or browsers.

* Learn more
* See full compatibility
* Report feedback
Доступное только для чтения свойство **`badInput`** объекта ValidityState, указывающее, что пользователь ввёл значение, которое браузер не может преобразовать. Например, поле ввода чисел, содержащее строку. ***Примечание:** Во всех браузерах, кроме Internet Explorer, ввести в числовое поле любое нечисловое значения не удастся.*

Пример
------

```html
<input type="number" id="age" />
```

```js
var input = document.getElementById("age");
if (input.validity.badInput) {
  console.log("Bad input detected…");
} else {
  console.log("Content of input ok.");
}
```

Спецификации
------------

| Specification |
| --- |
| HTML Standard # dom-validitystate-badinput-dev |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* Руководство: Валидация ограничений (en-US)
* Учебник: Валидация форм


ValidityState.rangeUnderflow - Интерфейсы веб API

ValidityState.rangeUnderflow
============================

Baseline 2023
-------------

Newly availableSince March 2023, this feature works across the latest devices and browser versions. This feature might not work in older devices or browsers.

* Learn more
* See full compatibility
* Report feedback
Доступное только для чтения свойство **`rangeUnderflow`** объекта **`ValidityState`** указывает, соответствует ли значение `<input>` после изменения пользователем ограничениям, установленным атрибутом `min` (en-US).

Если поле является числовым, включая типы date, month (en-US), week (en-US), time (en-US), datetime-local, number, range и заданно значение атрибута `min`, если содержимое поля не соответствует ограничению атрибута `min` (en-US), свойство `rangeUnderflow` будет true.

Учитывая следующее:

```html
<input type="number" min="20" max="40" step="2" />
```

если `value < 20`, `rangeUnderflow` будет true. Если `true`, элемент соответствует CSS-псевдоклассам `:invalid` и `:out-of-range`.

Спецификации
------------

| Specification |
| --- |
| HTML Standard # dom-validitystate-rangeunderflow |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* `ValidityState.rangeOverflow`
* Валидация ограничений (en-US)
* Валидация форм на стороне клиента
* Атрибут `step` (en-US)
* Атрибут `max` (en-US)


ValidityState.stepMismatch - Интерфейсы веб API

ValidityState.stepMismatch
==========================

Baseline 2023
-------------

Newly availableSince March 2023, this feature works across the latest devices and browser versions. This feature might not work in older devices or browsers.

* Learn more
* See full compatibility
* Report feedback
Доступное только для чтения свойство **`stepMismatch`** объекта **`ValidityState`** указывает, соответствует ли значение `<input>` после изменения пользователем ограничениям, установленным атрибутом `step`.

Если поле является числовым, включая типы date, month (en-US), week (en-US), time (en-US), datetime-local, number, range и значение атрибута `step` не равно `any`, в случае не соответствия поля ограниченям атрибутов `step` (en-US) и `min` (en-US), то `stepMismatch` будет true. Если остаток от деления значения элемента формы за вычетом `min` (en-US) на `step` (en-US), (которое по умолчаиню равно 1) не равен нулю, то это является несоответствием.

Учитывая следующее:

```html
<input type="number" min="20" max="40" step="2" />
```

если `(value - min) % 2 != 0`, `stepMismatch` будет true.

Если true, элемент соответствует CSS-псевдоклассам `:invalid` и `:out-of-range`.

Спецификации
------------

| Specification |
| --- |
| HTML Standard # dom-validitystate-stepmismatch |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* Валидация ограничений (en-US)
* Валидация форм на стороне клиента
* Атрибут `step` (en-US)


ValidityState.typeMismatch - Интерфейсы веб API

ValidityState.typeMismatch
==========================

Baseline 2023
-------------

Newly availableSince March 2023, this feature works across the latest devices and browser versions. This feature might not work in older devices or browsers.

* Learn more
* See full compatibility
* Report feedback
Доступное только для чтения свойство **`typeMismatch`** объекта **`ValidityState`** указывает, соответствует ли изменённое пользователем значение `<input>` ограничениям атрибута `type`.

Если атрибут `type` получает типы вроде email (en-US) или url (en-US), а значение не соответствует ограничениям данного типа, свойство `typeMismatch` будет true.

Тип email (en-US) допускает ввод одного или нескольких email-адресов, в зависимости от наличия атрибута `multiple` (en-US). Валидный email-адрес включает префикс электронной почты и домен, с доменом верхнего уровня или без него. Если значение поля email-адреса не является пустой строкой, одним или несколькими email-адресами, разделёнными запятой (если присутствует атрибут `multiple` (en-US)), то это `typeMismatch`.

Тип url (en-US) допускает ввода одного или нескольких url-адресов, в зависимости от наличия атрибута `multiple` (en-US). Валидный URL-адрес включает протокол с IP-адресом или комбинацией поддоменом, домена и домен верхнего уровня. Если значение поля URL не ялвяется пустой строкой, одним или несколькими URL-адресами, разделёнными запятой (если присутствует атрибут `multiple` (en-US)), то это `typeMismatch`.

| Тип input | Значение | Ожидаемое значение |
| --- | --- | --- |
| email (en-US) | `x@y` или `x@y.z` | Email-адрес с или без TLD (en-US) |
| url (en-US) | `x:` или `x://y.z` | Протокол или полный URL с протоколом |

Примеры
-------

Учитывая следующее:

```html
<p>
  <label>
    Enter an email address:
    <input type="email" value="example.com" />
  </label>
</p>
<p>
  <label>
    Enter a URL:
    <input type="url" value="example.com" />
  </label>
</p>
```

```css
input:invalid {
  border: red solid 3px;
}
```

В примере выше в обоих полях происходит `typeMismatch`, потому что email-адрес является просто доменом, а URL не содержит протокол

`typeMismatch` происходит при несоответствии `значения`, заданного в атрибуте `type` и содержимым поля. `typeMismatch` является лишь одной из возможных ошибок и возможна только для полей email (en-US) и url (en-US). Когда введённое значение не соответствует ожидаемому для других полей ввода, в зависимости от типа поля будут возникать разные ошибки. Например, если в поле number ввести значение не являющееся числом с плавающей запятой, `badInput` будет `true`. Если `обязательное поле email не заполнено`, `valueMissing` (en-US) будет `true`.

Спецификации
------------

| Specification |
| --- |
| HTML Standard # dom-validitystate-typemismatch |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* Валидация ограничений (en-US)
* Валидация форм на стороне клиента
* Регулярные выражения


validityState.tooShort - Интерфейсы веб API

validityState.tooShort
======================

Baseline 2023
-------------

Newly availableSince March 2023, this feature works across the latest devices and browser versions. This feature might not work in older devices or browsers.

* Learn more
* See full compatibility
* Report feedback
Доступное только для чтения свойство **`tooShort`** объекта **`ValidityState`** указывает, является ли длина изменённого пользователем значения `<input>`, `<button>`, `<select>`, `<output>`, `<fieldset>` или `<textarea>` (en-US) меньше минимально допустимого значения, заданного в атрибуте `minlength`.

Спецификации
------------

| Specification |
| --- |
| HTML Standard # dom-validitystate-tooshort-dev |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* Валидация ограничений (en-US)
* Валидация форм на стороне клиента


validityState.tooLong - Интерфейсы веб API

validityState.tooLong
=====================

Baseline 2023
-------------

Newly availableSince March 2023, this feature works across the latest devices and browser versions. This feature might not work in older devices or browsers.

* Learn more
* See full compatibility
* Report feedback
Доступное только для чтения свойство **`tooLong`** объекта **`ValidityState`** указывает, превышает ли длина значения `<input>` или `<textarea>` (en-US), после редактирования пользователем, заданный в атрибуте `maxlength` (en-US) максимум.

Спецификации
------------

| Specification |
| --- |
| HTML Standard # dom-validitystate-toolong-dev |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* Валидация ограничений (en-US)
* Валидация форм на стороне клиента


ValidityState.rangeOverflow - Интерфейсы веб API

ValidityState.rangeOverflow
===========================

Baseline 2023
-------------

Newly availableSince March 2023, this feature works across the latest devices and browser versions. This feature might not work in older devices or browsers.

* Learn more
* See full compatibility
* Report feedback
Доступное только для чтения свойство **`rangeOverflow`** объекта **`ValidityState`** указывает, что после редактирования пользователем поля `<input>`, значение не соответствует ограничениям, установленным атрибутом `max` (en-US).

Если поле является числовым, включая типы date, month (en-US), week (en-US), time (en-US), datetime-local, number, range и заданно значение атрибута max, если содержимое поля не соответствует ограничению атрибута `max` (en-US), свойство `rangeOverflow` будет true.

Учитывая слещующее:

```html
<input type="number" min="20" max="40" step="2" />
```

если `value > 40`, `rangeOverflow` будет true. Если `true`, элемент соответствует CSS-псевдоклассам `:invalid` и `:out-of-range`.

Спецификации
------------

| Specification |
| --- |
| HTML Standard # dom-validitystate-rangeoverflow |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* `ValidityState.rangeUnderflow`
* Валидация ограничений (en-US)
* Валидация форм на стороне клиента
* Атрибут `step` (en-US)
* Атрибут `min` (en-US)


abort - Интерфейсы веб API

abort
=====

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

Событие **`abort`** из Fetch API вызывается когда fetch запрос прерывается, т.е. с помощью `AbortController.abort()`.

|  |  |
| --- | --- |
| Bubbles | Нет |
| Cancelable | Нет |
| Target objects | `AbortSignal` |
| Interface | `Event` |

Примеры
-------

В следующем фрагменте мы создаём новый объект `AbortController`, и получаем его `AbortSignal` (доступно в свойстве `signal`). Позже мы проверяем, был ли прерван сигнал, используя свойство `aborted`, и выводим соответствующее сообщение в консоль.

```js
var controller = new AbortController();
var signal = controller.signal;

signal.onabort = function () {
  console.log("Request aborted");
};
```

Наследование
------------

Событие `abort` реализует `Event` интерфейс — он имеет свойства и методы, определённые в нём.

Спецификации
------------

| Specification |
| --- |
| DOM Standard # eventdef-abortsignal-abort |
| DOM Standard # abortsignal-onabort |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* Fetch API


AbortSignal.aborted - Интерфейсы веб API

AbortSignal.aborted
===================

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

Свойство **`aborted`** только для чтения, оно возвращает `Boolean` (en-US), который указывает прерван(`true`) DOM запрос(ы), с которым связан сигнал, или нет(`false`).

Синтаксис
---------

```js
var isAborted = abortSignal.aborted;
```

### Значение

`Boolean` (en-US)Примеры
-------

В следующем фрагменте мы создаём новый объект `AbortController`, и получаем его `AbortSignal` (доступно в свойстве `signal`). Позже мы проверяем, был ли прерван сигнал, используя свойство `aborted`, и выводим соответствующее сообщение в консоль.

```js
var controller = new AbortController();
var signal = controller.signal;

// ...

signal.aborted
  ? console.log("Запрос был отменён")
  : console.log("Запрос не отменён");
```

Спецификации
------------

| Specification |
| --- |
| DOM Standard # ref-for-dom-abortsignal-aborted① |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* Fetch API


Element.scrollHeight - Интерфейсы веб API

Element.scrollHeight
====================

Свойство **`Element.scrollHeight`** (только чтение) - измерение высоты контента в элементе, включая содержимое, невидимое из-за прокрутки. Значение `scrollHeight` равно минимальному `clientHeight`, которое потребуется элементу для того, чтобы поместить всё содержимое в видимую область (viewport), не используя вертикальную полосу прокрутки. Оно включает в себя padding элемента, но не его margin.

**Примечание:** Это свойство округляет значение до целого числа. Если вам нужно дробное значение, используйте `Element.getBoundingClientRect()`.

Синтаксис
---------
```

var intElemScrollHeight = document.getElementById(id_attribute_value).scrollHeight;
```

*intElemScrollHeight* - переменная, хранящая целое число, соответствующее пиксельному значению scrollHeight элемента. scrollHeight является свойством только для чтения.

Пример
------

padding-top

Бла-бла-бла, бла-бла-бла.Бла-бла-бла, бла-бла-бла.Бла-бла-бла, бла-бла-бла.

Кот Василий ел картошку.Бла-бла-бла, бла-бла-бла.Бла-бла-бла, бла-бла-бла.

padding-bottom

**Left** **Top** **Right** **Bottom** *margin-top* *margin-bottom* *border-top* *border-bottom*

![](/ru/docs/Web/API/Element/scrollHeight/scrollheight.png)

Проблемы и решения
------------------

### Определить, был ли элемент полностью прокручен

Следующее выражение возвращает `true`, если элемент был прокручен до конца, `false` если это не так.
```

element.scrollHeight - element.scrollTop === element.clientHeight
```

Пример работы scrollHeight
--------------------------

Если объединить это выражение с событием `onscroll` (en-US), оно может быть использовано для того, чтобы определить, прочитал ли пользователь текст, или нет (см. также свойства `element.scrollTop` (en-US) и `element.clientHeight` (en-US)). Например:

### HTML

```html
<form name="registration">
  <p>
    <textarea id="rules">
Регистрируясь на сайте любителей котиков я соглашаюсь со следующими условиями:
- покупать kitekat бездомным;
- делиться последним куском мяса;
- любить Firefox;
- вставлять в каждую фразу: "мурр", "мррр" и т.п.;
- в качестве документов предъявлять хвост и усы;
- заниматься разработкой;
- читать хабрахабр;
- смотреть "Tom and Jerry" и котопса;
- продать почку для поддержания здоровья кошек города;
- уметь ловить мышей;
- быть фанатом Матроскина;
- обожать молоко;
- уметь мурлыкать и рррычать;
- следовать жизненным принципам Леопольда;
- вставлять на MDN фразы про кошек для разнообразия и поддержания морального духа;
- загрузить в качестве аватарки фото с Простоквашино;
- другими словами, всегда любить и уважать кошек и ненавидеть собак.
Условия могут быть изменены в любое время, незнание не освобождает от ответственности.
    </textarea>
  </p>
  <p>
    <input type="checkbox" name="accept" id="agree" />
    <label for="agree">Я согласен</label>
    <input type="submit" id="nextstep" value="Далее" />
  </p>
</form>
```

### CSS

```css
#notice {
  display: inline-block;
  margin-bottom: 12px;
  border-radius: 5px;
  width: 600px;
  padding: 5px;
  border: 2px #7fdf55 solid;
}

#rules {
  width: 600px;
  height: 130px;
  padding: 5px;
  border: #2a9f00 solid 2px;
  border-radius: 5px;
}
```

### JavaScript

```js
function checkReading() {
  if (checkReading.read) {
    return;
  }
  checkReading.read = this.scrollHeight - this.scrollTop === this.clientHeight;
  document.registration.accept.disabled = document.getElementById(
    "nextstep",
  ).disabled = !checkReading.read;
  checkReading.noticeBox.innerHTML = checkReading.read
    ? "Спасибо вам."
    : "Пожалуйста, прокрутите и прочитайте следующий текст.";
}

onload = function () {
  var oToBeRead = document.getElementById("rules");
  checkReading.noticeBox = document.createElement("span");
  document.registration.accept.checked = false;
  checkReading.noticeBox.id = "notice";
  oToBeRead.parentNode.insertBefore(checkReading.noticeBox, oToBeRead);
  oToBeRead.parentNode.insertBefore(document.createElement("br"), oToBeRead);
  oToBeRead.onscroll = checkReading;
  checkReading.call(oToBeRead);
};
```

Спецификации
------------

| Specification |
| --- |
| CSSOM View Module # dom-element-scrollheight |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* MSDN Измерение размера и положения элемента с помощью CSSOM в Internet Explorer 9
* `Element.clientHeight`
* `HTMLElement.offsetHeight`
* Определение размеров элементов (en-US)


GlobalEventHandler.onanimationend - Интерфейсы веб API

GlobalEventHandler.onanimationend
=================================

Обработчик события `animationend (en-US)`. Это событие вызывается когда CSS-анимация достигает конца своего активного периода, который вычисляется как (`animation-duration` \* `animation-iteration-count`) + `animation-delay`.

Синтаксис
---------
```

var animEndHandler = target.onanimationend;

target.onanimationend = `Function`
```

### Значение

A `Function` вызывается, когда происходит событие `animationend (en-US)`, указывающее, что анимация CSS начинается с цели, где целевой объект является HTML-элементом (`HTMLElement`), документ (`Document`) или окно (`Window`). Функция получает в качестве входного параметра один параметр: `AnimationEvent` объект, описывающий событие, которое произошло.

Спецификации
------------

| Specification |
| --- |
| CSS Animations Level 1 # eventdef-globaleventhandlers-animationend |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* The `animationend (en-US)` event this event handler is triggered by
* `AnimationEvent`
* The `animationstart (en-US)` event


focusout - Интерфейсы веб API

focusout
========

Событие `focusout` вызывается перед потерей элементом фокуса. Главное отличие между этим событием и `blur` (en-US) в том, что у последнего нет фазы всплытия.

Основная информация

Спецификация

DOM L3

Интерфейс
`FocusEvent` (en-US)
Всплытие

Да

Отменяемый

Нет

Цель

Элемент

Действие по умолчанию

Нет.

Свойства
--------

| Свойство | Тип | Описание |
| --- | --- | --- |
| `target` Только для чтения  | `EventTarget` | Цель события, теряющая фокус. |
| `type` Только для чтения  | `DOMString` | Тип события. |
| `bubbles` Только для чтения  | `Boolean` | Всплывает ли событие при нормальных условиях. |
| `cancelable` Только для чтения  | `Boolean` | Возможно ли отменить событие. |
| `relatedTarget` Только для чтения  | `EventTarget` (DOM-элемент) | Цель события, получающая фокус. |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Related Events
--------------

* `focus (en-US)`
* `blur (en-US)`
* `focusin (en-US)`


Element: свойство classList - Интерфейсы веб API

Element: свойство classList
===========================

Описание
--------

**`Element.classList`** — это доступное только для чтения свойство, которое содержит текущую коллекцию `DOMTokenList` всех атрибутов `class` элемента.

Использование `classList` представляет более удобный способ, чем доступ к списку классов элемента в виде строки, разделенной пробелами, через `element.className`.

Значение
--------

`DOMTokenList` представляет содержимое атрибута `class` элемента. Если атрибут `class` не установлен или пуст, то будет возвращён пустой `DOMTokenList`, то есть `DOMTokenList` со свойством `length` равным `0`.

Хотя само свойство `classList` доступно только для чтения, можно изменять связанный с ним `DOMTokenList` с помощью методов `add()` (en-US), `remove()` (en-US), `replace()` и `toggle()` (en-US).

Для проверки, содержит ли элемент какой-либо класс можно использовать метод `classList.contains()` (en-US).

Примеры
-------

```js
const div = document.createElement("div");
div.className = "foo";

// Начальное состояние: <div class="foo"></div>
console.log(div.outerHTML);

// Используем classList API для удаления и добавления классов
div.classList.remove("foo");
div.classList.add("anotherclass");

// <div class="anotherclass"></div>
console.log(div.outerHTML);

// Если класс "visible" присутствует в списке классов, то он будет удалён, а иначе наоборот добавлен
div.classList.toggle("visible");

// Добавление/удаление класса "visible" в зависимости от условия, передаваемого вторым аргументом
div.classList.toggle("visible", i < 10);

// false
console.log(div.classList.contains("foo"));

// Добавление или удаление нескольких классов сразу
div.classList.add("foo", "bar", "baz");
div.classList.remove("foo", "bar", "baz");

// Добавление или удаление нескольких классов с использованием spread-синтаксиса
const cls = ["foo", "bar"];
div.classList.add(...cls);
div.classList.remove(...cls);

// Замена класса "foo" классом "bar"
div.classList.replace("foo", "bar");
```

Спецификации
------------

| Specification |
| --- |
| DOM Standard # ref-for-dom-element-classlist① |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* `element.className`
* `DOMTokenList`
* `classList.js` (кросс-браузерный полифил, реализующий функциональность `element.classList`)


Element.clientTop - Интерфейсы веб API

Element.clientTop
=================

Толщина верхней границы элемента в пикселях. Не включает в себя margin и padding. Свойство только для чтения.

Всё, что лежит между двумя местами (`offsetTop` и верх клиентской области) является границей элемента, потому что `offsetTop` показывает местоположение верха border элемента (не margin), в то время как верх клиентской области начинается сразу под border (клиентская область включает padding). Поэтому значение **clientTop** всегда будет равно значению `.getComputedStyle()` для "border-top-width". Например, если значение "border-top-width" равно нулю, то и **clientTop** тоже равно нулю.

**Примечание:** Это свойство округляет значение до целого. Если вам нужно дробное значение, используйте `element.getBoundingClientRect()`.

Основанные на Gecko приложения поддерживают clientTop начиная с Gecko 1.9 (Firefox 3, реализовано в Firefox bug 111207). Это свойство не поддерживается в Firefox 2 и более ранних.

Синтаксис
---------
```

vartop = element.clientTop;
```

Пример
------

В следующей иллюстрации клиентская область показана белым (части под названиями "Top", "Right" и т. д. не имеют никакого отношения к клиентской области). Значение **clientTop** - расстояние между окончанием области margin (жёлтый) или padding и началом области контента (белый)

Примечание
----------

`clientTop` был впервые введён в MS IE DHTML object model.

Спецификации
------------

| Specification |
| --- |
| CSSOM View Module # dom-element-clienttop |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* MSDN: Measuring Element Dimension and Location


Element.hasAttribute() - Интерфейсы веб API

Element.hasAttribute()
======================

**`Element.hasAttribute()`** метод возвращает Boolean значение указывающее, имеет ли указанный элемент указанный атрибут или нет.

Синтаксис
---------
```

var result = element.hasAttribute(attName);
```

* `Переменная result` хранит возвращённое значение `true` или `false`.
* `attName` это String представляющая имя атрибута.
Пример
------

```js
// проверка, существует ли атрибут, перед тем как задать значение
var d = document.getElementById("div1");

if (d.hasAttribute("align")) {
  d.setAttribute("align", "center");
}
```

Замечания
---------

Методы DOM имеют дело с атрибутами элементов:

| Не знают пространства имён, наиболее часто используемые методы | Вариант, знающий пространство имён (Уровень DOM 2) | Уровень DOM 1 методы для работы с `Attr` узлами напрямую (используется редко) | Уровень DOM 2 знает о методах пространства имён для работы с `Attr` узлами напрямую (используется редко) |
| --- | --- | --- | --- |
| `setAttribute` (DOM 1) | `setAttributeNS` (en-US) | `setAttributeNode` (en-US) | `setAttributeNodeNS` (en-US) |
| `getAttribute` (DOM 1) | `getAttributeNS` (en-US) | `getAttributeNode` (en-US) | `getAttributeNodeNS` (en-US) |
| `hasAttribute` (DOM 2) | `hasAttributeNS` (en-US) | - | - |
| `removeAttribute` (DOM 1) | `removeAttributeNS` (en-US) | `removeAttributeNode` (en-US) | - |

Спецификации
------------

| Specification |
| --- |
| DOM Standard # ref-for-dom-element-hasattribute① |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


Element.createShadowRoot() - Интерфейсы веб API

Element.createShadowRoot()
==========================

Baseline Widely available
-------------------------

This feature is well established and works across many devices and browser versions. It’s been available across browsers since January 2020.

* Learn more
* See full compatibility
* Report feedback
**Устарело:** Эта возможность была удалена из веб-стандартов. Хотя некоторые браузеры по-прежнему могут поддерживать её, она находится в процессе удаления. Не используйте её ни в старых, ни в новых проектах. Страницы или веб-приложения, использующие её, могут в любой момент сломаться.

Используйте `Element.createShadowRoot` чтобы создать экземпляр shadow DOM (en-US). После создания shadow DOM, он всегда будет привязан к существующему элементу. После создания shadowDOM, элемент к которому он привязан будет называться Теневой корень (shadowRoot) .

**Примечание:** This method has been deprecated in favor of attachShadow.

Синтаксис
---------
```

var shadowroot = element.createShadowRoot();
```

### Параметры

Отсутствуют

### Значение результата

Возвращает `ShadowRoot` (en-US).

Спецификация
------------

Эта функция больше не определяется никакими спецификациями

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


Element.removeAttribute() - Интерфейсы веб API

Element.removeAttribute()
=========================

`removeAttribute` удаляет атрибут с элемента.

Синтаксис
---------
```

element.removeAttribute(attrName);
```

* `attrName` строка, имя атрибута который должен быть удалён с *element*.
Пример
------
```

// <div id="div1" align="left" width="200px">
document.getElementById("div1").removeAttribute("align");
// now: <div id="div1" width="200px">
```

Примечания
----------

Вы должны использовать removeAttribute вместо того, чтобы устанавливать значение атрибута в null, используя setAttribute.

Попытка удаления атрибута, которого нет на элементе не вызывает ошибки.

Методы DOM имеют дело с атрибутами элементов:

| Не знают пространства имён, наиболее часто используемые методы | Вариант, знающий пространство имён (Уровень DOM 2) | Уровень DOM 1 методы для работы с `Attr` узлами напрямую (используется редко) | Уровень DOM 2 знает о методах пространства имён для работы с `Attr` узлами напрямую (используется редко) |
| --- | --- | --- | --- |
| `setAttribute` (DOM 1) | `setAttributeNS` (en-US) | `setAttributeNode` (en-US) | `setAttributeNodeNS` (en-US) |
| `getAttribute` (DOM 1) | `getAttributeNS` (en-US) | `getAttributeNode` (en-US) | `getAttributeNodeNS` (en-US) |
| `hasAttribute` (DOM 2) | `hasAttributeNS` (en-US) | - | - |
| `removeAttribute` (DOM 1) | `removeAttributeNS` (en-US) | `removeAttributeNode` (en-US) | - |

Спецификация
------------

DOM Level 2 Core: removeAttribute (introduced in DOM Level 1 Core)


Element.insertAdjacentElement() - Интерфейсы веб API

Element.insertAdjacentElement()
===============================

Метод **`insertAdjacentElement()`** добавляет переданный элемент в DOM-дерево относительно элемента, вызвавшего метод.

Синтаксис
---------
```

targetElement.insertAdjacentElement(position, element);
```

### Параметры

position

`DOMString` - определяет позицию добавляемого элемента относительно элемента, вызвавшего метод. Должно соответствовать одному из следующих значений (чувствительно к регистру):

* `'beforebegin'`: перед самим элементом `targetElement`.
* `'afterbegin'`: внутри элемента `targetElement`, перед его первым потомком.
* `'beforeend'`: внутри элемента `targetElement`, после его последнего потомка.
* `'afterend'`: после самого элемента `targetElement`.

element

Элемент, добавляемый в DOM-дерево.

### Возвращаемое значение

Метод возвращает добавляемый элемент, либо `null`, если добавление элемента завершилось ошибкой.

### Исключения

| Исключение | Пояснение |
| --- | --- |
| `SyntaxError` | Переданное значение `position` не соответствует ни одному из допустимых. |
| `TypeError` | Передаваемый `element` не является валидным. |

### Наглядное отображение параметра position
```

<!-- beforebegin -->
<p>
<!-- afterbegin -->
foo
<!-- beforeend -->
</p>
<!-- afterend -->
```

**Примечание:** значения `beforebegin` и `afterend` работают только если targetElement находится в DOM-дереве и имеет родительский элемент.

Примеры
-------

```js
beforeBtn.addEventListener("click", function () {
  var tempDiv = document.createElement("div");
  tempDiv.style.backgroundColor = randomColor();
  if (activeElem) {
    activeElem.insertAdjacentElement("beforebegin", tempDiv);
  }
  setListener(tempDiv);
});

afterBtn.addEventListener("click", function () {
  var tempDiv = document.createElement("div");
  tempDiv.style.backgroundColor = randomColor();
  if (activeElem) {
    activeElem.insertAdjacentElement("afterend", tempDiv);
  }
  setListener(tempDiv);
});
```

Посмотрите наше демо insertAdjacentElement.html на Github (так же посмотрите исходный код). В этом демо мы имеем последовательность `<div>` элементов внутри контейнера. При выборе одного из них можно нажать кнопку *Insert before* или *Insert after* и добавить новые div до или после выбранного элемента используя метод `insertAdjacentElement()`.

Спецификации
------------

| Specification |
| --- |
| DOM Standard # dom-element-insertadjacentelement |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* `Element.insertAdjacentHTML()`
* `Element.insertAdjacentText()`
* `Node.insertBefore()`
* `Node.appendChild()` (такой же эффект со значением position `beforeend`)


Элемент.scrollLeft - Интерфейсы веб API

Элемент.scrollLeft
==================

Свойство **`scrollLeft`** получает или устанавливает количество пикселей, на которое контент элемента прокручен влево.

Заметьте, что если свойство `direction`: `rtl` (right-to-left), то `scrollLeft` равен `0`, когда скроллбар на его самой правой позиции (с начала прокрученного контента), а затем становится отрицательным по мере прокрутки к концу контента.

Синтаксис
---------
```

// Получаем количество прокрученных пикселей
var sLeft = element.scrollLeft;
```

*sLeft* - целое число, представленное количеством пикселей, на которые элемент был прокручен влево.
```

// Устанавливаем количество прокрученных пикселей
element.scrollLeft = 10;
```

`scrollLeft` может быть установлен, как любое целое число, однако:

* Если элемент не может быть прокручен (т.е. у него нет переполнения), `scrollLeft` устанавливается в 0.
* Если установили значение меньше 0 (больше 0 при расположении элементов справа налево), `scrollLeft` устанавливается в 0.
* Если установлено значение больше, чем максимум прокручиваемого контента, `scrollLeft` устанавливается в максимум.
Пример
------

```html
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <style>
 #container {
 border: 1px solid #ccc;
 height: 100px;
 overflow: scroll;
 width: 100px;
 }
 #content {
 background-color: #ccc;
 width: 250px;
 }
 </style>
    <script>
 document.addEventListener(
 "DOMContentLoaded",
 function () {
 var button = document.getElementById("slide");
 button.onclick = function () {
 document.getElementById("container").scrollLeft += 20;
 };
 },
 false,
 );
 </script>
  </head>
  <body>
    <div id="container">
      <div id="content">Бла-бла-бла</div>
    </div>
    <button id="slide" type="button">Пролистать</button>
  </body>
</html>
```

Спецификации
------------

| Specification |
| --- |
| CSSOM View Module # dom-element-scrollleft |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


GlobalEventHandlers.onclick - Интерфейсы веб API

GlobalEventHandlers.onclick
===========================

Свойство **onclick** возвращает обработчик события `click` на текущем элементе.

**Примечание:** При использовании обработчика события `click` для вызова любого действия, убедитесь, что событие `keydown` имеет такое же действие. Это нужно для того, чтобы пользователи, которые не используют мышь или тачскрин могли использовать то же действие.

Синтаксис
---------
```

element.onclick = functionRef;
```

где *functionRef* это функция - зачастую это имя функции, которая объявлена где-то в другом месте или же *функциональное выражение*. См. "JavaScript Guide:Functions".

Единственный аргумент, переданный в определённую функцию обработчик события это `MouseEvent` объект. `this` внутри обработчика будет указывать на элемент, на котором было вызвано событие.

Пример
------

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>onclick event example</title>
    <script>
 function initElement() {
 var p = document.getElementById("foo");
 // NOTE: showAlert(); или showAlert(param); так НЕ сработает.
 // Нужно использовать ссылку на функцию, но не вызов функции.
 p.onclick = showAlert;
 }

 function showAlert(event) {
 alert("onclick Event detected!");
 }
 </script>
    <style>
 #foo {
 border: solid blue 2px;
 }
 </style>
  </head>
  <body onload="initElement();">
    <span id="foo">My Event Element</span>
    <p>click on the above element.</p>
  </body>
</html>
```

Или же вы можете использовать анонимную функцию, как здесь:

```js
p.onclick = function (event) {
  alert("moot!");
};
```

Примечания
----------

Событие `click` возникает, когда пользователь кликает на элемент. Событие `click` возникнет после событий `mousedown` и `mouseup`.

С данным свойством только один обработчик события `click` может быть назначен объекту. Возможно, вместо данного метода, вам стоит обратить внимание на метод `EventTarget.addEventListener()`, т.к. он более гибкий и является частью спецификации DOM Events.

Спецификации
------------

| Specification |
| --- |
| UI Events # event-type-click |
| HTML Standard # handler-onclick |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* `click (en-US)` event
* Related event handlers
    + `GlobalEventHandlers.onauxclick` (en-US)
    + `GlobalEventHandlers.ondblclick` (en-US)


Element: mouseenter event - Интерфейсы веб API

Element: mouseenter event
=========================

Событие **`mouseenter`** вызывается в `Element` когда указательное устройство (обычно мышь) изначально перемещается так, что его горячая точка находится в пределах элемента, в котором было запущено событие.

|  |  |
| --- | --- |
| Всплывающее | Нет |
| Отменяемое | Нет |
| Интерфейс | `MouseEvent` |
| Свойство обработчика события | `onmouseenter` (en-US) |

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

Хотя `mouseenter` похоже на `mouseover` (en-US), `mouseenter` отличается тем, что он не является bubble и не отправляется никаким потомкам, когда указатель перемещается из физического пространства одного из его потомков в его собственное физическое пространство.

![Диаграмма поведения mouseenter](/ru/docs/Web/API/Element/mouseenter_event/mouseenter.png)
 Одно событие `mouseenter` отправляется каждому элементу иерархии при их вводе. Здесь 4 события отправляются четырём элементам иерархии, когда указатель достигает текста.

![Диаграмма поведения mouseover](/ru/docs/Web/API/Element/mouseenter_event/mouseover.png)
 Одиночное событие наведения мыши `mouseover` отправляется в самый глубокий элемент дерева DOM, затем оно всплывает в иерархии, пока не будет отменено обработчиком или не достигнет корня.

При наличии глубокой иерархии количество отправляемых событий `mouseover` может быть довольно большим и вызывать значительные проблемы с производительностью. В таких случаях лучше обрабатывать события `mouseenter`.

В сочетании с соответствующим событием `mouseleave` (которое запускается в элементе, когда мышь покидает область содержимого), событие `mouseenter` действует очень похоже на псевдокласс CSS `:hover`.

Примеры
-------

В документации по `mouseover` (en-US) есть пример иллюстрирующий различия между `mouseover` и `mouseenter`.

### mouseenter

В следующем тривиальном примере событие `mouseenter` используется для изменения границы элемента `div`, когда мышь входит в выделенное ему пространство. Затем он добавляет элемент в список с номером события `mouseenter` или `mouseleave`.

#### HTML

```html
<div id="mouseTarget">
  <ul id="unorderedList">
    <li>No events yet!</li>
  </ul>
</div>
```

#### CSS

Стилизация `div` чтобы сделать его более заметным.

```css
#mouseTarget {
  box-sizing: border-box;
  width: 15rem;
  border: 1px solid #333;
}
```

#### JavaScript

```js
var enterEventCount = 0;
var leaveEventCount = 0;
const mouseTarget = document.getElementById("mouseTarget");
const unorderedList = document.getElementById("unorderedList");

mouseTarget.addEventListener("mouseenter", (e) => {
  mouseTarget.style.border = "5px dotted orange";
  enterEventCount++;
  addListItem("This is mouseenter event " + enterEventCount + ".");
});

mouseTarget.addEventListener("mouseleave", (e) => {
  mouseTarget.style.border = "1px solid #333";
  leaveEventCount++;
  addListItem("This is mouseleave event " + leaveEventCount + ".");
});

function addListItem(text) {
  // Создать новый текстовый узел, используя предоставленный текст
  var newTextNode = document.createTextNode(text);

  // Создать новый элемент li
  var newListItem = document.createElement("li");

  // Добавить текстовый узел к элементу li
  newListItem.appendChild(newTextNode);

  // Добавить вновь созданный элемент списка в список
  unorderedList.appendChild(newListItem);
}
```

### Результат

Спецификации
------------

| Specification |
| --- |
| UI Events # event-type-mouseenter |
| HTML Standard # handler-onmouseenter |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* Introduction to events
* `mousedown`
* `mouseup`
* `mousemove` (en-US)
* `click`
* `dblclick` (en-US)
* `mouseover` (en-US)
* `mouseout` (en-US)
* `mouseenter`
* `mouseleave`
* `contextmenu`


mousedown - Интерфейсы веб API

mousedown
=========

Событие `mousedown` срабатывает, когда кнопка указывающего устройства (к примеру, мыши) нажата над элементом.

Общая информация
----------------

Спецификация

DOM L3

Интерфейс
`MouseEvent`
Всплывающее

Да

Отменяемое

Да

Цель

Элемент

Действие по умолчанию

Различное: инициация перетаскивания, выделения текста, прокрутки или масштабирования (в сочетании с нажатием колеса при поддержке такового)

Свойства
--------

| Property | Type | Description |
| --- | --- | --- |
| `target` Только для чтения  | `EventTarget` | The event target (the topmost target in the DOM tree). |
| `type` Только для чтения  | `DOMString` | The type of event. |
| `bubbles` Только для чтения  | `Boolean` (en-US) | Whether the event normally bubbles or not |
| `cancelable` Только для чтения  | `Boolean` (en-US) | Whether the event is cancellable or not? |
| `view` Только для чтения  | `WindowProxy` | `document.defaultView` (`window` of the document) |
| `detail` Только для чтения  | `long` (`float`) | A count of consecutive clicks that happened in a short amount of time, incremented by one. |
| `currentTarget` Только для чтения  | EventTarget | The node that had the event listener attached. |
| `relatedTarget` Только для чтения  | EventTarget | For `mouseover`, `mouseout`, `mouseenter` and `mouseleave` events: the target of the complementary event (the `mouseleave` target in the case of a `mouseenter` event). `null` otherwise. |
| `screenX` Только для чтения  | long | The X coordinate of the mouse pointer in global (screen) coordinates. |
| `screenY` Только для чтения  | long | The Y coordinate of the mouse pointer in global (screen) coordinates. |
| `clientX` Только для чтения  | long | The X coordinate of the mouse pointer in local (DOM content) coordinates. |
| `clientY` Только для чтения  | long | The Y coordinate of the mouse pointer in local (DOM content) coordinates. |
| `button` Только для чтения  | unsigned short | The button number that was pressed when the mouse event was fired: Left button=0, middle button=1 (if present), right button=2. For mice configured for left handed use in which the button actions are reversed the values are instead read from right to left. |
| `buttons` Только для чтения  | unsigned short | The buttons being pressed when the mouse event was fired: Left button=1, Right button=2, Middle (wheel) button=4, 4th button (typically, "Browser Back" button)=8, 5th button (typically, "Browser Forward" button)=16. If two or more buttons are pressed, returns the logical sum of the values. E.g., if Left button and Right button are pressed, returns 3 (=1 | 2). More info. |
| `mozPressure` Только для чтения  | float | The amount of pressure applied to a touch or tabdevice when generating the event; this value ranges between 0.0 (minimum pressure) and 1.0 (maximum pressure). |
| `ctrlKey` Только для чтения  | boolean | `true` if the control key was down when the event was fired. `false` otherwise. |
| `shiftKey` Только для чтения  | boolean | `true` if the shift key was down when the event was fired. `false` otherwise. |
| `altKey` Только для чтения  | boolean | `true` if the alt key was down when the event was fired. `false` otherwise. |
| `metaKey` Только для чтения  | boolean | `true` if the meta key was down when the event was fired. `false` otherwise. |

Связанные события
-----------------

* `mousedown (en-US)`
* `mouseup (en-US)`
* `mousemove (en-US)`
* `click (en-US)`
* `dblclick (en-US)`
* `mouseover (en-US)`
* `mouseout (en-US)`
* `mouseenter (en-US)`
* `mouseleave (en-US)`
* `contextmenu (en-US)`


Element.setAttribute() - Интерфейсы веб API

Element.setAttribute()
======================

Добавляет новый атрибут или изменяет значение существующего атрибута у выбранного элемента.Синтаксис
---------
```

element.setAttribute(name, value);
```

* `name` - имя атрибута (строка).
* `value` - значение атрибута.
Пример
------

В следующем примере, `setAttribute()` используется, чтобы установить атрибут `disabled` кнопки `<button>`, делая её отключённой.

```html
<button>Hello World</button>
```

```js
var b = document.querySelector("button");

b.setAttribute("disabled", "disabled");
```

Примечания
----------

При вызове на элементе внутри HTML документа, setAttribute переведёт имя атрибута в нижний регистр.

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

Несмотря на то, что метод `getAttribute()` возвращает null у удалённых атрибутов, вы должны использовать removeAttribute() (en-US) вместо *elt*.setAttribute(*attr*, null), чтобы удалить атрибут. Последний заставит значение `null` быть строкой `"null"`, которая, вероятно, не то, что вы хотите.

Использование setAttribute() для изменения определённых атрибутов особенно значимо в XUL, так как работает непоследовательно, а атрибут определяет значение по умолчанию. Для того, чтобы получить или изменить текущие значения, вы должны использовать свойства. Например, elt.value вместо elt.setAttribure('value', val).

Чтобы установить атрибут, которому значение не нужно, такой как, например, атрибут `autoplay` элемента `<audio>`, используйте null или пустое значение. Например: `elt.setAttribute('autoplay', '')`

Методы DOM имеют дело с атрибутами элементов:

| Не знают пространства имён, наиболее часто используемые методы | Вариант, знающий пространство имён (Уровень DOM 2) | Уровень DOM 1 методы для работы с `Attr` узлами напрямую (используется редко) | Уровень DOM 2 знает о методах пространства имён для работы с `Attr` узлами напрямую (используется редко) |
| --- | --- | --- | --- |
| `setAttribute` (DOM 1) | `setAttributeNS` (en-US) | `setAttributeNode` (en-US) | `setAttributeNodeNS` (en-US) |
| `getAttribute` (DOM 1) | `getAttributeNS` (en-US) | `getAttributeNode` (en-US) | `getAttributeNodeNS` (en-US) |
| `hasAttribute` (DOM 2) | `hasAttributeNS` (en-US) | - | - |
| `removeAttribute` (DOM 1) | `removeAttributeNS` (en-US) | `removeAttributeNode` (en-US) | - |

Спецификации
------------

| Specification |
| --- |
| DOM Standard # ref-for-dom-element-setattribute① |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


Element.getBoundingClientRect() - Интерфейсы веб API

Element.getBoundingClientRect()
===============================

Метод **`Element.getBoundingClientRect()`** возвращает размер элемента и его позицию относительно viewport (часть страницы, показанная на экране, и которую мы видим).

Синтаксис
---------
```

domRect = element.getBoundingClientRect();
```

### Возвращаемое значение

Данный метод возвращает объект `DOMRect` (en-US), который является объединением прямоугольников, возвращаемых методом `getClientRects()` (en-US) для данного элемента, т. е. CSS border-boxes (css-коробок в рамках), связанных с этим элементом. Результатом является самый маленький прямоугольник, в котором содержится весь элемент с read-only `left`, `top`, `right`, `bottom`, `x`, `y`, `width` и `height` свойствами, описывающие это в пикселях. Все свойства, кроме `width` и `height`, являются относительными к верхнему левому углу viewport-а.

![Explanation of DOMRect values](/ru/docs/Web/API/Element/getBoundingClientRect/rect.png)

Пустые border-box полностью игнорируются. Если border-box элемента пуст, прямоугольник возвращается с нулевыми `width` и `height`, а `top` и `left` берутся у следующего CSS элемента (в порядке контента).

После каждого скролла значения `left`, `top`, `right` и `bottom` изменяются, так как эти значения относительны к viewport и не абсолютные.

Если вам нужны значения, описывающие прямоугольник относительно к верхнему левому углу документа, просто добавьте к свойствам `top` и `left` текущую позицию прокрутки, используя `window.scrollX` и `window.scrollY`), чтобы получить прямоугольник, положение которого не зависит от текущей позиции прокрутки.

### Про кроссбраузерность

Скрипты, требующих высокую кроссбраузерность, могут использовать `window.pageXOffset` (en-US) и `window.pageYOffset` (en-US) вместо `window.scrollX` and `window.scrollY`. Скрипты без доступа к этим свойствам могут использовать код, наподобие этого:

```js
// Для scrollX
(((t = document.documentElement) || (t = document.body.parentNode)) &&
typeof t.scrollLeft == "number"
  ? t
  : document.body
).scrollLeft(
  // Для scrollY
  ((t = document.documentElement) || (t = document.body.parentNode)) &&
    typeof t.scrollTop == "number"
    ? t
    : document.body,
).scrollTop;
```

Пример
------

```js
// rect - DOMRect объект с 8-ми свойствами: left, top, right, bottom, x, y, width, height
var rect = obj.getBoundingClientRect();
```

Спецификации
------------

| Specification |
| --- |
| CSSOM View Module # dom-element-getboundingclientrect |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* `getClientRects()` (en-US)
* MSDN: `getBoundingClientRect`
* MSDN: `ClientRect`, более ранняя версия `DOMRect`
*
* `Element.getClientRects()` (en-US)


Node.namespaceURI - Интерфейсы веб API

Node.namespaceURI
=================

Свойство **`Node.namespaceURI`** только для чтения, возвращает пространство имён URI узла или `null,` если узел не находится в пространстве имён (только для чтения). Хотя узел документа, возвращает пространство имён XML для текущего документа.

Синтаксис
---------
```

namespace = node.namespaceURI
```

Пример
------

В этом сниппете, узел рассматривается для его localName (en-US) и его `namespaceURI`. Если `namespaceURI` возвращает XUL пространство имён и `localName` возвращая "browser", затем узел XUL согласует `<browser/>`.

```js
if (
  node.localName == "browser" &&
  node.namespaceURI ==
    "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
) {
  // this is a XUL browser
}
```

Примечание
----------

Это не вычисленное значение, которое является результатом поиска имён на основе проверки декларации в области пространства имён. Пространство имён URI узла заморожена в момент создания узла.

В Firefox 3.5 и выше, пространство имён URI для HTML-элементов в HTML документах это `null`. В более поздних версиях, в соответствии с HTML5, это `http://www.w3.org/1999/xhtml` как в XHTML.

Для узлов любого nodeType (en-US) кроме `ELEMENT_NODE` и `ATTRIBUTE_NODE` значение `namespaceURI` всегда `null`.

Вы можете создать элемент с конкретным `namespaceURI` используйте метод DOM Level 2 document.createElementNS.

Через пространство имён в XML спецификации, атрибуты не наследуют пространство имён для элемента к которому он прикреплён. Если у атрибута не задано явно пространство имён, он не имеет пространства имён.

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

Спецификации
------------

| Specification |
| --- |
| DOM Standard # ref-for-dom-element-namespaceuri① |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


Node.childElementCount - Интерфейсы веб API

Node.childElementCount
======================

Свойство **`Node.childElementCount`** предназначено только для чтения и возвращает число дочерних **элементов** узла.

Синтаксис
---------
```

var elCount = Node.childElementCount;
```

* **`elCount`** - целое число, количество дочерних элементов узла **Node.**
* **`Node`** - объект, представляющий собой `Document`, `DocumentFragment` или `Element`.

**Предупреждение:** А наш добрый друг **Internet Explorer** в **6, 7** и **8** версиях ошибочно считает элементами комментарии в HTML-коде (`Comment`).

Пример
------

```js
var foo = document.getElementById("foo");
if (foo.childElementCount > 0) {
  // здесь нужный код..
}
```

Спецификация
------------

| Specification |
| --- |
| DOM Standard # dom-parentnode-childelementcount |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


Element.querySelectorAll() - Интерфейсы веб API

Element.querySelectorAll()
==========================

Общая информация
----------------

Возвращает статичный (не «живой») список типа NodeList, состоящий из всех элементов, которые являются потомками для элемента, над которым была выполнена функция и удовлетворяющим условию выборки.

Синтаксис
---------
```

elementList = baseElement.querySelectorAll(selectors);
```

где

* `elementList —` результирующий список объектов типа element (результаты).
* `baseElement —` элемент, над которым выполняется функция.
* `selectors —` текст селектора (en-US) для выбора нужных элементов.
Примеры
-------

Этот пример возвращает список всех элементов с тегом p, которые находятся в теле документа:

```js
var matches = document.body.querySelectorAll("p");
```

Этот пример возвращает список всех элементов с тегом p, которые находятся непосредственно в элементах-контейнерах с тегом div, имеющих класс 'highlighted', которые в свою очередь находятся внутри элемента с идентификатором 'test':

```js
var el = document.querySelector("#test");
var matches = el.querySelectorAll("div.highlighted > p");
```

Этот пример возвращает список всех элементов iframe, которые имеют атрибут "data-src":

```js
var matches = el.querySelectorAll("iframe[data-src]");
```

Примечания
----------

Функция выбрасывает исключение SYNTAX\_ERR, если текст селектора неправильный.

querySelectorAll() был представлен как часть WebApps API.

Строка указанная в качестве текста селектора, должна соответствовать синтаксису CSS.

Помните, что возвращённый в качестве результата список NodeList не рекомендуется для использования в циклах (например, в for(...)) в качестве массива, т.к., это не массив в «традиционном» понятии Javascript, а объект типа NodeList, который, хоть и схож по свойствам с массивом, но не является таковым в полной мере (не поддерживает все методы, доступные массиву), так что будьте осторожны.

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Ссылки на спецификации
----------------------

* Selectors API
Смотрите также
--------------

* `document.querySelectorAll` (en-US)
* `document.querySelector` (en-US)
* Сниппеты для `querySelector`


Element.outerHTML - Интерфейсы веб API

Element.outerHTML
=================

Описание
--------

Атрибут `outerHTML` DOM-интерфейса `element` получает сериализованный HTML-фрагмент, описывающий элемент, включая его потомков. Можно установить замену элемента узлами, полученными из заданной строки.

Синтаксис
---------
```

var content = element.outerHTML;
```

На выводе, `content` содержит сериализованный HTML-фрагмент, описывающий `element` и его потомки.
```

element.outerHTML = content;
```

Replaces the `element` with the nodes generated by parsing the string `content` with the parent of `element` as the context node for the fragment parsing algorithm.

Примеры
-------

Получение свойства `outerHTML` элемента:

```js
// HTML:
// <div id="d"><p>Content</p><p>Further Elaborated</p></div>

d = document.getElementById("d");
console.log(d.outerHTML);

// строка '<div id="d"><p>Content</p><p>Further Elaborated</p></div>'
// выведена в окно консоли
```

Замена ветки с помощью изменения свойства `outerHTML`:

```js
// HTML:
// <div id="container"><div id="d">Это div.</div></div>

container = document.getElementById("container");
d = document.getElementById("d");
console.log(container.firstChild.nodeName); // логирует "DIV"

d.outerHTML = "<p>Этот параграф заменил исходный div.</p>";
console.log(container.firstChild.nodeName); // логирует "P"

// div #d больше не часть дерева документа,
// новый параграф заменил его.
```

Примечания
----------

Если у элемента нет родительской ветки, которая не является корневой веткой документа, установка его свойства `outerHTML` выбросит исключение `DOMException` с кодом ошибки `NO_MODIFICATION_ALLOWED_ERR`. Например:

```js
document.documentElement.outerHTML = "test"; // бросает DOMException
```

Обратите внимание, когда произойдёт изменение элемента в документе, переменная, у которой было установлено свойство `outerHTML`, будет по-прежнему хранить ссылку на оригинальный элемент:

```js
var p = document.getElementsByTagName("p")[0];
console.log(p.nodeName); // показывает: "P"
p.outerHTML = "<div>Этот div заменил параграф.</div>";
console.log(p.nodeName); // всё ещё "P";
```

Спецификации
------------

| Specification |
| --- |
| DOM Parsing and Serialization # dom-element-outerhtml |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* MSDN: outerHTML Property


Element.scrollTo() - Интерфейсы веб API

Element.scrollTo()
==================

**`scrollTo()`** метод интерфейса `Element`, осуществляет прокрутку по заданному набору координат внутри данного элемента.

Синтаксис
---------
```

element.scrollTo(x-coord, y-coord)
element.scrollTo(options)
```

### Параметры

* `x-coord` координаты пикселя по горизонтальной оси элемента, который необходимо отобразить вверху слева.
* `y-coord` координаты пикселя по вертикальной оси элемента, который необходимо отобразить вверху слева.

- or -

* `options` как объект `ScrollToOptions` (en-US), с тремя свойствами.
Примеры
-------

```js
element.scrollTo(0, 1000);
```

С помощью `options`:

```js
element.scrollTo({
  top: 100,
  left: 100,
  behavior: "smooth",
});
```

Спецификации
------------

| Specification |
| --- |
| CSSOM View Module # dom-element-scrollto |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* `Element.scrollTop`, `Element.scrollLeft`
* `Window.scrollTo()`


Element.querySelector() - Интерфейсы веб API

Element.querySelector()
=======================

Возвращает первый элемент, являющийся потомком элемента, на который применено правило указанной группы селекторов.

Синтаксис
---------
```

element = baseElement.querySelector(selectors);
```

* `element` и `baseElement` это `element` объекты.
* `selectors` - это группа селекторов (en-US) для поиска совпадения.
Пример
------

Данный пример получает первый элемент style, который не имеет атрибута type или этот атрибут равен text/css, в теле (body) HTML документа:

```js
var el = document.body.querySelector(
  "style[type='text/css'], style:not([type])",
);
```

Примечания
----------

Возвращает null если совпадения не найдены, иначе первый найденный элемент.

Генерирует исключение `SYNTAX_ERR` если указанная группа селекторов не корректна.

`querySelector()` был представлен в WebApps API.

Строка аргументов передаваемая `querySelector()` должна удовлетворять синтаксису CSS. Более подробные примеры смотрите в `document.querySelector`.

Спецификация
------------

| Specification |
| --- |
| DOM Standard # ref-for-dom-parentnode-queryselectorall① |

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

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* `element.querySelectorAll()`
* `document.querySelector()`
* `document.querySelectorAll()`
* Фрагменты кода для querySelector