Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

return к функциям (функции и события)

 

Данный раздел подразумевает, что мы вернемся к функциям и найдем им применение в событиях.

Помните, следующий пример:

 

<html>
<body>
<input id="text" type="text" style="color: grey; font-size: small; font-style: italic; width: 200px; height: 20px;" value="Введите текст" onFocus="if(this.value == 'Введите текст') {this.value=''; this.style.color='black'; this.style.fontSize='normal'; this.style.fontStyle='normal';}" onBlur="if(this.value == '') {this.value='Введите текст'; this.style.color='grey'; this.style.fontSize='small'; this.style.fontStyle='italic';}" />
</body>
</html>

 

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

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

 

function clean() {
element = document.getElementById('text');

if (element.value == 'Введите текст') {
element.value = '';
element.style.color = 'black';
element.style.fontSize = 'normal';
element.style.fontStyle = 'normal';
}
}

 

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

 

function fill() {
element = document.getElementById('text');

if (element.value == '') {
element.value = 'Введите текст';
element.style.color = 'grey';
element.style.fontSize = 'small';
element.style.fontStyle = 'italic';
}
}

 

Да, а теперь давайте привяжем данные функции к определенным событиям на странице, и это будет проще простого:

 

<html>
<head>
<script>
function clean() {
var element = document.getElementById('text');

if (element.value == 'Введите текст') {
element.value = '';
element.style.color = 'black';
element.style.fontSize = 'normal';
element.style.fontStyle = 'normal';
}
}

function fill() {
var element = document.getElementById('text');

if (element.value == '') {
element.value = 'Введите текст';
element.style.color = 'grey';
element.style.fontSize = 'small';
element.style.fontStyle = 'italic';
}
}
</script>
</head>
<body onLoad="javascript: fill();">
<input id="text" value="" type="text" style="width: 200px; height: 20px;" onFocus="javascript: clean();" onBlur="javascript: fill();" />
</body>
</html>

 

Видите, как все стало намного проще. При загрузке страницы загружается текст, а при нажатии на текстовое поле он исчезает. А как реализуется вывод текста описано в блоке нашего скрипта.

Теперь наша задача состоит в том, чтобы сократить наш код. Во-первых, мы можем воспользоваться this вместо document.getElementById. Но помните, что this создается в момент события, но не в самом обработчике-функции, поэтому this нужно передать внутрь функции. Посмотрите, как это нужно делать и возьмите себе на заметку:

 

<html>
<head>
<script>
function clean(element) {
if (element.value == 'Введите текст') {
element.value = '';
element.style.color = 'black';
element.style.fontSize = 'normal';
element.style.fontStyle = 'normal';
}
}

function fill(element) {
if (element.value == '') {
element.value = 'Введите текст';
element.style.color = 'grey';
element.style.fontSize = 'small';
element.style.fontStyle = 'italic';
}
}
</script>
</head>
<body onLoad="javascript: fill(document.getElementById('text'));">
<input id="text" value="" type="text" style="width: 200px; height: 20px;" onFocus="javascript: clean(this);" onBlur="javascript: fill(this);" />
</body>
</html>

 

Единственное, что нужно сказать, это то, что в событии onLoad нельзя писать this, потому что this будет ссылкой на body, а нам нужно передать элемент text, который мы сможем получить при помощи document.getElementById.

 

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

К тому же текст типа 'Введите текст' повторяется два раза и если его придется изменить не целесообразно его менять в двух местах. Лучше всего создать переменную и пользоваться значением этой переменной везде. Помните, что использовать глобальную переменную внутри функции мы можем, если не создать внутри этой функции при помощи var другую переменную. Давайте сделаем все эти изменения:

 

<html>
<head>
<script>
var enterText = 'Введите текст...';


function changeStyle(element, value, color, fontSize, fontStyle) {
element.value = value;
element.style.color = color;
element.style.fontSize = fontSize;
element.style.fontStyle = fontStyle;
}

function clean(element) {
if (element.value == enterText)
changeStyle('', 'black', 'normal', 'normal');
}

function fill(element) {
if (element.value == '')
changeStyle(enterText, 'grey', 'small', 'italic');
}
</script>
</head>
<body onLoad="javascript: fill(document.getElementById('text'));">
<input id="text" value="" type="text" style="width: 200px; height: 20px;" onFocus="javascript: clean(this);" onBlur="javascript: fill(this);" />
</body>
</html>

 

Не на много стал код меньше, но зато намного понятнее, если конечно вы в совершенстве разобрались, зачем нам нужны функции. Если же вы этого не сделали, то самое время вам это начать.

 

 

4. Еще один пример использования функций и событий

 

В прошлом уроке мы написали классную функцию, которая прячет элемент и показывает его, если он уже спрятан, вот она:

 

function toggle(elementid) {
var el = document.getElementById(elementid);
if (el) {
if (el.style.display!= 'none') {
el.style.display = 'none';
}
else {
el.style.display = '';
}
}
}

 

Как вы думаете можно ли эту функцию привязать к какому-либо событию? Конечно можно. К примеру, можно заставить что-то исчезать, нажав на кнопку и появляться, нажав на ту же самую кнопку. Давайте сделаем панель, которая будет появляться, когда мы будем нажимать на кнопку. Мы сразу напишем пример и не будем его разбирать по кускам, вам нужно будет просто разобрать HTML код. А куда будет привязана данная функция и как она работает это уже должно быть понятно каждому.

 

<html>
<head>
<style>
html, body {
margin: 0px;
padding: 0px;
}
#panelcontainer {
position: absolute;
z-index: 2;
width: 100%;
}
#button {
height: 40px;
line-height: 40px;
text-align: center;
background: #eee;
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
}
#button span {
background: #ddd;
padding: 2px 5px;
border: 1px solid #aaa;
cursor: pointer;
}
#panel {
background: #f7f7f7;
padding: 20px;
display: block;
}
#maincontainer {
position: absolute;
z-index: 1;
width: 100%;
top: 42px;
}
</style>
<script>
function toggle(elementid) {
var el = document.getElementById(elementid);
if (el) {
if (el.style.display!= 'none') {
el.style.display = 'none';
}
else {
el.style.display = '';
}
}
}
</script>
</head>
<body onLoad="javascript: toggle('panel');">
<div id="panelcontainer">
<div id="panel">

В этой панели вы можете разместить все, что захотите.<br>И она будет поверх всего содержимого.

</div>
<div id="button">

<span onClick="javascript: toggle('panel');">Всплывающая панель</span>

</div>
</div>
<div id="maincontainer">
Здесь разместите свой сайт.

</div>
</body>
</html>

 

Самое главное – это красиво оформить страницу при помощи CSS, а эффект JS не так уж и много занимает места. И как заметили это эффект работает не так уж и сложно.

 

При помощи этой функции так же можно сделать и всплывающее меню. Точно так же как и в предыдущем случае, нужно красиво это меню оформить, а прицепить код выполнения – это проще простого: заставить появляться меню, когда мы наводим на пункт меню, и исчезать, когда мы от него теряем фокус.

Давайте мы попробуем реализовать меню в виде списков:

 

<html>
<head>
<style>
html, body {
margin: 0px;
padding: 0px;
}
#menu {
clear: both;
}
#firstlevel, #firstlevel li {
position: relative;
display: block;
float: left;
height: 40px;
line-height: 40px;
margin: 0px;
padding: 0px;
text-align: center;
}
#firstlevel li a {
display: block;
margin: 0px 20px;
}
#secondlevel {
position: absolute;
top: 40px;
display: block;
margin: 0px;
padding: 0px;
}
#secondlevel li {
position: relative;
clear: both;
display: block;
float: left;
height: 30px;
line-height: 30px;
margin: 0px;
padding: 0px;
overflow: hidden;
background: #fff;
width: auto;
}
#main {
clear: both;
}
</style>
<script>
function toggle(elementid) {
var el = document.getElementById(elementid);
if (el) {
if (el.style.display!= 'none') {
el.style.display = 'none';
}
else {
el.style.display = '';
}
}
}
</script>
</head>
<body onLoad="javascript: toggle('secondlevel');">
<div id="maincontainer">
<div id="menu">
<ul id="firstlevel">
<li>
<a href="#">Первый пункт меню</a>
</li>
<li onmouseover="javascript: toggle('secondlevel');" onmouseout="javascript: toggle('secondlevel');" >
<a href="#">Второй пункт меню</a>
<ul id="secondlevel">
<li>
<a href="#">Вложеный&nbsp;первый&nbsp;пункт&nbsp;меню</a>
</li>
<li>
<a href="#">Вложеный&nbsp;второй&nbsp;пункт&nbsp;меню</a>
</li>
<li>
<a href="#">Вложеный&nbsp;третий&nbsp;пункт&nbsp;меню</a>
</li>
</ul>
</li>
<li>
<a href="#">Третий пункт меню</a>
</li>
</ul>
</div>
<pre id="main">
Текст
</pre>
</div>
</body>
</html>


Видите, и опять как всегда все дело в стилях CSS, а само меню просто либо исчезает, либо появляется при помощи нашей магической функции toggle. Забавно. Так же вы можете самостоятельно сделать третий уровень меню и т.д. Кстати, если появиться еще одно выдвижное меню ему нужно давать новый идентификатор, потому что, во-первых, не может на странице присутствовать несколько идентификаторов, а во-вторых, если бы даже это было допустимо, то эти две меню одновременно скрывались и появлялись. А если вы укажете два идентификатора одинаковых, то функция document.getElementById будет находить только первый элемент с этим именем.

 

Если вы еще до сих пор не умеете управляться с CSS стилями, то самое время научиться это делать, а то кроме написания бесполезного кода вы ничего не добьетесь.

 

 

5. События и его свойства (Event)

 

В момент возникновения любого события иногда нужно прослеживать некоторые вещи, к примеру, кто вызвал это событие, в каком месте была нажата клавиша мыши, какая клавиша клавиатуры была нажата и т.д. За этим следит некий объект, который создается в момент возникновения события. Этот объект имеет имя Event. Внутри этого объекта есть несколько переменных, которые хранятся внутри объекта и чтобы обратиться к ним, нужно написать Event, затем точку, а потом написать имя переменной, которая хранит информацию о событии. Такие записи мы уже встречали, например, через точку мы обращались к свойствам стилей элемента.

 

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

Код скрипта:

 

<layer>
<a href="#" onClick="alert('x: ' + event.x + ' y: ' + event.y); return false;">
<img src="davinci.jpg" width=209 height=264 border=0>
</a>
</layer>

 

Как видите, в тэг <a> мы поместили программу обработки событий onClick, как это мы уже делали в предшествующих версиях JavaScript. Новое здесь заключается в том, что для создания окошка с сообщением мы используем event.x и event.y. А это как раз и есть объект Event, который здесь нам нужен, чтобы узнать координаты мыши.

К тому же мы поместили все команды в тэг <layer>. Благодаря этому мы получаем в сообщении координаты относительно данного слоя, т.е. в нашем случае относительно самого изображения. В противном же случае мы получили бы координаты относительно окна браузера. (инструкция return false; используется здесь для того, чтобы браузер не обрабатывал далее данную ссылку)

 

Объект Event получил следующие свойства (их мы рассмотрим в следующих примерах), кстати, не все свойства одинаково отображаются во всех браузерах, поэтому в таблице собраны свойства для двух типов браузеров:

 

 

Описание/Свойство IE Остальные
Целевой объект srcElement target
Тип события type type
Горизонтальное положение курсора внутри элемента offsetX offsetX, но не во всех работает
Вертикальное положение курсора внутри элемента offsetY offsetY, но не во всех работает
Горизонтальное положение курсора (в пикселах) относительно слоя. x x / layerX
Вертикальное положение курсора (в пикселах) относительно слоя. y y / layerY
Горизонтальное положение курсора (в пикселах) относительно окна браузера - pageX
Вертикальное положение курсора (в пикселах) относительно окна браузера - pageY
Горизонтальное положение курсора относительно верхнего левого угла клиентской области страницы clientX clientX
Вертикальное положение курсора относительно верхнего левого угла клиентской области страницы clientY clientY
Горизонтальное положение курсора (в пикселах) относительно экрана screenX screenX
Вертикальное положение курсора (в пикселах) относительно экрана screenY screenY
Определяет, какие кнопки мыши были нажаты в момент возникновения события
  • 0 - нет нажатых кнопок
  • 1 - левая кнопка
  • 2 - правая кнопка
  • 3 - левая и правая кнопки
  • 4 - средняя кнопка
  • 5 - левая и средняя кнопки
  • 6 - правая и средняя кнопки
  • 7 - все три кнопки
button button
Код нажатой на клавиатуре клавиши в Unicode keyCode keyCode
Признак состояния кнопки Shift в момент возникновения события: true - нажата, false - свободна shiftKey shiftKey
Признак состояния кнопки Alt в момент возникновения события: true - нажата, false - свободна altKey altKey
Признак состояния кнопки Ctrl в момент возникновения события: true - нажата, false - свободна ctrlKey ctrlKey
Предыдущий элемент fromElement relatedTarget
Следующий элемент toElement relatedTarget
устанавливает признак "всплывания" события
  • true - всплывание события не происходит
  • false - (по умолчанию) событие всплывает
cancelBubble cancelBubble
Позволяет установить возвращаемое обработчиком события значение.
  • true - (по умолчанию) стандартный обработчик будет вызван
  • false - стандартный обработчик не вызывается
returnValue returnValue

 

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

 

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

 

 

5.1. Передача объекта Event внутрь обработчика события

 

Объект действительно создается в момент возникновения события и его нужно передавать внутрь обработчика так же, как и ссылку this, но вся проблема в том, что в IE все работает не так. В IE объект создается внутри обработчика и имеет имя window.event, но с этим легко бороться. Давайте рассмотрим это наследующем примере, заодно и проверим некоторые свойства объекта Event:

 

 

<html>
<head>
<script>
function mouseShowHandler(e){
//В один момент времени может существовать или переданный объект e или window.event
//В конечном итоге переменная e будет равна одному из них
e = e || window.event
//Также можно использовать следующую запись
//e = window.event? window.event: e;
//Первая проще

//Записываем координаты мыши
document.getElementById('mouse').innerHTML = e.clientX + "px " + e.clientY + "px";
}
</script>
<style>
body {
margin: 0px;
paddig: 0px;
height: 100%;
width: 100%;
}
</style>
</head>
<body onmousemove="mouseShowHandler(event);">
<div style="position: absolute; right: 0px; bottom: 0px;" id="mouse"></div>
</body>
</html>

 

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

 

Давайте кратко рассмотрим некоторые свойства объекта Event.

 

 

5.2. Всплывание события cancelBubble

 

"Всплыванием" события (bubble) называют процесс передачи события от дочернего элемента к родительскому после его обработки. В пример можно поставить ссылку на сайте – если вы на нее нажмете, то должно сработать событие onClick для ссылки и событие onClick для всех элементов, которые находятся под этой ссылкой, даже для элемента body. То есть, после того, как некоторый элемент обработает событие, оно будет передано на обработку родительскому элементу. Таким образом, событие как бы поднимается по дереву элементов вверх – всплывает. Рассмотрим этот процесс на примере:

 

<html>
<head>
<style type="text/css">
#center {
height: 200px;
}
div {
border: 1px solid black;
margin: 100px;
}
</style>
<script type="text/javascript">
function clickHandler (elem) {
elem.style.backgroundColor="darkgreen";
alert ("Нажмите 'Ок' для продолжения");
}
</script>
</head>
<body onclick="clickHandler(this)">
<div onclick="clickHandler(this)">
<div id="center" onclick="clickHandler(this)"></div>
</div>
</body>
</html>

 

 

Как следует из кода примера, на странице три элемента (<body> и два элемента <div>) обрабатывают событие одного и того же типа – onclick. При этом для его обработки они используют одну функцию – clickHandler(elem), которая меняет фоновый цвет переданного ей элемента на зеленый и выдает сообщение методом alert(). Элемент, который требуется перекрасить, передается функции обработки посредством внутреннего указателя this. Таким образом, при вызове функции clickHandler(this) для некоторого элемента, this будет указывать на сам элемент.

Чтобы увидеть процесс всплывания события щелкните мышью на внутреннем прямоугольнике страницы. После щелчка он окрасится в зеленый цвет и будет выдано сообщение "Нажмите 'Ок' для продолжения". Процесс повторится для внешнего прямоугольника, а, затем, и для всей страницы. Если же щелкнуть сразу на внешнем прямоугольнике, то вы увидите уже два сообщения, а центральный прямоугольник останется неизмененным.

В ряде случаев всплывание события дает нежелательный эффект и его требуется запретить. Для этого необходимо присвоить значение true свойству cancelBubble объекта event:

 

event.cancelBubble = true;

 

Перепишем пример с использованием свойства cancelBubble:

 

<html>
<head>
<style type="text/css">
#center {
height: 200px;
}
div {
border: 1px solid black;
margin: 100px;
}
</style>
<script type="text/javascript">
function clickHandler (e, elem) {
elem.style.backgroundColor = "darkgreen";
alert ("Нажмите 'Ок' для продолжения");

e = e || window.event
e.cancelBubble = true;
}
</script>
</head>
<body onclick="clickHandler(event, this)">
<div onclick="clickHandler(event, this)">
<div id="center" onclick="clickHandler(event, this)"></div>
</div>
</body>
</html>

 

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

 

Это свойство редко когда может пригодиться, но необходимо знать, что оно есть.

 

 

5.3. Вызов стандартного обработчика

 

Существует ряд элементов в HTML, для которых определены некоторые обработчики событий по умолчанию или стандартные обработчики. Так для элемента <a> (гиперссылка) определен обработчик onСlick выполняющий переход на ресурс, заданный атрибутом href. Если вы желаете, чтобы после вашей обработки некоторого события стандартный обработчик не вызывался, присвойте значение false свойству returnValue объекта event.

 

<html>
<head>
<script type="text/javascript">
function clickHandler () {
alert ("Пользовательский обработчик!");
}
</script>
</head>
<body>
<a class="btn" href="http://www.google.com/" onclick="clickHandler(); event.returnValue = false;">Это гиперссылка</a>
</body>
</html>

 

Помните, что то же самое мы могли сделать и при помощи return false. Зачем же нам эта конструкция?

Все дело в том, что return false не работает внутри функции-обработчика, и отменить действия стандартного обработчика внутри функции мы не сможем простым return false.

 

Давайте рассмотрим следующий пример:

 

<html>
<head>
<script type="text/javascript">
function clickHandler (e, elem) {
e = e || window.event
e.returnValue = confirm('Переход на страницу ' + elem.innerText + '.\nПродолжить?')
}
</script>
</head>
<body>
<a class="btn" href="http://www.google.com" onclick="clickHandler (event, this);">
http://www.google.com
</a>
</body>
</html>

 

Разберем пример по порядку. На странице расположена гиперссылка на web-узел Google. При щелчке на гиперссылке будет вызван обработчик события click – clickHandler, в который мы передаем объект Event и указатель на текущий элемент. Внутри обработчика вызывается функция confirm, в зависимости от кнопки, нажатой пользователем в диалоговом окне, будет возвращено значение true или false, которое будет присвоено переменной e.returnValue. Эта переменная отвечает за работу стандартного обработчика. Соответственно, если пользователь нажмет отмену, то по ссылке мы не перейдем. Таким образом, переход по гиперссылке осуществляется только в том случае, если пользователь согласится с переходом.

В принципе то же самое мы можем сделать и при помощи return false, но этот вариант будет предпочтительнее, потому что всю оюработку мы ведем в функции-обработчике.

5.4. Практика работы с мышью: перетаскивание элементов

 

Как любой уважающий себя web разработчик, вы, наверняка стремитесь сделать свои страницы приятными для пользователей. Это означает, что, наряду с приятным оформлением, ваша страница должна обладать еще и дружественным к пользователю интерфейсом. Последним "писком" в этой области является технология перетаскивания объектов мышью – Drag and Drop.

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

 

Предупреждение:

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

 

Для начала зададимся вопросом, какие события мы будем обрабатывать для перетаскиваемого элемента? Во-первых, элемент нужно "схватить" мышью – то есть, нажать на нем левую кнопку мыши. Значит, событие "mousedown" необходимо отрабатывать. Так же дело обстоит и с "отпусканием" элемента. К списку обрабатываемых событий добавляем "mouseup", в тот момент, когда мы его отпускаем. Осталось событие перемещения курсора мыши – "mousemove", при котором мы будем менять позицию перетаскиваемого элемента.

Итак, с событиями мы решили. Теперь разберемся с самими элементами. Дело в том, что задавать координаты элементов (left и top) можно только для абсолютно позиционируемых (в нашем случае) элементов. Значит – в стилевое оформление перетаскиваемых элементов должна входить строка "position: absolute;".

Ниже приводится полный код примера. Обратите внимание на следующую особенность: события mousedown и mouseup обрабатываются для перетаскиваемого элемента, а событие "mousemove" – для элемента <body>. Это связано с тем, что при резком рывке курсора мы рискуем выскочить за пределы перетаскиваемого элемента и "уронить" его. Т.е. нам нужен элемент, который всегда будет следить за движением мыши, т.е. самый большой элемент – body.

 

 

<html>
<head>
<style type="text/css">
#square {
width: 50px;
height: 50px;
position: absolute;
left: 10px;
top: 10px;
border: 1px solid black;
background: #DDD;
}
</style>
<script type="text/javascript">
//Переменная отвечает за то, что захвачен элемен или нет
//Соответственно хранит захваченный элемент
var elementToDrag = null;

//"захват" элемента мышью
function captureElement (elem) {
if (!elementToDrag) {
elementToDrag = elem;
}
}
//"отпускание" элемента
function releaseElement () {
elementToDrag = null;
}
//"перетаскивание" элемента
function dragElement (e) {
if (elementToDrag){
e = e || window.event
elementToDrag.style.left = e.clientX;
elementToDrag.style.top = e.clientY;
}
}
</script>
</head>
<body onmousemove="dragElement(event)">
<div id="square"
onmousedown="captureElement(this)"
onmouseup="releaseElement()">
</div>
</body>
</html>

 

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

 

Исправим этот недостаток. Для этого будем при "захвате" элемента запоминать смещение курсора относительно верхнего левого угла перетаскиваемого элемента в глобальных переменных. Информация о смещении курсора хранится в свойствах offsetX и offsetY объекта event для IE и некоторых других браузерах, но для FF те же данные хранятся в свойствах layerX и layerY, которые не работают в IE. Соответственно для смещения по оси X мы используем свойство или offsetX или layerX, если они есть следующей записью: offX = e.layerX || e.offsetX, аналогично и для оси Y.

Смотрим пример:

 

<html>
<head>
<style type="text/css">
#square {
width: 50px;
height: 50px;
position: absolute;
left: 10px;
top: 10px;
border: 1px solid black;
background: #DDD;
}
</style>
<script type="text/javascript">
//Переменная отвечает за то, что захвачен элемен или нет
//Соответственно хранит захваченный элемент
var elementToDrag = null;

//Глобальные переменные для хранения смещения
var offX, offY;

//"захват" элемента мышью
function captureElement (e, elem) {
if (!elementToDrag) {
elementToDrag = elem;
e = e || window.event;
offX = e.layerX || e.offsetX; // запоминаем координаты курсора
offY = e.layerY || e.offsetY; // в момент щелчка
}
}
//"отпускание" элемента
function releaseElement () {
elementToDrag = null;
}
//"перетаскивание" элемента
function dragElement (e) {
if (elementToDrag){
e = e || window.event;
elementToDrag.style.left = e.clientX - offX;
elementToDrag.style.top = e.clientY - offY;
}
}
</script>
</head>
<body onmousemove="dragElement(event)">
<div id="square"
onmousedown="captureElement(event, this)"
onmouseup="releaseElement()">
</div>
</body>
</html>

 

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

 

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


6. Функции (нюансы)

 

Итак, события мы рассмотрели полностью, но в функциях существует множество нюансов, поэтому следующая тема будет посвящена именно им.

 

6.1. Знакомство с рекурсией.

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

Как правило, неопытный программист, узнав про рекурсию, испытывает легкое недоумение. Первая мысль – это бессмысленно!!! Такой ряд вызовов превратиться в вечный цикл, похожий на змею, которая съела сама себя, или приведет к ошибке на этапе выполнения, когда программа поглотит все ресурсы памяти.

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

 

Пример на рекурсию

Исторически сложилось так, что в качестве первого примера на рекурсию почти всегда приводят пример вычисления факториала. Мы уже это делали при помощи циклов.

Что ж, не будем нарушать традиций.

Для начала, вспомним, что такое факториал. Обозначается факториал восклицательным знаком «!» и вычисляется следующим образом:

 

N! = 1 * 2 * 3 * … * N

 

Другими словами, факториал представляет собой произведение натуральных чисел от 1 до N включительно. Исходя из вышеописанной формулы, можно обратить внимание наследующую закономерность:

 

N! = N * (N-1)!

 

Ура!!! Мы можем найти факториал через сам факториал!

Видите, что, реализуя факториал, внутри него уже есть вызов функции факториала – это и есть рекурсия.

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

 

1! = 1

 

Теперь мы можем себе позволить вычислить значение факториала любого числа. Попробуем, например, получить 5!, несколько раз применив формулу N! = N * (N-1)! и один раз формулу 1! = 1:

 

5! = 5 * 4! = 5 * 4 * 3! = 5 * 4 * 3 * 2! = 5 * 4 * 3 * 2 * 1! = 5 * 4 * 3 * 2 * 1

 

Давайте, попробуем реализовать рекурсивную функцию, как раз посмотрите, что это:

 

<html>
<head>
<script type="text/javascript">
function fact (n) {
if (n <= 1) return 1;
else return n * fact(n-1);
}
alert(fact(5));
</script>
</head>
</html>

 

Как видите, в момент вызова функции в нее передается значение числа, от которого нужно вычислить факториал. Внутри функции возвращается следующее значение: само число, умноженное на факториал числа меньшего на единицу, что само собой влечет за собой вычисления факториала числа меньшего на единицу. Так будет продолжаться, пока мы не доберемся до единицы, и факториал единицы вернет единицу. Сама же функция вычислит правильное значение факториала.

 

Рекурсии или итерации?

Изучив предыдущий раздел урока – вы наверняка задались вопросом: а зачем нужна рекурсия? Ведь, реализовать вычисление факториала можно и с помощью итераций и это совсем не сложно.

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

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

Значит ли это, что рекурсия бесполезна? Ни в коем случае!!! Существует ряд задач, для которых рекурсивное решение тонко и красиво, а итеративное – сложно, громоздко и неестественно. Ваша задача, в данном случае – научиться, не только оперировать рекурсией и итерацией, но и интуитивно выбирать, какой из подходов применять в конкретном случае. От себя можем сказать, что лучшее применение рекурсии – это решение задач, для которых свойственна следующая черта: решение задачи сводится к решению таких же задач, но меньшей размерности и, следовательно, гораздо легче разрешаемых.

Но если вы не поняли рекурсию – не страшно – всему свое время, ведь рекурсия в JS применяется крайне редко.

 

 

6.2. Функция – это переменная. Несколько видов объявлений функций.

 

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

 

<html>
<head>
<script type="text/javascript">
function f () {
alert('Это функция!');
}

var newf = f;
newf();
</script>
</head>
</html>

 

Видите, что newf стала тоже функцией. Самое интересное, что после объявления функция возвращает свое значение, и мы можем записать тоже самое следующим образом:

 

<html>
<head>
<script type="text/javascript">
var newf= function f () {
alert('Это функция!');
}
newf();
</script>
</head>
</html>

 

Самое интересное, что в данном случае можно и не задавать имя нашей функции и все будет работать:

 

<html>
<head>
<script type="text/javascript">
var newf= function () {
alert('Это функция!');
}
newf();
</script>
</head>
</html>

 

Т.е. с самого начала конструкция function () создает функцию без названия, а затем мы ее присваиваем в переменную newf. Это сделано для того, чтобы мы программно могли присваивать обработчики для событий, не создавая самой функции, вернее не задавая ей имя. В общем это нам пригодиться, но рассмотрим эти свойства немного позже.

 

6.3. Функция внутри функции

 

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

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

 

<html>
<head>
<script type="text/javascript">
function first () {
function second () {
alert('Функция вызвана');
}

second();
}

first();
if (typeof second!= "undefined") second();
else alert('Функция second недоступна');
</script>
</head>
</html>

 

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

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

 

6.4. Условная функция

Точно так же, можно создавать функции внутри условных операторов. Думаю следующий пример не нужно комментировать:

 

<html>
<head>
<script type="text/javascript">
var what = prompt("Какую функцию вы хотите объявить?\n1. Первую.\n2. Вторую.", 1);
what = parseInt(what);

var func;
if (what == 1) {
func = function () {
alert('Первая функция');
}
}
else {
func = function () {
alert('Вторая функция');
}
}

func();
</script>
</head>
</html>

 

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


7. Самостоятельное задание:

 

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

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


Приложение. Шпаргалка (события JavaScript)

 

В JavaScript определен ряд событий, связанных с элементами документа. Обработчики дают возможность организовать реакцию на возникновение событий из сценария. При этом соответствующий обработчик указывается как атрибут элемента HTML-документа; значением этого атрибута является выражение JavaScript. Например:

 

<div onmouseOver="this.style.bgColor='#CCCCCC'" onmouseOut="this.style.bgColor='

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...