Дан список сообщений. Добавьте каждому сообщению кнопку для его удаления.
Используйте делегирование событий. Один обработчик для всего.
В результате, при нажатии на крестик, сообщение удаляется(скрывается).
Изображение кнопки:
Исходный код http://learn.javascript.ru/play/tutorial/browser/events/messages-delegate-src/index.html или:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<style>
body {
margin: 10px auto;
width: 470px;
}
h3 {
margin: 0;
padding-bottom: .3em;
padding-right: 20px;
font-size: 1.1em;
}
p {
margin: 0;
padding: 0 0 .5em;
}
.pane {
background: #edf5e1;
padding: 10px 20px 10px;
border-top: solid 2px #c4df9b;
position: relative;
}
.remove-button {
position: absolute;
top: 10px;
right: 10px;
cursor: pointer;
display: block;
background: url(delete.gif) no-repeat;
width: 16px;
height: 16px;
}
</style>
</head>
<body>
<div id="messages-container">
<div class="pane">
<h3>Лошадь</h3>
<p>Домашняя лошадь — животное семейства непарнокопытных, одомашненный и единственный сохранившийся подвид дикой лошади, вымершей в дикой природе, за исключением небольшой популяции лошади Пржевальского.</p>
<span class="remove-button"></span>
</div>
<div class="pane">
<h3>Осёл</h3>
<p>Домашний осёл или ишак — одомашненный подвид дикого осла, сыгравший важную историческую роль в развитии хозяйства и культуры человека. Все одомашненные ослы относятся к африканским ослам.</p>
<span class="remove-button"></span>
</div>
<div class="pane">
<h3>Корова, а также пара слов о диком быке, о волах и о тёлках. </h3>
<p>Коро́ва — самка домашнего быка, одомашненного подвида дикого быка, парнокопытного жвачного животного семейства полорогих. Самцы вида называются быками, молодняк — телятами, кастрированные самцы — волами. Молодых (до первой стельности) самок называют тёлками.</p>
<span class="remove-button"></span>
</div>
</div>
<script>
/* ваш код */
</script>
</body>
</html>
Шаг 1:
Поставьте обработчик click
на контейнере. Он должен проверять, произошел ли клик на кнопке удаления (target
), и если да, то удалять соответствующий ей DIV.
Шаг 2:
document.getElementById('messages-container').onclick = function(e) {
e = e || window.event;
var target = e.target || e.srcElement;
// без цикла, т.к. мы точно знаем, что внутри нет тегов
if (target.className != 'remove-button') return;
target.parentNode.style.display = 'none';
}
Свой вариант:
document.querySelector('#messages-container').addEventListener('click', function(e){
var event = e || window.event;
var target = event.target || event.srcElement;
if (target.className != 'remove-button') return;
target.parentNode.style.display = 'none';
}, false);
Создайте дерево, которое по клику на заголовок скрывает-показывает детей:
Исходный документ: http://learn.javascript.ru/play/tutorial/browser/events/tree-src/index.html или
<!DOCTYPE HTML>
<html>
<head><meta charset="utf-8"></head>
<body>
<ul class="tree">
<li>Животные
<ul>
<li>Млекопитающие
<ul>
<li>Коровы</li>
<li>Ослы</li>
<li>Собаки</li>
<li>Тигры</li>
</ul>
</li>
<li>Другие
<ul>
<li>Змеи</li>
<li>Птицы</li>
<li>Ящерицы</li>
</ul>
</li>
</ul>
</li>
<li>Рыбы
<ul>
<li>Аквариумные
<ul>
<li>Гуппи</li>
<li>Скалярии</li>
</ul>
</li>
<li>Морские
<ul>
<li>Морская форель</li>
</ul>
</li>
</ul>
</li>
</ul>
</body>
</html>
Требования:
Дерево устроено как вложенный список.
Клики на все элементы можно поймать, повесив единый обработчик onclick
на внешний UL
.
Как поймать клик на заголовке? Элемент LI
является блочным, поэтому нельзя понять, был ли клик на тексте, или справа от него.
Проблема в верстке, в том что LI
занимает всю ширину. Можно кликнуть справа от текста, это все еще LI
.
Один из способов это поправить — обернуть заголовки в дополнительный элемент SPAN
, и обрабатывать только клики внутри SPAN
'ов.
Мы могли бы это сделать в HTML, но давайте для примера используем JavaScript. Следующий код ищет все LI
и оборачивает текстовые узлы в SPAN
.
var treeUl = document.getElementsByTagName('ul')[0];
var treeLis = treeUl.getElementsByTagName('li');
for(var i=0; i<treeLis.length; i++) {
var li = treeLis[i];
var span = document.createElement('span');
li.insertBefore(span, li.firstChild); // добавить пустой SPAN
span.appendChild(span.nextSibling); // переместить в него заголовок
}
Теперь можно отслеживать клики на заголовках.
При проверке так выглядит дерево с обёрнутыми в SPAN
заголовками и делегированием:
<style>
span { border: 1px solid red; }
</style>
<ul onclick="alert((event.target||event.srcElement).tagName)">
<li><span>Млекопетающие</span>
<ul>
<li><span>Коровы</span></li>
<li><span>Ослы</span></li>
<li><span>Собаки</span></li>
<li><span>Тигры</span></li>
</ul>
</li>
</ul>
Так как SPAN
инлайновый элемент, он всегда такого же размера как текст.
В реальной жизни дерево должно быть сразу со SPAN
, чтобы не нужно было исправлять структуру. Если HTML-код дерева генерируется на сервере, то это несложно. Если дерево генерируется в JavaScript – тем более просто.
Получение узла по SPAN
Для делегирования нужно по клику понять, на каком узле он произошел.
В нашем случае у SPAN нет детей-элементов, поэтому не нужно подниматься вверх по цепочке родителей. Достаточно просто проверить event.target.tagName == 'SPAN'
, чтобы понять, где был клик, и спрятать потомков.
var tree = document.getElementsByTagName('ul')[0];
tree.onclick = function(e) {
e = e || event;
var target = e.target || e.srcElement;
if (target.tagName != 'SPAN') {
return; // клик был не на заголовке
}
var li = target.parentNode; // получить родительский LI
// получить UL с потомками -- это первый UL внутри LI
var node = li.getElementsByTagName('ul')[0];
if (!node) return; // потомков нет -- ничего не надо делать
// спрятать/показать (можно и через CSS-класс)
node.style.display = node.style.display ? '' : 'none';
}
Жирные узлы при наведении
Узел выделяется при наведении при помощи CSS-селектора :hover
.
Невыделяемость при клике
На всё дерево можно поставить обработчик, отменяющий выделение при клике
tree.onselectstart = tree.onmousedown = function() {
return false; // делаем узлы невыделяемыми
}
Полное решение вы можете увидеть здесь http://learn.javascript.ru/play/tutorial/browser/events/tree/index.html или:
<!DOCTYPE HTML>
<html>
<head>
<style>
* html body {
behavior:url("csshover.htc"); /* IE6: http://www.xs4all.nl/~peterned/csshover.html */
}
.tree span:hover {
font-weight: bold;
}
.tree span {
cursor: pointer;
}
</style>
<meta charset="utf-8">
</head>
<body>
<ul class="tree">
<li>Животные
<ul>
<li>Млекопитающие
<ul>
<li>Коровы</li>
<li>Ослы</li>
<li>Собаки</li>
<li>Тигры</li>
</ul>
</li>
<li>Другие
<ul>
<li>Змеи</li>
<li>Птицы</li>
<li>Ящерицы</li>
</ul>
</li>
</ul>
</li>
<li>Рыбы
<ul>
<li>Аквариумные
<ul>
<li>Гуппи</li>
<li>Скалярии</li>
</ul>
</li>
<li>Морские
<ul>
<li>Морская форель</li>
</ul>
</li>
</ul>
</li>
</ul>
<script>
var tree = document.getElementsByTagName('ul')[0];
var treeLis = tree.getElementsByTagName('li');
/* wrap all textNodes into spans */
for(var i=0; i<treeLis.length; i++) {
var li = treeLis[i];
var span = document.createElement('span');
li.insertBefore(span, li.firstChild);
span.appendChild(span.nextSibling);
}
/* catch clicks on whole tree */
tree.onclick = function(evt) {
evt = evt || window.event;
var target = evt.target || evt.srcElement;
if (target.tagName != 'SPAN') {
return;
}
/* now we know SPAN is clicked */
var node = target.parentNode.getElementsByTagName('ul')[0];
if (!node) return; // no children
node.style.display = node.style.display ? '' : 'none';
}
tree.onselectstart = tree.onmousedown = function() {
return false; // делаем узлы невыделяемыми
}
</script>
</body>
</html>
Создайте галерею изображений, в которой основное изображение изменяется при клике на уменьшенный вариант.
Результат должен выглядеть так:
Для обработки событий используйте делегирование, т.е. не более одного обработчика.
Исходный документ: http://learn.javascript.ru/play/tutorial/browser/events/gallery-src/index.html или:
<!DOCTYPE HTML>
<html>
<head>
<title>Галерея</title>
<meta charset="utf-8">
body {
margin: 0;
padding: 0;
font: 75%/120% Arial, Helvetica, sans-serif;
}
h2 {
font: bold 190%/100% Arial, Helvetica, sans-serif;
margin: 0 0 .2em;
}
h2 em {
font: normal 80%/100% Arial, Helvetica, sans-serif;
color: #999999;
}
#largeImg {
border: solid 1px #ccc;
width: 550px;
height: 400px;
padding: 5px;
}
#thumbs a {
border: solid 1px #ccc;
width: 100px;
height: 100px;
padding: 3px;
margin: 2px;
float: left;
}
#thumbs a:hover {
border-color: #FF9900;
}
</head>
<body>
<p><img id="largeImg" src="img1-lg.jpg" alt="Large image"></p>
<div id="thumbs">
<!-- При наведении на изображение показывается встроенная подсказка браузера (title) -->
<a href="img2-lg.jpg" title="Image 2"><img src="img2-thumb.jpg"></a>
<a href="img3-lg.jpg" title="Image 3"><img src="img3-thumb.jpg"></a>
<a href="img4-lg.jpg" title="Image 4"><img src="img4-thumb.jpg"></a>
<a href="img5-lg.jpg" title="Image 5"><img src="img5-thumb.jpg"></a>
<a href="img6-lg.jpg" title="Image 6"><img src="img6-thumb.jpg"></a>
</div>
</body>
</html>
P.S. Обратите внимание — клик может быть как на маленьком изображении IMG
, так и на A
вне него. При этом event.target
будет, соответственно, либо IMG
, либо A
.
Дополнительно:
Решение состоит в том, чтобы добавить обработчик на контейнер #thumbs
и отслеживать клики на ссылках.
Когда происходит событие, обработчик должен изменять src
#largeImg
на href
ссылки и заменять alt
на ее title
.
Код решения:
var largeImg = document.getElementById('largeImg');
document.getElementById('thumbs').onclick = function(e) { e = e || window.event; var target = e.target || e.srcElement;
while(target != this) {
if (target.nodeName == 'A') {
showThumbnail(target.href, target.title);
return false;
}
target = target.parentNode;
}
}
function showThumbnail(href, title) { largeImg.src = href; largeImg.alt = title; }
Рабочий пример http://learn.javascript.ru/play/tutorial/browser/events/gallery/index.html или:
<!DOCTYPE HTML>
<html>
<head>
<title>Галерея</title>
<meta charset="utf-8">
<style>
body {
margin: 0;
padding: 0;
font: 75%/120% Arial, Helvetica, sans-serif;
}
h2 {
font: bold 190%/100% Arial, Helvetica, sans-serif;
margin: 0 0 .2em;
}
h2 em {
font: normal 80%/100% Arial, Helvetica, sans-serif;
color: #999999;
}
#largeImg {
border: solid 1px #ccc;
width: 550px;
height: 400px;
padding: 5px;
}
#thumbs a {
border: solid 1px #ccc;
width: 100px;
height: 100px;
padding: 3px;
margin: 2px;
float: left;
}
#thumbs a:hover {
border-color: #FF9900;
}
#thumbs li {
list-style: none;
}
#thumbs {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<p><img id="largeImg" src="img1-lg.jpg" alt="Large image"></p>
<ul id="thumbs">
<!-- При наведении на изображение показывается встроенная подсказка браузера (title) -->
<li><a href="img2-lg.jpg" title="Image 2"><img src="img2-thumb.jpg"></a></li>
<li><a href="img3-lg.jpg" title="Image 3"><img src="img3-thumb.jpg"></a></li>
<li><a href="img4-lg.jpg" title="Image 4"><img src="img4-thumb.jpg"></a></li>
<li><a href="img5-lg.jpg" title="Image 5"><img src="img5-thumb.jpg"></a></li>
<li><a href="img6-lg.jpg" title="Image 6"><img src="img6-thumb.jpg"></a></li>
</ul>
<script>
var largeImg = document.getElementById('largeImg');
var thumbs = document.getElementById('thumbs');
thumbs.onclick = function(e) {
e = e || window.event;
var target = e.target || e.srcElement;
while(target != this) {
if (target.nodeName == 'A') {
showThumbnail(target.href, target.title);
return false;
}
target = target.parentNode;
}
}
function showThumbnail(href, title) {
largeImg.src = href;
largeImg.alt = title;
}
/* предзагрузка */
var imgs = thumbs.getElementsByTagName('img');
for(var i=0; i<imgs.length; i++) {
var url = imgs[i].parentNode.href;
var img = document.createElement('img');
img.src = url;
}
</script>
</body>
</html>
Предзагрузка картинок
Для того, чтобы картинка загрузилась, достаточно создать новый элемент IMG
и указать ему src
, вот так:
var imgs = thumbs.getElementsByTagName('img');
for(var i = 0; i < imgs.length; i++) {
var url = imgs[i].parentNode.href;
var img = document.createElement('img');
img.src = url;
}
Как только элемент создан и ему назначен src
, браузер сам начинает скачивать файл картинки.
При правильных настройках сервера как-то использовать этот элемент не обязательно — картинка уже закеширована.
Семантичная верстка
Для списка картинок используется DIV
. С точки зрения семантики более верный вариант — список UL/LI
.