JavaScript и Web-программирование Валеев Т. Ф. к.ф.-м.н., н.с. ИСИ СО РАН Материалы курса: http://nprog.ru/~lan/CourseJS Введение в CSS • • CSS — каскадные таблицы стилей На данный момент неплохо поддерживается CSS 3.0 (IE – с 9-й версии) http://www.w3.org/TR/CSS2/ http://www.w3.org/Style/CSS/specs http://www.w3.org/TR/css-2010/ Определение стиля: – Внутри тега: <div style=“color: red;”> (не рекомендуется) – В заголовке HTML-документа: <style>...</style> – В отдельном файле стилей .css <link rel="stylesheet" type="text/css" href="style.css"/> • Стиль применяется в соответствии с селектором. Вот некоторые примеры ( => styles.html): – – – – – – div {color: blue;} div.alert {color: red;} // <div class=“alert”>!!!</div> div#msg {color: green;} // <div id=“msg”>Green message</div> a:hover {text-decoration: underline;} div.alert span, span.alert {background: yellow;} input[type=“text”] {background: blue;} Введение в CSS: некоторые свойства • Свойства (property) разделяются точкой с запятой • Свойства задаются в виде «имя: значение» • Отдельные элементы значения разделяются пробелами или (редко) запятыми • Для расстояний всегда надо задавать единицу измерения • Некоторые свойства используются как сокращения для других свойств (border; border-top; border-width; border-top-width) • Оформление текста: color, background, font-family, font-size, textdecoration , text-indent, text-transform, font-weight, white-space • Box-model: margin, border, padding • Заполнение: width, height, overflow (hidden/auto/scroll) • Расположение блоков: display (block/inline/none), float, z-index, position (relative/absolute/fixed), left, right, top, bottom CSS: рекомендации • • • • • • • • http://habrahabr.ru/post/160177/ Код CSS «с душком» http://practicaltypography.com/index.html Butterick’s Practical Typography Рекомендуется большинство стилей задавать в заголовке или внешнем CSS-файле, определяя их для классов или для id, отделяя тем самым документ от представления Не забываем, что в документе не должно быть более одного элемента с заданным id! Вместо <div style=“border: 1pt solid blue; background: yellow url(‘static/back.png’); color: blue; text-decoration: underline; font-weight: bold”> пишем: <div class=“highlighted”> // в static/style.css-файле: div.highlighted { color: blue; text-decoration: underline; font-weight: bold; background: yellow url(‘back.png’); // путь относительно .css-файла, а не исходного html! border: 1pt solid blue; } Явно задавать можно стиль display (скрыть/показать элемент), а также стили, значение которых может меняться непрерывно (а не переключаться между несколькими состояниями). Пример: ширина полосы прогресс-индикатора width. Элемент может принадлежать нескольким классам (указывать через пробел). Пример: => tabs.html Введение в DOM • DOM — Document Object Model — кроссплатформенный программный интерфейс для представления и взаимодействия с объектами в HTML, XHTML, XML-документах (http://www.w3.org/DOM/DOMTR ); • Стандарт: DOM3 (2004), черновик: DOM4 (2014) • Имеются реализации DOM на разных языках, в том числе JavaScript (но DOM не является неотъемлемой частью JavaScript!) • Каждый элемент HTML(XML)-документа представляется в виде объекта определённого класса в иерархии со своим набором методов, полей и обработчиков событий; • Большинство полей соответствуют атрибутам соответствующего тега, что позволяет получать текущее состояние и визуальное представление элемента или менять его. • Tutorial: http://www.w3schools.com/dom/default.asp DOM: поиск нужных элементов (Vanilla JS!) • Получение элемента или группы элементов: – – – – document.getElementById(“id”) document.getElementsByName(“name”) document.getElementsByTagName(“div”) document.getElementsByClassName(“name”) ( => dynamiclist.html ) • Обход дерева элементов: – – – – elem.getElementsByTagName(“*”) elem.parentNode() elem.childNodes[i] elem.firstChild, elem.lastChild, nextSibling, prevSibling • Осторожно: текстовые элементы! ( => domtraversal.html ) DOM: создание элемента • Создание: newelem = document.createElement(‘div’); textnode = document.createTextNode(‘Text’); clone = elem.cloneNode(true); • Вставка в документ: oldelem.appendChild(newelem); • Удаление: parent.removeChild(removeelem); DOM: получение информации об элементе • Общее: – node.nodeType (1 = элемент, 3 = текстовый объект и др.) • Элементы (теги): – – – – elem.id — поле id элемента elem.tagName — имя тега (DIV, BODY и т. д.) elem.className — классы стилей elem.innerHTML — HTML внутри элемента • Текстовый объект: – textnode.data — содержимое – textnode.isElementContentWhitespace — одни пробелы или нет DOM: управление атрибутами • Стандартные атрибуты тега обычно доступны как поля соответствующего элемента ( => attr.html) • Аттрибуты могут преобразовываться браузером автоматически (вы необязательно получите точно то, что установили) • Стили доступны в объекте style, имена свойств пишутся слитно (без дефисов), второе и последующие слова с большой буквы: text-decoration (CSS) => textDecoration (DOM) (не забывайте единицы измерения!) • Имена классов доступны в elem.className • Почти всё доступно для записи DOM: пользовательские аттрибуты • Пользовательские аттрибуты недоступны как поле класса, но доступны как объект Attr ( => attr_u.html) • Можно использовать getAttribute/setAttribute • Удалить атрибут: removeAttribute • HTML-5: data-* DOM: события (events) • Элементу можно назначить обработчик события в соответствующем атрибуте тега: <div onclick=“handleClick()”> или в скрипте: elem.onclick = handleClick; // старый метод elem.addEventListener(“click”, handleClick); // современный метод • Виды событий: – От мыши: click, dblclick, mousemove, mouseover, mouseout, mousedown, mouseup и т. д. (события от правой кнопки пользователь может запретить!) – От клавиатуры: keydown, keyup – Логические: focus, blur, change • Обработчику события передаётся параметром объект event, позволяющий узнать дополнительную информацию о событии (координаты клика мышки, состояние клавиш shift, ctrl, alt и т. д.) • Простой пример: => mousemove.html DOM: назначение события на клик • Некоторые используют тег <a>: <a href=“#” onclick=“handleclick(this)”> Способ неправильный ( => handleclick.html ) • Следует писать <span class=“clickable” onclick=“handleclick(this)”> • Можно даже <span class=“clickable”> А где-то ниже (+ jQuery) <script> $(‘.clickable’).click(handleclick); </script> => clickable.html DOM: управление элементами формы • • • • Фокус ввода: focus(), blur() Эмуляция клика: click() Выделение текста в текстовом поле: select() Манипуляция списком <select>: add(), remove() Координаты объектов • С координатами много проблем • Есть координаты в клиентской области, координаты в буфере прокрутки, координаты относительно родителя, позиция собственного буфера прокрутки (scrollLeft, scrollTop) • У элемента имеется offsetLeft, offsetTop, offsetParent. • Ширина объектов: clientWidth (ширина содержимого, видимая на странице), offsetWidth (ширина элемента, занимаемая на странице), scrollWidth (полная ширина с учётом буфера прокрутки) ( => width.html) AJAX • AJAX = Asynchronous Javascript + XML — технология, позволяющая клиентскому JS-коду самостоятельно выполнять HTTP-запросы к серверу • IFrames: IE 3.0, 1996 • XMLHTTP ActiveX control: IE 5.0, 1999 • Название AJAX — Garret, 2005-й год, тогда же началось распространение технологии (Gmail, Google Maps) • Черновик стандарта W3C: http://www.w3.org/TR/XMLHttpRequest/ AJAX: синтаксис • Для создания AJAX-запросов в современных браузерах используется DOM-объект XMLHttpRequest: var req = new XMLHttpRequest() • В более старых браузерах (IE 5, IE 5.5, IE 6) синтаксис отличался, поэтому рекомендуется пользоваться библиотеками prototype.js/jQuery, которые реализуют совместимый с многими браузерами класс для AJAX-запросов. • req.open(method, URL, async?[, user, password]) – method = GET/POST/HEAD/etc. (IE кэширует GET-запросы!) – URL (должен быть на том же сервере и на том же порту, что и исходный документ!) – async? = true/false, является ли запрос асинхронным (рекомендуется всегда ставить true) – user/password для HTTP-аутентификации, обычно не нужно AJAX: синтаксис • req.setRequestHeader(name, value) — добавить полей в заголовок HTTP-запроса (текущие cookies, httpаутентификация и ряд других полей добавляются автоматически, часть полей установить нельзя!) • req.onreadystatechange — обработчик события изменения состояния запроса • req.send(content) — отправить запрос. Значение content обычно null. Асинхронный запрос не блокирует программу. Когда он будет выполнен, вызовется обработчик onreadystatechange • req.abort() — прервать запрос AJAX: обработчик onreadystatechange • Внутри обработчика можно использовать: – req.readyState — текущий статус • 0 — uninitialized, 1 — open, 2 — sent, 3 — receiving, 4 — loaded – req.status — код возврата HTTP-сервера • 200 = OK, 404 = Not found, 500 = Server error, etc. – req.getResponseHeader(headerField) — поле HTTPзаголовка ответа (например, “Content-type”) – req.responseText — документ, возвращённый сервером ( => ajaxbasic.html) – req.responseXML — DOM-объект возвращённого XMLдокумента (если вернули XML-документ). Для него весь DOM работает! AJAX: сценарии использования • • Сохранение состояния на сервере. В запросе передаются параметры пользовательского ввода (например, форма), факт получения ответа 200 свидетельствует об успешном сохранении на сервере (responseText не требуется или минимален) Получение информации с сервера в текстовом виде. Запрашивается некоторое значение (текущая температура воздуха, количество ответов в теме на форуме, занято ли выбранное пользователем имя и т. д.), которое затем вписывается в соответствующее поле на странице: Desired user name: <input onblur=“checkname(this.value)” type=“text”><span id=“check_name”></span> <script> function checkname(name) { var req = new XMLHttpRequest(); req.open(“POST”, “checkname.pl?name=“+name, true); req.onreadystatechange = function() { if(req.readyState == 4 && req.status == 200) { document.getElementById(‘check_name’).innerHTML = req.responseText == ‘OK’?’Ok’:’Please select another name’; } } req.send(); } </script> AJAX: сценарии использования • • • • Получение фрагмента HTML-документа и внедрение его в нужное место: <div id=“info”></div> … document.getElementById(“info”).innerHTML = req.responseText; Так удобно периодически (или по запросу пользователя) обновлять фрагмент страницы, не трогая страницу целиком (похоже на IFrame) Если пришедший фрагмент содержит блоки <script>, они не выполнятся автоматически! (см. prototype.js) Выполнение пришедшего JS-кода: eval(req.responseText); практически универсальная конструкция: пришедший с сервера код может сделать любое другое действие (встроить фрагмент HTML-кода в нужное место, поменять значения каких-либо полей и т. д.) Получение XML с последующей обработкой: x=req.responseXML.documentElement.getElementsByTagName(“State"); alert(x.length.toString()+” state(s) were loaded”); Получение информации в произвольно форматированном виде и её разбор (regexp, string functions, etc.) — обычно некрасиво. AJAX: обработка ошибок • • • • Ошибки, возвращённые HTTP-сервером: проверить req.status Ошибки при подключении к серверу (DNS lookup failure, connection refused, etc.): req.status = 0 Тайм-аут подключения к серверу — обработать самим: var reqtimer = setTimeout(function() {req.abort();alert(‘Timeout in AJAX call’);}, 1000); req.onreadystatechange = function() { if(req.readyState != 4) return; clearTimeout(reqtimer); … } Что сказать пользователю? – Ничего – Показать предупреждение, попытаться повторить запрос (если был тайм-аут) – Показать сообщение об ошибке, разрешить пользователю повторить запрос вручную