мета-данные страницы
Упражнения и задания к урокам
Урок 1: введение
Язык JavaScript изначально был предназначен для написания простых сценариев, исполняемых в среде www-браузера…
На странице портала javascript.ru и в разделе Встраивание в веб-страницы на wikipedia подробное обсуждается вопрос внедрения скриптов в тело html-страниц с примерами и историей вопроса. Если коротко, то самый компактный и современный (по стандарту html5) вариант выглядит так:
<script> alert('Hello, World!'); </script>
более общий и более совместимый со стандартом html4 – так:
<script type="text/javascript"> alert('Hello, World!'); </script>
ещё более древний, не стандартный, но до сих пор самый ходовой:
<script language="javascript"> alert('Hello, World!'); </script>
(возможно их совмещение, указание дополнительных атрибутов, напр., кодировки скрипта – примеры см. на указанных выше сайтах)
Наиболее важным для нас атрибутом является src, который позволяет подгружать внешний отдельный файл со скриптом.
Урок 2: ввод-вывод информации из скрипта
Простейший вывод из скрипта на JavaScript осуществляется с помощью вызова функции alert("string").
<html> <head><title>Hello, world!</title></head> <body> <p><a href="javascript:alert('Hello, world!')">Click me!</a></p> </body> </html>
Реализацию можно посмотреть тут: Hello, world!
Простейший ввод можно сделать с помощью функции prompt().
<html> <head><title>Alert-Prompt</title></head> <body> <p><a href="javascript:n=prompt('Put something, please:','');alert(n)">Click me!</a></p> </body> </html>
Реализацию можно посмотреть тут: Alert-Prompt (в Internet Explorer'е может быть заблокировано окошко ввода, и надо будет дать специальное разрешение на временное исполнение скрипта)
NB!! Вот здесь надо прочитать Почему <a href="javascript:..."> - плохо
Следующее упражнение: вычисление факториала от заданного числа, с возможностью продолжения и прекращения выполнения вычисления.
<HTML> <HEAD> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <TITLE>n!-calculating</TITLE> <SCRIPT LANGUAGE="JavaScript"> function checkinput(n) { var n1; n = n + ""; n1 = parseInt(n) + ""; if ((n == n1) && (n1>0)) {return 1} else {return 0}; } // checkinput function fact(n) { if ( n==0 ) { return 1; }; return n*fact(n-1); }; // fact function You_Go() { n = prompt('put in the field a natural number: ',1); while ( checkinput(n) ) { f = fact(n); n = prompt('n!='+f+'\nput in the field a natural number: ',1); } }; </SCRIPT> </HEAD> <BODY BGCOLOR="White" TEXT="Black" LINK="Blue" VLINK="Purple" ALINK="Red"> <H1>Расчет факториала</H1> <P>На данной странице предложен пример расчета факториала... <BR> Для завершения работы введите любое ненатуральное число и/или буквы. <hr> <a href="javascript:You_Go()">Перезапуск</a></P> <SCRIPT LANGUAGE="JavaScript">You_Go()</SCRIPT> </BODY> </HTML>
Реализацию можно посмотреть тут: факториал (в Internet Explorer'е может быть заблокировано окошко ввода, и надо будет дать специальное разрешение на временное исполнение скрипта)
Таким образом, в этом уроке, кроме собственно ввода и вывода данных, мы видим активацию функций JavaScript по событиям, задаваемым пользователем, таким как клик мышкой по ссылке, изменение данных в форме ввода и т.п. Связь эта изначально описывалась атрибутами onclick, onchange, onload и другим, добавленными к некоторым тегам в html-3, либо обработчиками в форме по атрибуту action или по псведопротоколу в ссылках (см. выше). В настоящее время, отчетливо сформировалась другая тенденция, так называемый ненавязчивый JavaScript, суть которого еще больше разделить контент с размеченным html-текстом и скрипты поддержки на javascript. Но об этом в другой раз.
Урок 2.1: ввод-вывод из полей формы
На практике функцию prompt() используют чаще всего в целях отладки. Для ввода удобней поля специально предназначенных для этого форм. Рассмотрим пример:
<HTML> <HEAD> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <TITLE>working with form</TITLE> </HEAD> <BODY BGCOLOR="White" TEXT="Black" LINK="Blue" VLINK="Purple" ALINK="Red"> <H1>Форма ввода</H1> <P>Обрабатываем форму ввода...</P> <P><form name="fm1" action="javascript:void(Yeah())"> <INPUT TYPE="text" name="tx1" value="это текст!! :)" size="60"> <INPUT TYPE="button" VALUE="Сменить!" onClick="Yeah()"> <INPUT TYPE="reset" VALUE="Сброс"> </form></P> <SCRIPT LANGUAGE="JavaScript"> function Yeah() { var s1 = document.fm1.tx1.value; var s2 = prompt('Введите что-нибудь еще!\nВаш ввод был:', s1); document.fm1.tx1.value = s2; } </SCRIPT> </BODY></HTML>
Обращение к полям в функции Yeah() происходит как квалифицированной глобальной переменой, точнее, как к свойству объекта, внешнего по отношению к телу функции. Запись
document.fm1.tx1.value
как раз и показывает пример такого обращения. Здесь document – это объект самого высокого уровня (выше – ссылка на окно, по умолчанию – текущее), fm1 – имя формы (подчиненного объекта), заданной в атрибуте name формы, tx1 – имя имя текстового поля ввода (подчиненного к форме), value – изменяемое свойство объекта document.fm1.tx1.
Пример доступен здесь: Доступ к полям формы через объекты
Добавим еще код. Теперь обратимся к элементам формы не через глобальный объект, а через передачу ссылки на объект при вызове функции, сократив таким образом количество вводимого текста и сделав функцию вызова более универсальной (единообразно пригодной для обработки других форм на странице).
<P>Определим Ваш любимый цвет:</P> <P><form name="fm2"> <select name="sl"> <option>красный</option> <option>зеленый</option> <option>синий</option> <option>желтый</option> <INPUT TYPE="button" VALUE="Посмотрим выбор!" onClick="GoNow(this.form.sl)"> <INPUT TYPE="reset" VALUE="Сброс"> </form</P> <SCRIPT LANGUAGE="JavaScript"> function GoNow(s) { var i = s.selectedIndex; var s = s.options[i].text; alert ("" + s); }; </SCRIPT>
В заключение темы стоит отметить, что современным способом вывода отладочной информации является использование 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; }
запуск будем осуществлять через такую страничку:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Решатель квадратных уравнений</title> </head> <script src="roots.js"></script> <body> <H1>Решатель квадратных уравнений</H1> <form name="myform"> a: <input type="text" name="a"> b: <input type="text" name="b"> c: <input type="text" name="c"> <input type="button" name="runtest" value="Решить" onclick="alert(roots(this.form.a.value,this.form.b.value,this.form.c.value))"> <input type="reset"> </form> </body> </html>
Урок 4: динамическое изменение документов (простой вариант)
Сочетание JavaScript и HTML4 дает возможность простого изменения содержимого документов в случае если теги поддерживают изменение атрибутов, либо с помощью функции write мы можем перезаписать содержимое документа.
При применении функции write должна происходить дозапись в конец документа, однако может происходить и удаление предыдущего и запись нового документа. В таком случае, лучше не надеясь на сохранение предыдущего документа, осуществлять перезапись во фрейм. Данная последовательность команд всегда делает перезапись:
top.doc.document.open(); top.doc.document.write("<P>Hello!</P>"); top.doc.document.close();
Здесь top – ссылка на окно самого верхнего уровня (в нашем случае будем фреймсодержащее окно), top.doc – ссылка на окно (фрейм), предназначенное для перезаписи.
Если речь идет о текущем окне, то пишем document.open() и т.п.
Иллюстрация описанных идей: Пример динамического изменения документа
Урок 5: динамическое изменение документов (более сложный вариант)
Рассмотрим элементы наиболее современной технологии динамического изменения элементов HTML документа: так называемую технологию DOM.
Прежде всего мы должны уметь получить ссылку на желаемый html-элемент по его «ID»:
<div id="label23">...</div> ... 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) }; };
Теперь, можно посмотреть реализацию данных идей в примере тут: Пример динамического изменения документа
Эта тема рассмотрена на сайте javascript.ru: Изменение страницы посредством DOM.
Другие возможности. Можно упростить вставку, не формируя поддерево DOM, а вставляя лишь требуемый html-код. Об этом можно почитать, напр., тут: JavaScript метод insertAdjacentHTML и beforeend или тут: Свойство innerHTML.
Использование css. Для создания спойлеров, описанный выше метод может оказаться громоздким. Более простым решением будет манипуляция свойством стиля, например: display:none или display:block (см. описание display или похожую технику visibility)
И реализовать тогда его можно следующим образом. Получаем как прежде ссылку на требуемый объект (html-ноду):
<div id="label23">...</div> ... var zdes = document.getElementById("label123")
Затем устанавливаем
zdes.style.display = 'none';
и наш
..
вместе с содержимым визуально исчезнет. Выставим теперь:
zdes.style.display = 'block';
и он появится!
Урок 5.1: Создаем свой спойлер
Сформулируем такую задачу: необходимо создать разметку спойлера, основанную на тэгах div и необходимых классах, сопровождение в виде js-функций, с тем, чтобы при отсустствии поддержки javascript в окне браузера, все спойлеры были раскрыты и никаких затруднений (и даже напоминаний о спойлере) у пользователя не возникало.
Иными словами, выглядеть это должно примерно так:
<div class="spoilertitle" text="THIS IS SPOILER!!!"></div> <div class="spoiler"> ...здесь скрываемый текст... </div>
Для начала определим пару полезных нам функций:
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<alldiv.length; j++) { if(alldiv[j].className == "spoilertitle") { alldiv[j].insertAdjacentHTML('afterbegin', alldiv[j].getAttribute("text")); alldiv[j].onclick = 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"; }; } function spoiling() { var nxt = getNext(this); while ( nxt.className != "spoiler" ) {nxt = getNext(nxt)}; console.log(nxt.id, "check: ", 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)}; }
Прокомментируем программу. Условие
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, значение которого мы будем динамически менять. Сами рисунки в документе организованы в массив, к которому удобно обращаться, если нам ненужно или неудобно обращать к рисунку по имени-ссылке.
Имя рисунка, заданного тегом <img name="myimg" src="pict.gif"> будет совпадать со значением атрибута name.
Вот как это реализовано в примере: Дин. картинки
Урок 7: тайм-аут ;-)
Пример работы с таймером и с датой демонстрирует «старый стиль» работы с таймером: вместо установки setInterval используем рекурсивный вызов таймера, и вместо передачи ссылки на функцию передаем строку с выражением для выполнения.
<HTML>
<script> var alldiv = getTagged(«div»);
for (var j=0; j<alldiv.length; j++) {
if(alldiv[j].className == "spoilertitle") { alldiv[j].insertAdjacentHTML('afterbegin', alldiv[j].getAttribute("text")); alldiv[j].onclick = 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"; };
}
function spoiling() {
var nxt = getNext(this); while ( nxt.className != "spoiler" ) {nxt = getNext(this)}; console.log(nxt.id, "check: ", 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)};
}
function getTagged(name, elem) {
return (elem || document).getElementsByTagName(name);
}
function getNext(elem) {
do { elem = elem.nextSibling; } while ( elem && elem.nodeType != 1 ); return elem;
} </script> </HTML>