====== Упражнения и задания к урокам ======
[[http://wiki.nsunc.com/_export/html/javascript/ex|удобный для просмотра вид]]
===== Урок 1: введение =====
Язык JavaScript изначально был предназначен для написания простых сценариев, исполняемых в среде www-браузера...
На [[http://learn.javascript.ru/hello-world|странице портала javascript.ru]] и в разделе
[[http://ru.wikipedia.org/wiki/JavaScript#.D0.92.D1.81.D1.82.D1.80.D0.B0.D0.B8.D0.B2.D0.B0.D0.BD.D0.B8.D0.B5_.D0.B2_.D0.B2.D0.B5.D0.B1-.D1.81.D1.82.D1.80.D0.B0.D0.BD.D0.B8.D1.86.D1.8B|Встраивание в веб-страницы]] на wikipedia подробное обсуждается вопрос внедрения скриптов в тело html-страниц с примерами и историей вопроса. Если коротко, то самый компактный и современный (по стандарту html5) вариант выглядит так:
На данной странице предложен пример расчета факториала...
более общий и более совместимый со стандартом html4 -- так:
ещё более древний, не стандартный, но до сих пор самый ходовой:
(возможно их совмещение, указание дополнительных атрибутов, напр., кодировки скрипта -- примеры см. на указанных выше сайтах)
Наиболее важным для нас атрибутом является src, который позволяет подгружать внешний отдельный файл со скриптом.
===== Урок 2: ввод-вывод информации из скрипта =====
Простейший вывод из скрипта на JavaScript осуществляется с помощью вызова функции
Реализацию можно посмотреть тут: [[http://users.nsunc.com/~vlasov/javascript/hellow.html|Hello, world!]]
Простейший ввод можно сделать с помощью функции prompt().
Реализацию можно посмотреть тут: [[http://users.nsunc.com/~vlasov/javascript/alertprompt.html|Alert-Prompt]]
(в Internet Explorer'е может быть заблокировано окошко ввода, и надо будет дать специальное разрешение на временное исполнение скрипта)
**NB!!** Вот здесь надо прочитать [[http://javascript.ru/unsorted/why_href_js_is_bad|Почему - плохо]]
Следующее упражнение: вычисление факториала от заданного числа, с возможностью продолжения и прекращения выполнения вычисления.
Расчет факториала
Для завершения работы введите любое ненатуральное число и/или буквы.
Перезапуск
working with form
Форма ввода
Обрабатываем форму ввода...
Обращение к полям в функции Yeah() происходит как квалифицированной глобальной переменой, точнее, как к свойству объекта, внешнего по отношению к телу функции. Запись
document.fm1.tx1.value
как раз и показывает пример такого обращения. Здесь document -- это объект самого высокого уровня (выше -- ссылка на окно, по умолчанию -- текущее), fm1 -- имя формы (подчиненного объекта), заданной в атрибуте name формы, tx1 -- имя
имя текстового поля ввода (подчиненного к форме), value -- изменяемое свойство объекта document.fm1.tx1.
Пример доступен здесь: [[http://users.nsunc.com/~vlasov/javascript/forma.html|Доступ к полям формы через объекты]]
Добавим еще код. Теперь обратимся к элементам формы не через глобальный объект, а через передачу ссылки на объект при вызове функции, сократив таким образом количество вводимого текста и сделав функцию вызова более универсальной (единообразно пригодной для обработки других форм на странице).
Определим Ваш любимый цвет:
В заключение темы стоит отметить, что современным способом вывода отладочной информации является использование ''console'':
console.log("var =", myvar);
===== Урок 3: управляющие операторы, создание функций =====
Пока сообщим, что язык Си-подобный, основные управляющие операторы if, for, while и др. наследуются из Си. Особенности опишем позже :)
В качестве примера рассмотрим "решатель квадратных уравнений":
function roots(a,b,c)
{
var sd,x1,x2;
if (a==0 && b==0) return;
if (a==0 && b!=0) { x1=-c/b; return [x1,x1] };
var d = b*b - 4*a*c;
if (d>=0)
{
sd = Math.sqrt(d);
x1 = (-b-sd)/(2*a);
x2 = (-b+sd)/(2*a);
return [x1,x2];
}
else return;
}
запуск будем осуществлять через такую страничку:
Решатель квадратных уравнений
Решатель квадратных уравнений
===== Урок 4: динамическое изменение документов (простой вариант) =====
Сочетание JavaScript и HTML4 дает возможность простого изменения содержимого документов в случае если теги поддерживают изменение атрибутов, либо с помощью функции write мы можем перезаписать содержимое документа.
При применении функции write должна происходить дозапись в конец документа, однако может происходить и удаление предыдущего и запись нового документа. В таком случае, лучше не надеясь на сохранение предыдущего документа, осуществлять перезапись во фрейм. Данная последовательность команд всегда делает перезапись:
top.doc.document.open();
top.doc.document.write("Hello!
");
top.doc.document.close();
Здесь top -- ссылка на окно самого верхнего уровня (в нашем случае будем фреймсодержащее окно), top.doc -- ссылка на окно (фрейм), предназначенное для перезаписи.
Если речь идет о текущем окне, то пишем document.open() и т.п.
Иллюстрация описанных идей: [[http://users.nsunc.com/~vlasov/javascript/doc.html|Пример динамического изменения документа]]
===== Урок 5: динамическое изменение документов (более сложный вариант) =====
Рассмотрим элементы наиболее современной технологии динамического изменения элементов HTML документа: так называемую технологию DOM.
Прежде всего мы должны уметь получить ссылку на желаемый html-элемент по его "ID":
...
...
var zdes = document.getElementById("label123")
Далее, мы должны сформировать html-контейнер, который будет содержать требуемый html-код, и текст:
var node1 = document.createElement('p');
var node2 = document.createTextNode("В лесу родилась елочка");
Теперь, добавим текстовое содержимое (т.е. node2) в заданный контейнер (т.е. node1):
node1.appendChild(node2);
Затем, мы должны добавить полученный контейнер в дерево документа:
zdes.appendChild(node1);
Обращаясь каждый раз к данному коду, мы можем добавить ряд подобных записей. Чтобы теперь удалить последнего "потомка", сделаем так:
zdes.removeChild(zdes.lastChild)
а чтобы удалить их всех, так:
function MyClear()
{
while (zdes.lastChild) { zdes.removeChild(zdes.lastChild) };
};
Теперь, можно посмотреть реализацию данных идей в примере тут:
[[http://users.nsunc.com/~vlasov/javascript/simpledom.html|Пример динамического изменения документа]]
Эта тема рассмотрена на сайте javascript.ru: [[http://javascript.ru/tutorial/dom/modify|Изменение страницы посредством DOM]].
**Другие возможности.** Можно упростить вставку, не формируя поддерево DOM, а вставляя лишь требуемый html-код. Об этом можно почитать, напр., тут: [[http://habrahabr.ru/post/235333/|JavaScript метод insertAdjacentHTML и beforeend]] или тут: [[http://innerhtml.ru/|Свойство innerHTML]].
**Использование css.** Для создания спойлеров, описанный выше метод может оказаться громоздким. Более простым решением будет манипуляция свойством стиля, например: display:none или display:block (см. описание [[http://htmlbook.ru/css/display|display]] или похожую технику [[http://htmlbook.ru/css/visibility|visibility]])
И реализовать тогда его можно следующим образом. Получаем как прежде ссылку на требуемый объект (html-ноду):
...
...
var zdes = document.getElementById("label123")
Затем устанавливаем
zdes.style.display = 'none';
и наш
zdes.style.display = 'block';
и он появится! 8-)
==== Урок 5.1: Создаем свой спойлер ====
Сформулируем такую задачу: //необходимо создать разметку спойлера, основанную на тэгах div и необходимых классах, сопровождение в виде js-функций, с тем, чтобы при отсустствии поддержки javascript в окне браузера, все спойлеры были раскрыты и никаких затруднений (и даже напоминаний о спойлере) у пользователя не возникало.//
Иными словами, выглядеть это должно примерно так:
...здесь скрываемый текст...
Для начала определим пару полезных нам функций:
function getTagged(name, elem) {
return (elem || document).getElementsByTagName(name);
}
function getNext(elem) {
do {
elem = elem.nextSibling;
} while ( elem && elem.nodeType != 1 );
return elem;
}
Здесь первая функция ''getTagged'' собирает множество элементов с тэгом ''name'', при этом, если задан второй аргумент ''elem'', то в его <<потомках>>, если не задан, то -- по всему документу.
Вторая функция ''getNext'' находит и возрващает следующий сестринский элемент, который не будет являться текстом. Следует иметь ввиду, что текстом может оказаться простой перевод строки, поэтому проверка
elem.nodeType != 1
важна, если есть такой риск.
Теперь, собственно, основной код:
var alldiv = getTagged("div");
for (var j=0; j
Прокомментируем программу. Условие
if(alldiv[j].className == "spoilertitle")
делает отбор только тэгов, помеченных классом ''spoilertitle''. Для этого контейнера, мы, во-первых вставляем следом (но перед спойлером!) html-текст из <<нестандартного>> атрибута ''text'':
alldiv[j].insertAdjacentHTML('afterbegin', alldiv[j].getAttribute("text"));
Строка
alldiv[j].onclick = spoiling;
создает обработчик события клика мышкой по содержимому контейнера. Заметим, что ''spoiling'' -- всего лишь ссылка на функцию, а не ее вызов типа ''spoiling(..)''!
Строки
alldiv[j].onmouseover = function(){this.style.textDecoration="underline"};
alldiv[j].onmouseout = function(){this.style.textDecoration="none"};
описывают поведение, когда наводим мышку на текст и когда уводим мышку. Также обращаем внимание, что вместо ссылки на функцию используем анонимную функцию, созданную прямо по месту применения.
Далее, в блоке
var nxt = getNext(alldiv[j]);
while ( nxt.className != "spoiler" ) {nxt = getNext(nxt)};
nxt.style.border = "dotted black";
nxt.style.backgroundColor = "aqua";
nxt.style.display = "none";
во-первых, с помощью ''nxt = getNext(alldiv[j])'' получаем ссылку на следующий контейнер (сестринский элемент), перебираем их все, проверяя, чтобы был в наличии класс ''spoiler'':
while ( nxt.className != "spoiler" ) {nxt = getNext(nxt)};
Для найденного элемента ''nxt'' устанавливаем требуемое стилевое оформление:
nxt.style.border = "dotted black";
nxt.style.backgroundColor = "aqua";
nxt.style.display = "none";
где самое главное для нас -- скрытое по умолчанию состояние спойлера: ''nxt.style.border = "dotted black" ''
И, наконец, рассмотрим функцию-обработчик клика, которая и осуществляет работу спойлера.
Строки вроде таких
var nxt = getNext(this);
while ( nxt.className != "spoiler" ) {nxt = getNext(nxt)};
мы уже обсуждали.
Команда
console.log("check: ", nxt.style.display);
позволяет нам осуществить запись в лог значения ''nxt.style.display''.
Наконец, проверяем
if (nxt.style.display == "none") {nxt.style.display = "block"; console.log("set=",nxt.style.display); return};
if (nxt.style.display == "block" || !nxt.style.display) {nxt.style.display = "none"; console.log("set=",nxt.style.display)};
состояние значения ''nxt.style.display'' и соответственно переобпредляем это значение на противополжное (отдельная забота о случае, если pyfxtybt ''nxt.style.display'' не определено).
Код базируется на примерах, взятых из книги Резинга, создателя пакета ''jquery''; разность стилей в выполнении однотипных задач определяется ленью и забывчивостью...
===== Урок 6: динамическое изменение картинок и события задержки =====
В браузерах рисунки рассматриваются как объекты с набором некоторых свойств. Таким образом, новый рисунок может быть создан в скрипте таким образом:
img1 = new Image(40,120);
(однако, это не значит, что он будет отображен, тем не менее, он будет добавлен в кэш и в случае необходимости мгновенно отображен)
Наиболее важным для нас атрибутом будет src, значение которого мы будем динамически менять.
Сами рисунки в документе организованы в массив, к которому удобно обращаться, если нам ненужно или неудобно обращать к рисунку по имени-ссылке.
Имя рисунка, заданного тегом будет совпадать со значением атрибута name.
Вот как это реализовано в примере: [[http://users.nsunc.com/~vlasov/javascript/knopa.html|Дин. картинки]]
===== Урок 7: тайм-аут ;-) =====
[[http://users.nsunc.com/~vlasov/javascript/data.html|Пример работы с таймером и с датой]] демонстрирует "старый стиль" работы с таймером: вместо установки setInterval используем рекурсивный вызов таймера, и вместо передачи ссылки на функцию передаем строку с выражением для выполнения.
sic (на будущее) [[http://htmlweb.ru/java/example/calendar_kdg.php|работа с календарем]]