renovations
This commit is contained in:
parent
a5e8c1219f
commit
41f07253d3
21 changed files with 536 additions and 126 deletions
|
@ -128,15 +128,16 @@ alert( +"2" > +"14" ); // false, теперь правильно
|
||||||
|
|
||||||
## Сравнение разных типов
|
## Сравнение разных типов
|
||||||
|
|
||||||
При сравнении значения преобразуются к числам. Исключение: когда оба значения -- строки, тогда не преобразуются.
|
При сравнении значений разных типов, используется числовое преобразование. Оно применяется к обоим значениям.
|
||||||
|
|
||||||
Например:
|
Например:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
//+ run
|
//+ run
|
||||||
alert( '2' > 1 ); // true
|
alert( '2' > 1 ); // true, сравнивается как 2 > 1
|
||||||
alert( '01' == 1 ); //true
|
alert( '01' == 1 ); // true, сравнивается как 1 == 1
|
||||||
alert( false == 0 ); // true, false становится 0, а true 1.
|
alert( false == 0 ); // true, false становится числом 0
|
||||||
|
alert( true == 1); // true, так как true становится числом 1.
|
||||||
```
|
```
|
||||||
|
|
||||||
Тема преобразований типов будет продолжена далее, в главе [](/types-conversion).
|
Тема преобразований типов будет продолжена далее, в главе [](/types-conversion).
|
||||||
|
@ -177,12 +178,14 @@ alert(0 === false); // false, т.к. типы различны
|
||||||
|
|
||||||
Проблемы со специальными значениями возможны, когда к переменной применяется операция сравнения `> < <= >=`, а у неё может быть как численное значение, так и `null/undefined`.
|
Проблемы со специальными значениями возможны, когда к переменной применяется операция сравнения `> < <= >=`, а у неё может быть как численное значение, так и `null/undefined`.
|
||||||
|
|
||||||
**Интуитивно кажется, что `null/undefined` эквивалентны нулю, но это не так! Они ведут себя по-другому.**
|
**Интуитивно кажется, что `null/undefined` эквивалентны нулю, но это не так.**
|
||||||
|
|
||||||
|
Они ведут себя по-другому.
|
||||||
|
|
||||||
<ol>
|
<ol>
|
||||||
<li>**Значения `null` и `undefined` равны `==` друг другу и не равны чему бы то ни было ещё.**
|
<li>Значения `null` и `undefined` равны `==` друг другу и не равны чему бы то ни было ещё.
|
||||||
Это жёсткое правило буквально прописано в спецификации языка.</li>
|
Это жёсткое правило буквально прописано в спецификации языка.</li>
|
||||||
<li>**При преобразовании в число `null` становится `0`, а `undefined` становится `NaN`.**</li>
|
<li>При преобразовании в число `null` становится `0`, а `undefined` становится `NaN`.</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
Посмотрим забавные следствия.
|
Посмотрим забавные следствия.
|
||||||
|
@ -240,4 +243,6 @@ alert(undefined == 0); // false (3)
|
||||||
<li>Строки сравниваются побуквенно.</li>
|
<li>Строки сравниваются побуквенно.</li>
|
||||||
<li>Значения разных типов приводятся к числу при сравнении, за исключением строгого равенства `===` (`!==`).</li>
|
<li>Значения разных типов приводятся к числу при сравнении, за исключением строгого равенства `===` (`!==`).</li>
|
||||||
<li>Значения `null` и `undefined` равны `==` друг другу и не равны ничему другому. В других сравнениях (с участием `>`,`<`) их лучше не использовать, так как они ведут себя не как `0`.</li>
|
<li>Значения `null` и `undefined` равны `==` друг другу и не равны ничему другому. В других сравнениях (с участием `>`,`<`) их лучше не использовать, так как они ведут себя не как `0`.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
Мы ещё вернёмся к теме сравнения позже, когда лучше изучим различные типы данных в JavaScript.
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip {
|
.tooltip {
|
||||||
position:absolute;
|
position: fixed;
|
||||||
z-index:100; /* подсказка должна перекрывать другие элементы */
|
z-index:100; /* подсказка должна перекрывать другие элементы */
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
|
|
||||||
|
@ -66,8 +66,7 @@
|
||||||
var showingTooltip;
|
var showingTooltip;
|
||||||
|
|
||||||
document.onmouseover = function(e) {
|
document.onmouseover = function(e) {
|
||||||
e = e || event;
|
var target = e.target;
|
||||||
var target = e.target || e.srcElement;
|
|
||||||
|
|
||||||
// ВАЖНО: mouseover может сработать сразу на потомке
|
// ВАЖНО: mouseover может сработать сразу на потомке
|
||||||
// минуя родителя (при быстром движении мышью)
|
// минуя родителя (при быстром движении мышью)
|
||||||
|
@ -105,16 +104,14 @@ function showTooltip(text, elem) {
|
||||||
tooltipElem.innerHTML = text;
|
tooltipElem.innerHTML = text;
|
||||||
document.body.appendChild(tooltipElem);
|
document.body.appendChild(tooltipElem);
|
||||||
|
|
||||||
var coords = getCoords(elem);
|
var coords = elem.getBoundingClientRect();
|
||||||
|
|
||||||
// не вылезаем за пределы экрана
|
var left = coords.left + (elem.offsetWidth - tooltipElem.offsetWidth)/2;
|
||||||
var scroll = getPageScroll();
|
if (left < 0) left = 0; // не вылезать за левую границу экрана
|
||||||
|
|
||||||
var left = coords.left + (elem.offsetWidth - tooltipElem.offsetWidth)/2^0;
|
|
||||||
if (left < scroll.left) left = scroll.left; // не вылезать за левую границу экрана
|
|
||||||
|
|
||||||
|
// не вылезать за верхнюю границу окна
|
||||||
var top = coords.top - tooltipElem.offsetHeight - 5;
|
var top = coords.top - tooltipElem.offsetHeight - 5;
|
||||||
if (top < scroll.top) {
|
if (top < 0) {
|
||||||
top = coords.top + elem.offsetHeight + 5;
|
top = coords.top + elem.offsetHeight + 5;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,50 +46,5 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
|
||||||
|
|
||||||
|
|
||||||
// --------- вспомогательные функции ---------
|
|
||||||
|
|
||||||
function getCoords(elem) {
|
|
||||||
var box = elem.getBoundingClientRect();
|
|
||||||
|
|
||||||
var body = document.body;
|
|
||||||
var docEl = document.documentElement;
|
|
||||||
|
|
||||||
var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
|
|
||||||
var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;
|
|
||||||
|
|
||||||
var clientTop = docEl.clientTop || body.clientTop || 0;
|
|
||||||
var clientLeft = docEl.clientLeft || body.clientLeft || 0;
|
|
||||||
|
|
||||||
var top = box.top + scrollTop - clientTop;
|
|
||||||
var left = box.left + scrollLeft - clientLeft;
|
|
||||||
|
|
||||||
return { top: Math.round(top), left: Math.round(left) };
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPageScroll() {
|
|
||||||
if (window.pageXOffset != undefined) {
|
|
||||||
return {
|
|
||||||
left: pageXOffset,
|
|
||||||
top: pageYOffset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var html = document.documentElement;
|
|
||||||
var body = document.body;
|
|
||||||
|
|
||||||
var top = html.scrollTop || body && body.scrollTop || 0;
|
|
||||||
top -= html.clientTop;
|
|
||||||
|
|
||||||
var left = html.scrollLeft || body && body.scrollLeft || 0;
|
|
||||||
left -= html.clientLeft;
|
|
||||||
|
|
||||||
return { top: top, left: left };
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -1,6 +1,6 @@
|
||||||
# Поведение "вложенная подсказка"
|
# Поведение "вложенная подсказка"
|
||||||
|
|
||||||
[importance 4]
|
[importance 5]
|
||||||
|
|
||||||
Напишите JS-код, который будет показывать всплывающую подсказку над элементом, если у него есть атрибут `data-tooltip`.
|
Напишите JS-код, который будет показывать всплывающую подсказку над элементом, если у него есть атрибут `data-tooltip`.
|
||||||
|
|
||||||
|
@ -20,7 +20,6 @@
|
||||||
|
|
||||||
[iframe src="solution" height=300 border=1]
|
[iframe src="solution" height=300 border=1]
|
||||||
|
|
||||||
Исходный документ содержит вспомогательные функции [](#getPageScroll) и [](#getCoords).
|
Вы можете использовать как заготовку решение задачи [](/task/behavior-tooltip).
|
||||||
Вы также можете использовать как заготовку решение задачи [](/task/behavior-tooltip).
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
Самый простой способ решения этой задачи -- замерять скорость движения курсора. То есть, при `mousemove` вычислять расстояние между текущими координатами и предыдущими, а затем делить на разницу во времени.
|
|
||||||
|
|
||||||
Когда скорость будет очень маленькой, например 5 пикселей за 100 миллисекунд -- можно считать, что курсор остановился (некоторое дрожание может присутствовать) и обработать этот факт.
|
|
||||||
|
|
||||||
Обработчик `mousemove` может стоять на всём документе, либо на контейнере, который включает в себя интересующие нас элементы.
|
|
||||||
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
# Как отследить прекращение движения курсора?
|
|
||||||
|
|
||||||
[importance 5]
|
|
||||||
|
|
||||||
Представим ситуацию -- посетитель быстро проводит мышью над элементами и останавливается на интересном ему.
|
|
||||||
|
|
||||||
Нам надо запустить код (например открыть пункт меню) для того, на котором он остановился, а те элементы, над которыми он быстро провёл мышь, но на которых не остановился -- игнорировать, даже если события мыши на них произошли.
|
|
||||||
|
|
||||||
Как бы вы решали такую задачу?
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
Будем замерять скорость движения курсора.
|
||||||
|
|
||||||
|
Для этого можно запустить `setInterval`, который каждые 100мс (или другой интервал) будет сравнивать текущие координаты курсора с предыдущими и, если расстояние пройдено маленькое, считаем, что посетитель "навёл указатель на элемент", вызвать `options.over`.
|
||||||
|
|
||||||
|
В браузере нет способа "просто получить" текущие координаты. Это может сделать обработчик события, в данном случае `mousemove`. Поэтому нужно будет поставить обработчик на `mousemove` и при каждом движении запоминать текущие координаты, чтобы `setInterval` мог раз в 100мс сравнивать их.
|
||||||
|
|
||||||
|
Можно обойтись и без `setInterval` -- сравнивать координаты при каждом срабатывании `mousemove`. Если передвинулись на маленькое расстояние с последнего `mousemove` -- это "наведение на элемент", а на большое -- игнорируем. Вариант с `setInterval` теоретически надёжнее, но на практике и один `mousemove` работает.
|
||||||
|
|
||||||
|
Чтобы наш код не срабатывал чересчур часто, мы будем начинать анализ координат при заходе на элемент, а заканчивать -- при выходе с него.
|
||||||
|
|
||||||
|
Если выход осуществлён, и при этом на элементе зафиксировано "состояние наведения", то нужно вызвать соответствующий обработчик `options.out`.
|
||||||
|
|
||||||
|
Чтобы точно отловить момент входа и выхода, без учёта подэлементов (во избежание мигания), можно использовать `mouseenter/mouseleave`.
|
||||||
|
|
||||||
|
В решении, предложенном ниже, однако, используется `mouseover/mouseout`, так как это позволит легко "прикрутить" к такому объекту делегирование, если потребуется. А, чтобы не было лишних срабатываний, лишние переходы отфильтровываются.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
|
||||||
|
function HoverIntent(options) {
|
||||||
|
|
||||||
|
options = Object.create(options); // not to modify the object
|
||||||
|
options.interval = options.interval || 100;
|
||||||
|
|
||||||
|
// скорость меньше 1px/ms считается остановкой над элементом
|
||||||
|
options.sensitivity = options.sensitivity || 0.1;
|
||||||
|
var elem = options.elem;
|
||||||
|
|
||||||
|
// instantiate variables
|
||||||
|
// cX, cY = current X and Y position of mouse, updated by mousemove event
|
||||||
|
// pX, pY = previous X and Y position of mouse, set by mouseover and polling interval
|
||||||
|
var cX, cY, pX, pY, cTime, pTime;
|
||||||
|
var checkSpeedInterval;
|
||||||
|
var isOverElement;
|
||||||
|
var isHover;
|
||||||
|
|
||||||
|
// A private function for handling mouse 'hovering'
|
||||||
|
elem.addEventListener("mouseover", function(event) {
|
||||||
|
|
||||||
|
if (isOverElement) {
|
||||||
|
// если мы и так над элементом, то это всплывший переход внутри него
|
||||||
|
// мы и так уже замеряем скорость, поэтому этот переход лишний
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isOverElement = true;
|
||||||
|
|
||||||
|
// при каждом движении мыши mousemove мы будем вычислять расстояние между
|
||||||
|
// предыдущими и текущими координатами курсора
|
||||||
|
// если оно меньше sensivity, то скорость маленькая и это наведение на элемент
|
||||||
|
// pX, pY - "предыдущие" координаты
|
||||||
|
pX = event.pageX;
|
||||||
|
pY = event.pageY;
|
||||||
|
pTime = Date.now();
|
||||||
|
|
||||||
|
elem.addEventListener('mousemove', onMouseMove);
|
||||||
|
});
|
||||||
|
|
||||||
|
elem.addEventListener("mouseout", function(event) {
|
||||||
|
// если ушли вовне элемента
|
||||||
|
if (event.relatedTarget && !elem.contains(event.relatedTarget)) {
|
||||||
|
isOverElement = false;
|
||||||
|
elem.removeEventListener('mousemove', onMouseMove);
|
||||||
|
if (isHover) {
|
||||||
|
// если была остановка над элементом
|
||||||
|
options.out.call(elem, event);
|
||||||
|
isHover = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function onMouseMove(event) {
|
||||||
|
cX = event.pageX;
|
||||||
|
cY = event.pageY;
|
||||||
|
cTime = Date.now();
|
||||||
|
|
||||||
|
if (pTime == cTime) return; // когда mousemove вместе с mouseover
|
||||||
|
|
||||||
|
var speed = Math.sqrt(Math.pow(pX - cX, 2) + Math.pow(pY - cY, 2)) / (cTime - pTime);
|
||||||
|
|
||||||
|
if (speed < options.sensitivity) {
|
||||||
|
// если с предыдущей позиции меньше sensivity дистанция, то "остановка на элементе"
|
||||||
|
elem.removeEventListener("mousemove", onMouseMove);
|
||||||
|
isHover = true;
|
||||||
|
options.over.call(elem, event);
|
||||||
|
} else {
|
||||||
|
// следующее измерение с текущей точки
|
||||||
|
pX = cX;
|
||||||
|
pY = cY;
|
||||||
|
pTime = cTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Document</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<script src="hoverIntent.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="elem" class="clock">
|
||||||
|
<span class="hours">12</span>
|
||||||
|
:
|
||||||
|
<span class="minutes">30</span>
|
||||||
|
:
|
||||||
|
<span class="seconds">00</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
var tooltip = document.createElement('div');
|
||||||
|
tooltip.className = "tooltip";
|
||||||
|
tooltip.innerHTML = "Подсказка";
|
||||||
|
|
||||||
|
new HoverIntent({
|
||||||
|
elem: elem,
|
||||||
|
over: function() {
|
||||||
|
tooltip.style.left = this.getBoundingClientRect().left + 'px';
|
||||||
|
tooltip.style.top = this.getBoundingClientRect().bottom + 5 + 'px';
|
||||||
|
document.body.appendChild(tooltip);
|
||||||
|
},
|
||||||
|
out: function() {
|
||||||
|
document.body.removeChild(tooltip);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,26 @@
|
||||||
|
.hours {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.minutes {
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.seconds {
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clock {
|
||||||
|
border: 1px dashed black;
|
||||||
|
padding: 5px;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 30px;
|
||||||
|
background: yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip {
|
||||||
|
position: absolute;
|
||||||
|
background: #eee;
|
||||||
|
border: 1px brown solid;
|
||||||
|
padding: 3px;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
function HoverIntent(options) {
|
||||||
|
/* ваш код */
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Document</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<script src="hoverIntent.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="elem" class="clock">
|
||||||
|
<span class="hours">12</span>
|
||||||
|
:
|
||||||
|
<span class="minutes">30</span>
|
||||||
|
:
|
||||||
|
<span class="seconds">00</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
var tooltip = document.createElement('div');
|
||||||
|
tooltip.className = "tooltip";
|
||||||
|
tooltip.innerHTML = "Подсказка";
|
||||||
|
|
||||||
|
new HoverIntent({
|
||||||
|
elem: elem,
|
||||||
|
over: function() {
|
||||||
|
tooltip.style.left = this.getBoundingClientRect().left + 'px';
|
||||||
|
tooltip.style.top = this.getBoundingClientRect().bottom + 5 + 'px';
|
||||||
|
document.body.appendChild(tooltip);
|
||||||
|
},
|
||||||
|
out: function() {
|
||||||
|
document.body.removeChild(tooltip);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,26 @@
|
||||||
|
.hours {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.minutes {
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.seconds {
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clock {
|
||||||
|
border: 1px dashed black;
|
||||||
|
padding: 5px;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 30px;
|
||||||
|
background: yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip {
|
||||||
|
position: absolute;
|
||||||
|
background: #eee;
|
||||||
|
border: 1px brown solid;
|
||||||
|
padding: 3px;
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
# Подсказка при замедлении над элементом
|
||||||
|
|
||||||
|
[importance 5]
|
||||||
|
|
||||||
|
Нужно написать функцию, которая показывает подсказку при *наведении* на элемент, но не при *быстром проходе* над ним.
|
||||||
|
|
||||||
|
То есть, если посетитель именно навёл курсор мыши на элемент и почти остановился -- подсказку показать, а если быстро провёл над ним, то не надо (зачем излишнее мигание?).
|
||||||
|
|
||||||
|
Технически -- можно измерять скорость движения мыши над элементом, если она маленькая, то считаем, что это "наведение на элемент" (показать подсказку), если большая -- "быстрый проход мимо элемента" (не показывать).
|
||||||
|
|
||||||
|
Задача -- сделать универсальный код, который отслеживает "наведение на элемент".
|
||||||
|
|
||||||
|
Пусть это будет объект `new HoverIntent(options)`, который при создании принимает `options`:
|
||||||
|
<ul>
|
||||||
|
<li>`elem` -- элемент, наведение на который нужно отслеживать.</li>
|
||||||
|
<li>`over` -- функция-обработчик наведения на элемент.</li>
|
||||||
|
<li>`out` -- функция-обработчик ухода с элемента (если было наведение).</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
Пример использования такого объекта для подсказки:
|
||||||
|
```js
|
||||||
|
function HoverIntent(options) {
|
||||||
|
//... ваш код ...
|
||||||
|
}
|
||||||
|
|
||||||
|
// образец подсказки
|
||||||
|
var tooltip = document.createElement('div');
|
||||||
|
tooltip.className = "tooltip";
|
||||||
|
tooltip.innerHTML = "Подсказка";
|
||||||
|
|
||||||
|
// при "наведении на элемент" показать подсказку
|
||||||
|
new HoverIntent({
|
||||||
|
elem: elem,
|
||||||
|
over: function() {
|
||||||
|
tooltip.style.left = this.getBoundingClientRect().left + 'px';
|
||||||
|
tooltip.style.top = this.getBoundingClientRect().bottom + 5 + 'px';
|
||||||
|
document.body.appendChild(tooltip);
|
||||||
|
},
|
||||||
|
out: function() {
|
||||||
|
document.body.removeChild(tooltip);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Демо:
|
||||||
|
|
||||||
|
[iframe src="solution" height=110]
|
||||||
|
|
||||||
|
Если провести мышкой над "часиками" быстро, то ничего не будет, а если медленно или остановиться на них, то появится подсказка.
|
||||||
|
|
||||||
|
Обратите внимание -- подсказка не "мигает"" при проходе мыши внутри "часиков", по подэлементам.
|
||||||
|
|
||||||
|
|
|
@ -1,36 +1,65 @@
|
||||||
# Мышь: движение mouseover/out, mouseenter/leave
|
# Мышь: движение mouseover/out, mouseenter/leave
|
||||||
|
|
||||||
В этой главе мы рассмотрим события, возникающие при движении мыши над элементами.
|
В этой главе мы рассмотрим события, возникающие при движении мыши над элементами.
|
||||||
|
|
||||||
[cut]
|
[cut]
|
||||||
|
|
||||||
## События mouseover/mouseout, свойство relatedTarget
|
## События mouseover/mouseout, свойство relatedTarget
|
||||||
|
|
||||||
Событие `mouseover` происходит, когда мышь появляется над элементом, а `mouseout` -- когда уходит из него.
|
Событие `mouseover` происходит, когда мышь появляется над элементом, а `mouseout` -- когда уходит из него.
|
||||||
|
|
||||||
При этом мы можем узнать, с какого элемента пришла (или на какой ушла) мышь, используя дополнительное свойство `relatedTarget`.
|
<img src="mouseover-mouseout.svg">
|
||||||
|
|
||||||
В случае `mouseover` оно содержит элемент, *с которого* пришла мышь, а для `mouseout` -- *на который* ушла.
|
При этом мы можем узнать, с какого элемента пришла (или на какой ушла) мышь, используя дополнительное свойство объекта события `relatedTarget`.
|
||||||
|
|
||||||
|
Например, в обработчике события `mouseover`:
|
||||||
|
<ul>
|
||||||
|
<li>`event.target` -- элемент, на который пришла мышь, то есть на котором возникло событие.</li>
|
||||||
|
<li>`event.relatedTarget` -- элемент, с которого пришла мышь.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
Для `mouseout` всё наоборот:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>`event.target` -- элемент, с которого ушла мышь, то есть на котором возникло событие.</li>
|
||||||
|
<li>`event.relatedTarget` -- элемент, на который перешла мышь.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
[online]
|
||||||
В примере ниже вы можете наглядно посмотреть события `mouseover/out`, возникающие на всех элементах.
|
В примере ниже вы можете наглядно посмотреть события `mouseover/out`, возникающие на всех элементах.
|
||||||
|
|
||||||
[codetabs src="mouseoverout" height=220]
|
[codetabs src="mouseoverout" height=220]
|
||||||
|
[/online]
|
||||||
|
|
||||||
Можно заметить, что в некоторых случаях значение `relatedTarget` может быть `null`. Это вполне нормально и означает, что мышь пришла из-за пределов окна (или ушла за окно).
|
[warn header="`relatedTarget` может быть `null`"]
|
||||||
|
Свойство `relatedTarget` может быть равно `null`.
|
||||||
|
|
||||||
## Частота событий mousemove и mouseover/out
|
Это вполне нормально и означает, что мышь пришла не с другого элемента, а из-за пределов окна (или ушла за окно). Мы обязательно должны иметь в виду такую возможность, когда пишем код, который обращается к свойствам `event.relatedTarget`.
|
||||||
|
[/warn]
|
||||||
|
|
||||||
|
## Частота событий
|
||||||
|
|
||||||
Событие `mousemove` срабатывает при передвижении мыши. Но это не значит, что каждый пиксель экрана порождает отдельное событие!
|
Событие `mousemove` срабатывает при передвижении мыши. Но это не значит, что каждый пиксель экрана порождает отдельное событие!
|
||||||
|
|
||||||
События `mousemove` и `mouseover/mouseout` срабатывают так часто, насколько это позволяет внутренняя система взаимодействия с мышью браузера.
|
События `mousemove` и `mouseover/mouseout` срабатывают так часто, насколько это позволяет внутренняя система взаимодействия с мышью браузера.
|
||||||
|
|
||||||
Это означает, что если вы двигаете мышью очень быстро, то DOM-элементы, через которые мышь проходит на большой скорости, могут быть пропущены.
|
Это означает, что если посетитель двигает мышью быстро, то DOM-элементы, через которые мышь проходит на большой скорости, могут быть пропущены.
|
||||||
|
|
||||||
К примеру:
|
<img src="mouseover-mouseout-over-elems.svg">
|
||||||
<ul>
|
|
||||||
<li>Курсор может быстро перейти *над* родительским элементом в дочерний, при этом *не вызвав событий на родителе*, как будто он через родителя никогда не проходил.</li>
|
|
||||||
<li>Курсор может быстро выйти из дочернего элемента без генерации событий на родителе.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
При быстром движении с элемента `#FROM` до элемента `#TO`, как изображено на картинке выше -- промежуточные `<DIV>` будут пропущены. Сработает только событие `mouseout` на `#FROM` и `mouseover` на `#TO`.
|
||||||
|
|
||||||
|
На практике это полезно, потому что таких промежуточных элементов может быть много, и если обрабатывать заход и уход с каждого -- дополнительные вычислительные затраты.
|
||||||
|
|
||||||
|
С другой стороны, мы должны это понимать и не рассчитывать на то, что мышь аккуратно пройдёт с одного элемента на другой и так далее. Нет, она "прыгает".
|
||||||
|
|
||||||
|
В частности, возможна ситуация, когда курсор прыгает в середину страницы, и при этом `relatedTarget=null`, то есть он пришёл "ниоткуда" (на самом деле извне окна):
|
||||||
|
|
||||||
|
<img src="mouseover-mouseout-from-outside.svg">
|
||||||
|
|
||||||
|
Обратим внимание ещё на такую деталь. При быстром движении курсор окажется над `#TO` сразу, даже если этот элемент глубоко в DOM. Его родители при движении сквозь них события не поймают.
|
||||||
|
|
||||||
|
[online]
|
||||||
Попробуйте увидеть это "вживую" на тестовом стенде ниже.
|
Попробуйте увидеть это "вживую" на тестовом стенде ниже.
|
||||||
|
|
||||||
Его HTML представляет собой два вложенных `div'а`.
|
Его HTML представляет собой два вложенных `div'а`.
|
||||||
|
@ -40,22 +69,44 @@
|
||||||
А еще попробуйте зайти курсором мыши на красный `div` и потом быстро вывести мышь из него куда-нибудь сквозь зеленый. Если движение мыши достаточно быстрое, то родительский элемент будет проигнорирован.
|
А еще попробуйте зайти курсором мыши на красный `div` и потом быстро вывести мышь из него куда-нибудь сквозь зеленый. Если движение мыши достаточно быстрое, то родительский элемент будет проигнорирован.
|
||||||
|
|
||||||
[codetabs height=360 src="mouseoverout-fast"]
|
[codetabs height=360 src="mouseoverout-fast"]
|
||||||
|
[/online]
|
||||||
|
|
||||||
|
Важно иметь в виду эту особенность событий, чтобы не написать код, который рассчитан на последовательный проход над элементами. В остальном это вполне удобно.
|
||||||
|
|
||||||
Важно иметь в виду эту особенность событий, чтобы не написать код, который рассчитан на последовательный проход над элементами.
|
|
||||||
## "Лишний" mouseout при уходе на потомка
|
## "Лишний" mouseout при уходе на потомка
|
||||||
|
|
||||||
Представьте ситуацию -- курсор зашёл на элемент. Сработал `mouseover` на нём. Потом курсор идёт на дочерний... И, оказывается, на элементе-родителе при этом происходит `mouseout`! Как будто курсор с него ушёл, хотя он всего лишь перешёл на потомка.
|
Представьте ситуацию -- курсор зашёл на элемент. Сработал `mouseover` на нём. Потом курсор идёт на дочерний... И, оказывается, на элементе-родителе при этом происходит `mouseout`! Как будто курсор с него ушёл, хотя он всего лишь перешёл на потомка.
|
||||||
|
|
||||||
**При переходе на потомка срабатывает `mouseout` на родителе.**
|
**При переходе на потомка срабатывает `mouseout` на родителе.**
|
||||||
|
|
||||||
|
<img src="mouseover-to-child.svg">
|
||||||
|
|
||||||
Это кажется странным, но легко объяснимо.
|
Это кажется странным, но легко объяснимо.
|
||||||
|
|
||||||
**Согласно браузерной логике, курсор мыши может быть только над *одним* элементом -- самым глубоким в DOM (и верхним по z-index).**
|
**Согласно браузерной логике, курсор мыши может быть только над *одним* элементом -- самым глубоким в DOM (и верхним по z-index).**
|
||||||
|
|
||||||
Так что если он перешел куда-нибудь, то автоматически ушёл с предыдущего элемента. Всё просто.
|
Так что если он перешел куда-нибудь, то автоматически ушёл с предыдущего элемента. Всё просто.
|
||||||
|
|
||||||
К чему это приводит на практике, можно увидеть в примере ниже. В нём красный `div` вложен в синий. На синем стоит обработчик, который записывает его `mouseover/mouseout`.
|
Самое забавное начинается чуть позже.
|
||||||
|
|
||||||
|
Ведь события `mouseover` и `mouseout` всплывают.
|
||||||
|
|
||||||
|
Получается, что если поставить обработчики `mouseover` и `mouseout` на `#FROM` и `#TO`, то последовательность срабатывания при переходе `#FROM` -> `#TO` будет следующей:
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>`mouseout` на `#FROM` (с `event.target=#FROM`, `event.relatedTarget=#TO`).</li>
|
||||||
|
<li>`mouseover` на `#TO` (с `event.target=#TO`, `event.relatedTarget=#FROM`).</li>
|
||||||
|
<li>Событие `mouseover` после срабатывания на `#TO` всплывает выше, запуская обработчики `mouseover` на родителях. Ближайший родитель -- как раз `#FROM`, то есть сработает обработчик `mouseover` на нём, с теми же значениями `target/relatedTarget`.</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
Если посмотреть на `1)` и `3)`, то видно, что то видно, что на `#FROM` сработает сначала `mouseout`, а затем с `#TO` всплывёт `mouseover`.
|
||||||
|
|
||||||
|
Если по `mouseover` мы что-то показываем, а по `mouseout` -- скрываем, то может получается "мигание".
|
||||||
|
|
||||||
|
**У обработчиков создаётся впечатление, что курсор ушёл `mouseout` с родителя, а затем тут же перешёл `mouseover` на него (за счёт всплытия `mouseover` с потомка).**
|
||||||
|
|
||||||
|
[online]
|
||||||
|
Это можно увидеть в примере ниже. В нём красный `div` вложен в синий. На синем стоит обработчик, который записывает его `mouseover/mouseout`.
|
||||||
|
|
||||||
Зайдите на синий элемент, а потом переведите мышь на красный -- и наблюдайте за событиями:
|
Зайдите на синий элемент, а потом переведите мышь на красный -- и наблюдайте за событиями:
|
||||||
|
|
||||||
|
@ -68,12 +119,9 @@
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
На самом деле, обратного перехода нет. Событие `mouseover` сработало на потомке (видно по `target: red`), а затем всплыло.
|
На самом деле, обратного перехода нет. Событие `mouseover` сработало на потомке (видно по `target: red`), а затем всплыло.
|
||||||
|
[/online]
|
||||||
|
|
||||||
**То есть, у кода создаётся впечатление, что курсор ушёл `mouseout` с родителя, а затем тут же перешёл `mouseover` на него (за счёт всплытия `mouseover` с потомка).**
|
Если действия при наведении и уходе курсора с родителя простые, например скрытие/показ подсказки, то можно вообще ничего не заметить. Ведь события происходят сразу одно за другим, подсказка будет скрыта по `mouseout` и тут же показана по `mouseover`.
|
||||||
|
|
||||||
Как это влияет на его поведение?
|
|
||||||
|
|
||||||
Если действия при наведении и уходе курсора с родителя простые, например скрытие/показ подсказки, то можно вообще ничего не заметить. Ведь события происходят одновременно, подсказка будет скрыта по `mouseout` и тут же показана по `mouseover`.
|
|
||||||
|
|
||||||
Если же происходит что-то более сложное, то бывает важно отследить момент "настоящего" ухода, то есть понять, когда элемент зашёл на родителя, а когда ушёл -- без учёта переходов по дочерним элементам.
|
Если же происходит что-то более сложное, то бывает важно отследить момент "настоящего" ухода, то есть понять, когда элемент зашёл на родителя, а когда ушёл -- без учёта переходов по дочерним элементам.
|
||||||
|
|
||||||
|
@ -84,39 +132,34 @@
|
||||||
События `mouseenter/mouseleave` похожи на `mouseover/mouseout`. Они тоже срабатывают, когда курсор заходит на элемент и уходит с него, но с двумя отличиями.
|
События `mouseenter/mouseleave` похожи на `mouseover/mouseout`. Они тоже срабатывают, когда курсор заходит на элемент и уходит с него, но с двумя отличиями.
|
||||||
|
|
||||||
<ol>
|
<ol>
|
||||||
<li>При переходе на потомка курсор не уходит с родителя.</li>
|
<li>Не учитываются переходы внутри элемента.</li>
|
||||||
<li>События `mouseenter/mouseleave` не всплывают.</li>
|
<li>События `mouseenter/mouseleave` не всплывают.</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
Эти события более интуитивно понятны. Курсор заходит на элемент -- срабатывает `mouseenter`, а затем -- неважно, куда он внутри него переходит, `mouseleave` будет, когда курсор окажется за пределами элемента.
|
Эти события более интуитивно понятны.
|
||||||
|
|
||||||
|
Курсор заходит на элемент -- срабатывает `mouseenter`, а затем -- неважно, куда он внутри него переходит, `mouseleave` будет, когда курсор окажется за пределами элемента.
|
||||||
|
|
||||||
|
[online]
|
||||||
|
|
||||||
Вы можете увидеть, как они работают проведя курсором над голубым `DIV'ом` ниже. Обработчик стоит только на внешнем, синем элементе. Обратите внимание -- лишних событий при переходе на красного потомка нет!
|
Вы можете увидеть, как они работают проведя курсором над голубым `DIV'ом` ниже. Обработчик стоит только на внешнем, синем элементе. Обратите внимание -- лишних событий при переходе на красного потомка нет!
|
||||||
|
|
||||||
[codetabs height=340 src="mouseleave"]
|
[codetabs height=340 src="mouseleave"]
|
||||||
|
[/online]
|
||||||
|
|
||||||
## Делегирование -- проблема mouseenter/leave
|
## Делегирование
|
||||||
|
|
||||||
События `mouseenter/leave` более наглядны и понятны, но они не всплывают, а значит с ними нельзя использовать делегирование.
|
События `mouseenter/leave` более наглядны и понятны, но они не всплывают, а значит с ними нельзя использовать делегирование.
|
||||||
|
|
||||||
Представьте себе, что нам нужно обработать вход/выход мыши для ячеек таблицы. А в таблице таких ячеек тысяча.
|
Представим, что нам нужно обработать вход/выход мыши для ячеек таблицы. А в таблице таких ячеек тысяча.
|
||||||
|
|
||||||
Естественное решение -- поставить обработчик на верхний элемент `<table>` и ловить все события в нём. Но события `mouseenter/leave` не всплывают, а срабатывают именно на том элементе, на котором стоит обработчик и только на нём.
|
Естественное решение -- поставить обработчик на верхний элемент `<table>` и ловить все события в нём. Но события `mouseenter/leave` не всплывают, они срабатывают именно на том элементе, на котором стоит обработчик и только на нём.
|
||||||
|
|
||||||
Это легко видеть в примере ниже: обработчики `mouseenter/leave` стоят на `<table>` и сработают при входе-выходе из таблицы, получить из них какую-то информацию о переходах по её ячейкам не представляется возможным:
|
Если обработчики `mouseenter/leave` стоят на `<table>`, то они сработают при входе-выходе из таблицы, но получить из них какую-то информацию о переходах по её ячейкам невозможно.
|
||||||
|
|
||||||
[codetabs height=480 src="mouseleave-table"]
|
|
||||||
|
|
||||||
Не беда -- воспользуемся `mouseover/mouseout`.
|
Не беда -- воспользуемся `mouseover/mouseout`.
|
||||||
|
|
||||||
Но мы хотели бы, чтобы наши действия выполнялись только при входе-выходе в ячейку, без учета переходов внутри самих ячеек.
|
Простейший вариант обработчиков выглядит так:
|
||||||
|
|
||||||
Если нужно делегирование -- нужно использовать `mouseover/out`.
|
|
||||||
|
|
||||||
Получится так:
|
|
||||||
|
|
||||||
[codetabs height=450 src="mouseenter-mouseleave-delegation"]
|
|
||||||
|
|
||||||
В этом примере код обработчиков выглядит так:
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
table.onmouseover = function(event) {
|
table.onmouseover = function(event) {
|
||||||
|
@ -129,20 +172,33 @@ table.onmouseout = function(event) {
|
||||||
target.style.background = '';
|
target.style.background = '';
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
[online]
|
||||||
|
|
||||||
Пока что они срабатывают на всём подряд. Их нужно фильтровать:
|
[codetabs height=450 src="mouseenter-mouseleave-delegation"]
|
||||||
|
|
||||||
|
[/online]
|
||||||
|
|
||||||
|
В таком виде они срабатывают при переходе с любого элемента на любой. Нас же интересуют переходы строго с одной ячейки `<td>` на другую.
|
||||||
|
|
||||||
|
Нужно фильтровать события.
|
||||||
|
|
||||||
|
Один из вариантов:
|
||||||
<ul>
|
<ul>
|
||||||
<li>Вход-выход срабатывает на любых элементах, а нам нужны именно ячейки таблицы.
|
<li>Запоминать текущий подсвеченный `<td>` в переменной.</li>
|
||||||
|
<li>При `mouseover` проверять, остались ли мы внутри того же `<td>`, если да -- игнорировать.</li>
|
||||||
Для этого по `mouseover` нужно проверять, находится ли `event.target` был внутри `<td>`, это стандартная проверка при делегировании.</li>
|
<li>При `mouseout` проверять, если мы ушли с текущего `<td>`, а не перешли куда-то внутрь него, то игнорировать.</li>
|
||||||
<li>Лишними для нас будут `mouseover/mouseout`, связанные с переходом на дочерние элементы внутри `<td>`. Проверить их можно по `event.target/event.relatedTarget`.</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
[offline]
|
||||||
|
Детали кода вы можете посмотреть в [edit src="mouseenter-mouseleave-delegation-2"]полном примере[/edit].
|
||||||
|
[/offline]
|
||||||
|
|
||||||
|
[online]
|
||||||
Детали кода вы можете посмотреть в примере ниже, который демонстрирует этот подход:
|
Детали кода вы можете посмотреть в примере ниже, который демонстрирует этот подход:
|
||||||
|
|
||||||
[codetabs height=450 src="mouseenter-mouseleave-delegation-2"]
|
[codetabs height=450 src="mouseenter-mouseleave-delegation-2"]
|
||||||
|
|
||||||
Попробуйте по-разному, быстро или медленно заходить и выходить в ячейки таблицы. Обработчики `mouseover/mouseout` стоят на `table`, но при помощи делегирования корректно обрабатывают вход-выход.
|
Попробуйте по-разному, быстро или медленно заходить и выходить в ячейки таблицы. Обработчики `mouseover/mouseout` стоят на `table`, но при помощи делегирования корректно обрабатывают вход-выход.[/online]
|
||||||
|
|
||||||
## Особенности IE8-
|
## Особенности IE8-
|
||||||
|
|
||||||
|
@ -162,11 +218,13 @@ function fixRelatedTarget(e) {
|
||||||
## Итого
|
## Итого
|
||||||
|
|
||||||
У `mouseover, mousemove, mouseout` есть следующие особенности:
|
У `mouseover, mousemove, mouseout` есть следующие особенности:
|
||||||
<ol>
|
<ul>
|
||||||
|
<li>При быстром движении мыши события `mouseover, mousemove, mouseout` могут пропускать промежуточные элементы.</li>
|
||||||
<li>События `mouseover` и `mouseout` -- единственные, у которых есть вторая цель: `relatedTarget` (`toElement/fromElement` в IE).</li>
|
<li>События `mouseover` и `mouseout` -- единственные, у которых есть вторая цель: `relatedTarget` (`toElement/fromElement` в IE).</li>
|
||||||
<li>Событие `mouseout` срабатывает, когда мышь уходит с родительского элемента на дочерний. Используйте `mouseenter/mouseleave` или фильтруйте их, чтобы избежать излишнего реагирования.</li>
|
<li>События `mouseover/mouseout` подразумевают, что курсор находится над одним, самым глубоким элементом. Они срабатывают при переходе с родительского элемента на дочерний.</li>
|
||||||
<li>При быстром движении мыши события `mouseover, mousemove, mouseout` могут пропускать промежуточные элементы. Мышь может моментально возникнуть над потомком, миновав при этом его родителя.</li>
|
</ul>
|
||||||
</ol>
|
|
||||||
|
События `mouseenter/mouseleave` не всплывают и не учитывают переходы внутри элемента.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg width="440px" height="183px" viewBox="0 0 440 183" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||||
|
<!-- Generator: bin/sketchtool 1.3 (252) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>mouseover-mouseout-from-outside.svg</title>
|
||||||
|
<desc>Created with bin/sketchtool.</desc>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="combined" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||||
|
<g id="mouseover-mouseout-from-outside.svg" sketch:type="MSArtboardGroup">
|
||||||
|
<rect id="Rectangle-10" stroke="#E8C48E" stroke-width="4" stroke-dasharray="5,1,5,1" opacity="0.6" fill="#FFF9EB" sketch:type="MSShapeGroup" x="202" y="57" width="126" height="93"></rect>
|
||||||
|
<g id="noun_69008_cc" sketch:type="MSLayerGroup" transform="translate(171.000000, 8.000000)" fill="#E8C48E">
|
||||||
|
<path d="M234.020833,169 L4.97916667,169 C2.23066667,169 0,167.09875 0,164.775 L0,4.225 C0,1.90125 2.23066667,0 4.97916667,0 L234.020833,0 C236.759375,0 239,1.90125 239,4.225 L239,164.775 C239,167.09875 236.759375,169 234.020833,169 L234.020833,169 Z M9.95833333,160.55 L229.041667,160.55 L229.041667,8.45 L9.95833333,8.45 L9.95833333,160.55 L9.95833333,160.55 Z" id="Shape" sketch:type="MSShapeGroup"></path>
|
||||||
|
<path d="M229.041667,42.25 L9.95833333,42.25 C7.20983333,42.25 4.97916667,40.34875 4.97916667,38.025 C4.97916667,35.70125 7.20983333,33.8 9.95833333,33.8 L229.041667,33.8 C231.780208,33.8 234.020833,35.70125 234.020833,38.025 C234.020833,40.34875 231.780208,42.25 229.041667,42.25 L229.041667,42.25 Z" id="Shape" sketch:type="MSShapeGroup"></path>
|
||||||
|
<path d="M29.875,21.125 C29.875,23.4593125 27.6468229,25.35 24.8958333,25.35 C22.1448437,25.35 19.9166667,23.4593125 19.9166667,21.125 C19.9166667,18.7906875 22.1448437,16.9 24.8958333,16.9 C27.6468229,16.9 29.875,18.7906875 29.875,21.125 L29.875,21.125 Z" id="Shape" sketch:type="MSShapeGroup"></path>
|
||||||
|
<path d="M49.7916667,21.125 C49.7916667,23.4593125 47.5634896,25.35 44.8125,25.35 C42.0615104,25.35 39.8333333,23.4593125 39.8333333,21.125 C39.8333333,18.7906875 42.0615104,16.9 44.8125,16.9 C47.5634896,16.9 49.7916667,18.7906875 49.7916667,21.125 L49.7916667,21.125 Z" id="Shape" sketch:type="MSShapeGroup"></path>
|
||||||
|
<path d="M69.7083333,21.125 C69.7083333,23.4593125 67.4801563,25.35 64.7291667,25.35 C61.9781771,25.35 59.75,23.4593125 59.75,21.125 C59.75,18.7906875 61.9781771,16.9 64.7291667,16.9 C67.4801563,16.9 69.7083333,18.7906875 69.7083333,21.125 L69.7083333,21.125 Z" id="Shape" sketch:type="MSShapeGroup"></path>
|
||||||
|
</g>
|
||||||
|
<rect id="Rectangle-6" stroke="#E8C48E" stroke-width="4" fill="#FFF9EB" sketch:type="MSShapeGroup" x="231" y="85" width="69" height="36"></rect>
|
||||||
|
<text id="#TO" sketch:type="MSTextLayer" font-family="Open Sans" font-size="14" font-weight="526" sketch:alignment="middle" fill="#8A704D">
|
||||||
|
<tspan x="251.150618" y="109">#TO</tspan>
|
||||||
|
</text>
|
||||||
|
<path d="M236,94.6353921 L223.12832,94.6353921 L217.344468,101.853926 L105.198001,101.853926 L108.348404,94.146 L82,103.645409 L108.348404,113.146 L105.235092,105.438074 L217.204218,105.438074 L223.12832,112.830378 L236,112.830378 L228.709332,103.733476 L236,94.6353921" id="Fill-21" stroke="#EE6B47" stroke-width="2" stroke-linecap="square" fill="#EE6B47" sketch:type="MSShapeGroup" transform="translate(159.000000, 103.646000) scale(-1, 1) translate(-159.000000, -103.646000) "></path>
|
||||||
|
<text id="target" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="bold" fill="#8A704D">
|
||||||
|
<tspan x="240" y="80">target</tspan>
|
||||||
|
</text>
|
||||||
|
<text id="relatedTarget-=-null" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="bold" fill="#8A704D">
|
||||||
|
<tspan x="15" y="85">relatedTarget = null</tspan>
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4 KiB |
|
@ -0,0 +1,38 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg width="508px" height="92px" viewBox="0 0 508 92" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||||
|
<!-- Generator: bin/sketchtool 1.3 (252) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>mouseover-mouseout-over-elems.svg</title>
|
||||||
|
<desc>Created with bin/sketchtool.</desc>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="combined" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||||
|
<g id="mouseover-mouseout-over-elems.svg" sketch:type="MSArtboardGroup">
|
||||||
|
<rect id="Rectangle-6" stroke="#E8C48E" stroke-width="4" fill="#FFF9EB" sketch:type="MSShapeGroup" x="374" y="21" width="90.0136719" height="52.4511719"></rect>
|
||||||
|
<text id="#TO" sketch:type="MSTextLayer" font-family="Open Sans" font-size="14" font-weight="526" sketch:alignment="middle" fill="#8A704D">
|
||||||
|
<tspan x="405.150618" y="53">#TO</tspan>
|
||||||
|
</text>
|
||||||
|
<rect id="Rectangle-7" stroke="#E8C48E" stroke-width="4" fill="#FFF9EB" sketch:type="MSShapeGroup" x="16" y="21" width="90.0136719" height="52.4511719"></rect>
|
||||||
|
<text id="#FROM" sketch:type="MSTextLayer" font-family="Open Sans" font-size="14" font-weight="526" sketch:alignment="middle" fill="#8A704D">
|
||||||
|
<tspan x="36.8122396" y="53">#FROM</tspan>
|
||||||
|
</text>
|
||||||
|
<rect id="Rectangle-8" stroke="#E8C48E" stroke-width="4" stroke-dasharray="5,1,5,1" opacity="0.6" fill="#FFF9EB" sketch:type="MSShapeGroup" x="124" y="31" width="69.0072917" height="52.4511719"></rect>
|
||||||
|
<text id="<DIV>" opacity="0.6" sketch:type="MSTextLayer" font-family="Open Sans" font-size="14" font-weight="526" sketch:alignment="middle" fill="#8A704D">
|
||||||
|
<tspan x="139.384505" y="63"><DIV></tspan>
|
||||||
|
</text>
|
||||||
|
<rect id="Rectangle-9" stroke="#E8C48E" stroke-width="4" stroke-dasharray="5,1,5,1" opacity="0.6" fill="#FFF9EB" sketch:type="MSShapeGroup" x="207" y="31" width="69.0072917" height="52.4511719"></rect>
|
||||||
|
<text id="<DIV>-2" opacity="0.6" sketch:type="MSTextLayer" font-family="Open Sans" font-size="14" font-weight="526" sketch:alignment="middle" fill="#8A704D">
|
||||||
|
<tspan x="222.384505" y="63"><DIV></tspan>
|
||||||
|
</text>
|
||||||
|
<rect id="Rectangle-10" stroke="#E8C48E" stroke-width="4" stroke-dasharray="5,1,5,1" opacity="0.6" fill="#FFF9EB" sketch:type="MSShapeGroup" x="291" y="31" width="69.0072917" height="52.4511719"></rect>
|
||||||
|
<text id="<DIV>-3" opacity="0.6" sketch:type="MSTextLayer" font-family="Open Sans" font-size="14" font-weight="526" sketch:alignment="middle" fill="#8A704D">
|
||||||
|
<tspan x="306.384505" y="63"><DIV></tspan>
|
||||||
|
</text>
|
||||||
|
<path d="M401,38.6353921 L375.340223,38.6353921 L363.810075,45.8539263 L140.245366,45.8539263 L146.525714,38.146 L94,47.6454089 L146.525714,57.146 L140.319306,49.4380737 L363.530486,49.4380737 L375.340223,56.8303775 L401,56.8303775 L386.466006,47.7334759 L401,38.6353921" id="Fill-21" stroke="#EE6B47" stroke-width="2" stroke-linecap="square" fill="#EE6B47" sketch:type="MSShapeGroup" transform="translate(247.500000, 47.646000) scale(-1, 1) translate(-247.500000, -47.646000) "></path>
|
||||||
|
<text id="mouseover" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="bold" fill="#8A704D">
|
||||||
|
<tspan x="340" y="17">mouseover</tspan>
|
||||||
|
</text>
|
||||||
|
<text id="mouseout" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="bold" fill="#8A704D">
|
||||||
|
<tspan x="75" y="18">mouseout</tspan>
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.7 KiB |
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg width="278px" height="92px" viewBox="0 0 278 92" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||||
|
<!-- Generator: bin/sketchtool 1.3 (252) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>mouseover-mouseout.svg</title>
|
||||||
|
<desc>Created with bin/sketchtool.</desc>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="combined" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||||
|
<g id="mouseover-mouseout.svg" sketch:type="MSArtboardGroup">
|
||||||
|
<rect id="Rectangle-6" stroke="#E8C48E" stroke-width="4" fill="#FFF9EB" sketch:type="MSShapeGroup" x="94" y="24" width="90.0136719" height="52.4511719"></rect>
|
||||||
|
<text id="<DIV>" sketch:type="MSTextLayer" font-family="Open Sans" font-size="14" font-weight="526" sketch:alignment="middle" fill="#8A704D">
|
||||||
|
<tspan x="119.384505" y="56"><DIV></tspan>
|
||||||
|
</text>
|
||||||
|
<path d="M109,51.8276766 C109,51.8276766 88.1589755,39.0886766 74.3265137,34 C73.990849,36.1044846 73.6561461,38.2078702 73.3204815,40.3112558 C50.6491708,39.1326345 27.6239215,40.8772137 6,45.5449934 C8.76995481,49.733632 11.5399096,53.9217211 14.3098644,58.1098102 C32.5800247,54.1662369 52.0341482,52.6925483 71.1891551,53.6881948 C70.8534905,55.7926793 70.5178258,57.8960649 70.1831229,60 C81.3091081,56.2091804 109,51.8276766 109,51.8276766" id="Fill-55" stroke="#EE6B47" stroke-width="2" stroke-linecap="square" fill="#EE6B47" sketch:type="MSShapeGroup"></path>
|
||||||
|
<text id="mouseover" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="bold" fill="#8A704D">
|
||||||
|
<tspan x="17" y="21">mouseover</tspan>
|
||||||
|
</text>
|
||||||
|
<path d="M268,51.8276766 C268,51.8276766 247.158975,39.0886766 233.326514,34 C232.990849,36.1044846 232.656146,38.2078702 232.320481,40.3112558 C209.649171,39.1326345 186.623921,40.8772137 165,45.5449934 C167.769955,49.733632 170.53991,53.9217211 173.309864,58.1098102 C191.580025,54.1662369 211.034148,52.6925483 230.189155,53.6881948 C229.85349,55.7926793 229.517826,57.8960649 229.183123,60 C240.309108,56.2091804 268,51.8276766 268,51.8276766" id="Fill-56" stroke="#EE6B47" stroke-width="2" stroke-linecap="square" fill="#EE6B47" sketch:type="MSShapeGroup"></path>
|
||||||
|
<text id="mouseoout" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="bold" fill="#8A704D">
|
||||||
|
<tspan x="176" y="21">mouseoout</tspan>
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
|
@ -0,0 +1,26 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg width="233px" height="150px" viewBox="0 0 233 150" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||||
|
<!-- Generator: bin/sketchtool 1.3 (252) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>mouseover-to-child.svg</title>
|
||||||
|
<desc>Created with bin/sketchtool.</desc>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="combined" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||||
|
<g id="mouseover-to-child.svg" sketch:type="MSArtboardGroup">
|
||||||
|
<rect id="Rectangle-7" stroke="#E8C48E" stroke-width="4" fill="#FFF9EB" sketch:type="MSShapeGroup" x="12" y="14" width="212" height="117"></rect>
|
||||||
|
<text id="#FROM" sketch:type="MSTextLayer" font-family="Open Sans" font-size="14" font-weight="526" sketch:alignment="middle" fill="#8A704D">
|
||||||
|
<tspan x="18.9784745" y="31">#FROM</tspan>
|
||||||
|
</text>
|
||||||
|
<rect id="Rectangle-6" stroke="#E8C48E" stroke-width="4" fill="#FFF9EB" sketch:type="MSShapeGroup" x="140" y="64" width="69" height="36"></rect>
|
||||||
|
<text id="#TO" sketch:type="MSTextLayer" font-family="Open Sans" font-size="14" font-weight="526" sketch:alignment="middle" fill="#8A704D">
|
||||||
|
<tspan x="160.150618" y="88">#TO</tspan>
|
||||||
|
</text>
|
||||||
|
<path d="M151,83.0279175 C151,83.0279175 135.824497,73.7186483 125.752316,70 C125.5079,71.5378926 125.264184,73.074982 125.019768,74.6120715 C108.511532,73.7507714 91.7455739,75.0256562 76,78.436726 C78.0169574,81.4976542 80.0339148,84.5581808 82.0508721,87.6187075 C95.3543869,84.7368655 109.520011,83.6599391 123.467831,84.3875269 C123.223415,85.9254195 122.978999,87.462509 122.735284,89 C130.836729,86.2297857 151,83.0279175 151,83.0279175" id="Fill-54" stroke="#EE6B47" stroke-width="2" stroke-linecap="square" fill="#EE6B47" sketch:type="MSShapeGroup"></path>
|
||||||
|
<text id="mouseover" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="bold" fill="#8A704D">
|
||||||
|
<tspan x="113" y="59">mouseover</tspan>
|
||||||
|
</text>
|
||||||
|
<text id="mouseout" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="bold" fill="#8A704D">
|
||||||
|
<tspan x="39" y="70">mouseout</tspan>
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
BIN
figures.sketch
BIN
figures.sketch
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue