Fare öğeler arasında hareket ettiğinde meydana gelen olaylar hakkında daha fazla ayrıntıya girelim.
Mouseover/mouseout, relatedTarget
mouseover
olayı fare bir ögenin üzerine geldiğinde gerçekleşirken, mouseout
fare bu ögenin üzerinden gittiği zaman gerçekleşir.
Bu olaylar özeldir, çünkü relatedTarget
özellikleri vardır.
Bu özellik target
ı (hedefi) tamamlar. Fare bir ögeyi diğer ögeye gitmek için bıraktığında, bunlardan biri target
(hedef) , diğeri relatedTarget
(ilişkiliTarget) olur.
mouseover
için:
event.target
– fareyle üzerine gelinen ögeevent.relatedTarget
– farenin hedefe gitmeden önce üzerinde oldugu ögerelatedTarget
(relatedTarget
→target
).
mouseout
için tam tersi:
event.target
– farenin terk ettiği öge.event.relatedTarget
– farenin hedefteki ögeyi terk ettikten sonra gittiği öge. (target
→relatedTarget
).
Aşağıdaki örnekte her yüz özelliği bir öğedir. Fareyi hareket ettirdiğinizde, metin alanında fare olaylarını görebilirsiniz.
Her olay, elementin nereden geldiği ve nereye gittiği hakkında bilgi içerir.
container.onmouseover = container.onmouseout = handler;
function handler(event) {
function str(el) {
if (!el) return "null"
return el.className || el.tagName;
}
log.value += event.type + ': ' +
'target=' + str(event.target) +
', relatedTarget=' + str(event.relatedTarget) + "\n";
log.scrollTop = log.scrollHeight;
if (event.type == 'mouseover') {
event.target.style.background = 'pink'
}
if (event.type == 'mouseout') {
event.target.style.background = ''
}
}
body,
html {
margin: 0;
padding: 0;
}
#container {
border: 1px solid brown;
padding: 10px;
width: 330px;
margin-bottom: 5px;
box-sizing: border-box;
}
#log {
height: 120px;
width: 350px;
display: block;
box-sizing: border-box;
}
[class^="smiley-"] {
display: inline-block;
width: 70px;
height: 70px;
border-radius: 50%;
margin-right: 20px;
}
.smiley-green {
background: #a9db7a;
border: 5px solid #92c563;
position: relative;
}
.smiley-green .left-eye {
width: 18%;
height: 18%;
background: #84b458;
position: relative;
top: 29%;
left: 22%;
border-radius: 50%;
float: left;
}
.smiley-green .right-eye {
width: 18%;
height: 18%;
border-radius: 50%;
position: relative;
background: #84b458;
top: 29%;
right: 22%;
float: right;
}
.smiley-green .smile {
position: absolute;
top: 67%;
left: 16.5%;
width: 70%;
height: 20%;
overflow: hidden;
}
.smiley-green .smile:after,
.smiley-green .smile:before {
content: "";
position: absolute;
top: -50%;
left: 0%;
border-radius: 50%;
background: #84b458;
height: 100%;
width: 97%;
}
.smiley-green .smile:after {
background: #84b458;
height: 80%;
top: -40%;
left: 0%;
}
.smiley-yellow {
background: #eed16a;
border: 5px solid #dbae51;
position: relative;
}
.smiley-yellow .left-eye {
width: 18%;
height: 18%;
background: #dba652;
position: relative;
top: 29%;
left: 22%;
border-radius: 50%;
float: left;
}
.smiley-yellow .right-eye {
width: 18%;
height: 18%;
border-radius: 50%;
position: relative;
background: #dba652;
top: 29%;
right: 22%;
float: right;
}
.smiley-yellow .smile {
position: absolute;
top: 67%;
left: 19%;
width: 65%;
height: 14%;
background: #dba652;
overflow: hidden;
border-radius: 8px;
}
.smiley-red {
background: #ee9295;
border: 5px solid #e27378;
position: relative;
}
.smiley-red .left-eye {
width: 18%;
height: 18%;
background: #d96065;
position: relative;
top: 29%;
left: 22%;
border-radius: 50%;
float: left;
}
.smiley-red .right-eye {
width: 18%;
height: 18%;
border-radius: 50%;
position: relative;
background: #d96065;
top: 29%;
right: 22%;
float: right;
}
.smiley-red .smile {
position: absolute;
top: 57%;
left: 16.5%;
width: 70%;
height: 20%;
overflow: hidden;
}
.smiley-red .smile:after,
.smiley-red .smile:before {
content: "";
position: absolute;
top: 50%;
left: 0%;
border-radius: 50%;
background: #d96065;
height: 100%;
width: 97%;
}
.smiley-red .smile:after {
background: #d96065;
height: 80%;
top: 60%;
left: 0%;
}
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="container">
<div class="smiley-green">
<div class="left-eye"></div>
<div class="right-eye"></div>
<div class="smile"></div>
</div>
<div class="smiley-yellow">
<div class="left-eye"></div>
<div class="right-eye"></div>
<div class="smile"></div>
</div>
<div class="smiley-red">
<div class="left-eye"></div>
<div class="right-eye"></div>
<div class="smile"></div>
</div>
</div>
<textarea id="log">Events will show up here!
</textarea>
<script src="script.js"></script>
</body>
</html>
relatedTarget
null
olabilirrelatedTarget
özelliği null
(boş) olabilir.
Bu normaldir ve sadece farenin başka bir elementten değil, pencerenin dışından geldiği anlamına gelir. Ya da pencereden çıktığı anlamına gelir.
Kodumuzda event.relatedTarget
kullanırken bu olasılığı hesaba katmalıyız.event.relatedTarget.tagName
özelliğine ulaşırsak, bu hata verebilir.
Ögeleri atlama
mousemove
olayı fare hareket ettiğinde tetiklenir. Ancak bu her piksel bir olayı tetikler anlamına gelmez.
Tarayıcı farenin konumunu zaman içerisinde kontrol eder. Ve eğer konum değişikliği farekederse, olayı tetikler.
Bu, eğer kullanıcı fareyi çok hızlı hareket ettiriyorsa, bazı DOM ögelerinin atlanabileceği anlamına gelir.
Eğer fare #FROM
ögesinden#TO
ögesine çok hızlı bir şekilde hareket ederse, ortadaki <div>
ögeleri (ya da bazıları) atlanabilir. mouseout
olayı #FROM
ogesinde ve ardından aniden #TO
ögesi üzerinde tetiklenir.
Bu, performans için iyidir, çünkü arada birçok öge bulunabilir. Her birinde olay tetiklemeyi her zaman istemeyiz.
Öte yandan, fare ımlecinin yol boyunca tüm öğeleri “ziyaret etmediğini” unutmamalıyız. Bu ögelerin üzerinden “zıplayabilir”.
Özellikle, imlecin pencereden sayfanın ortasına doğru atlaması mümkündür. Bu durumda relatedTarget=null
, olur çünkü imleç “hiçbir yerden” gelmiştir:
Aşağıdaki test standında “canlı” olarak kontrol edebilirsiniz.
HTML iç içe geçmiş <div>
ögelerinden oluşuyor. Eğer farenizi onların üzerinden hızlıca hareket ettirirseniz, hiçbir olay tetiklenmeyebilir, belki sadece kırmızı div olay tetikleyebilir ya da sadece yeşil div tetikleyebilir.
Ayrıca, fareyi kırmızı “div” nin üzerine getirmeyi deneyin ve ardından hızlıca yeşil olandan aşağı doğru hareket ettirin. Hareket yeterince hızlıysa, ana öğe göz ardı edilir.
green.onmouseover = green.onmouseout = green.onmousemove = handler;
function handler(event) {
let type = event.type;
while (type < 11) type += ' ';
log(type + " target=" + event.target.id)
return false;
}
function clearText() {
text.value = "";
lastMessage = "";
}
let lastMessageTime = 0;
let lastMessage = "";
let repeatCounter = 1;
function log(message) {
if (lastMessageTime == 0) lastMessageTime = new Date();
let time = new Date();
if (time - lastMessageTime > 500) {
message = '------------------------------\n' + message;
}
if (message === lastMessage) {
repeatCounter++;
if (repeatCounter == 2) {
text.value = text.value.trim() + ' x 2\n';
} else {
text.value = text.value.slice(0, text.value.lastIndexOf('x') + 1) + repeatCounter + "\n";
}
} else {
repeatCounter = 1;
text.value += message + "\n";
}
text.scrollTop = text.scrollHeight;
lastMessageTime = time;
lastMessage = message;
}
#green {
height: 50px;
width: 160px;
background: green;
}
#red {
height: 20px;
width: 110px;
background: red;
color: white;
font-weight: bold;
padding: 5px;
text-align: center;
margin: 20px;
}
#text {
font-size: 12px;
height: 200px;
width: 360px;
display: block;
}
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="green">
<div id="red">Test</div>
</div>
<input onclick="clearText()" value="Clear" type="button">
<textarea id="text"></textarea>
<script src="script.js"></script>
</body>
</html>
Çocuk öge için ayrılırken “Ekstra” mouseout olayı
Fareyle bir elementin üzerine geldiğinizi düşünün. mouseover
olayı tetiklendi. Daha sonra fare imleci iç içe geçmiş çocuk elementin üzerine gittiğini varsayalım. İlginç olarak mouseout
olayı tetiklenir. Fare imleci teknik olarak hala elementin üzerinde, ancak biz buradan ekstra bir mouseout
olayı çıkarmış olduk.
Bu ilginç görünebilir ancak kolayca açıklanabilir bir durumdur.
Tarayıcı mantığına göre, fare imleci herhangi bir zamanda yalnızca tek bir öğenin üzerinde olabilir – en içte olanı seçer ( z-endeksi en yüksek olanı yani en üstte olanı).
Yani başka bir öğeye giderse (aynı ögeye baglı bıle olsa), o zaman bir öncekinden ayrılmış kabul edilir. Bu kadar basit.
Buradan aşağıdaki örnekte görebileceğimiz komik bir sonuç çıkar.
Kırmızı <div>
mavi olanın içine konmuştur. Mavi <div>
mouseover/out
olayı tetiklendiği zamanlarda aşağıdaki metin alanına yazan bir şekilde kodlanmıştır.
Mavi öğeye girip fareyi kırmızı öğenin üzerine getirmeyi deneyin ve olayları izleyin:
function mouselog(event) {
text.value += event.type + ' [target: ' + event.target.className + ']\n'
text.scrollTop = text.scrollHeight
}
.blue {
background: blue;
width: 160px;
height: 160px;
position: relative;
}
.red {
background: red;
width: 100px;
height: 100px;
position: absolute;
left: 30px;
top: 30px;
}
textarea {
height: 100px;
width: 400px;
display: block;
}
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="blue" onmouseover="mouselog(event)" onmouseout="mouselog(event)">
<div class="red"></div>
</div>
<textarea id="text"></textarea>
<input type="button" onclick="text.value=''" value="Clear">
<script src="script.js"></script>
</body>
</html>
- Mavi ogeye girerken –
mouseover [target: blue]
olayı tetiklenir. - TMavi olandan kırmızı olana hareket ettikten sonra –
mouseout [target: blue]
olayı tetiklenir. - …Ve aniden
mouseover [target: red]
.
Bu nedenle, “hedef” i hesaba katmayan bir kod için, “(2)” öğesinde “mouseout” öğesinde üstteki ögeyi bıraktık ve “(3)” öğesinde “mouseover” ile ona geri döndük gibi görünüyor.
Sonuç olarak öğeye girme / öğeden çıkma konusunda bazı eylemler gerçekleştirir, sadece bunları hesaba katarak bir yazılım geliştirirsek birçok ekstra “yanlış” sonuç elde edebiliriz.
Bu sorunu mouseenter/mouseleave
olaylarını kullanarak düzeltebiliriz.
mouseenter and mouseleave olayları
mouseenter/mouseleave
olayları mouseover/mouseout
olaylarına benzer şekilde çalışır. Bunlar da imleç bir ögenin üzerine geldiğinde/ ayrıldığında tetiklenir.
Ancak iki fark vardır:
- Elementin içindeki imleç hareketi sayılmaz.
mouseenter/mouseleave
olay kabarcıklanması (bubble) yapmaz.
Bu olaylar sezgisel olarak çok açık.
İmleç bir elementin üzerine geldiği zaman – mouseenter
tetiklenir, ve bu elementin içinde nereye hareket ettiği önem taşımaz. mouseleave
olayı ancak imleç o elementten tamamen ayrıldığı zaman tetiklenir.
Eğer aynı örneği verecek olursak, mouseenter/mouseleave
olayını mavi <div>
üzerinde denersek, aynı hareketi yaptığımız zaman-- olayların sadece <div>
ögesinden girişte ve çıkışta tetiklendiğini görürüz. Ekstra olarak kırmızı olana giriş çıkışta olay tetiklenmez. İç içe geçmiş çocuk elementler göz ardı edilir.
function log(event) {
text.value += event.type + ' [target: ' + event.target.id + ']\n';
text.scrollTop = text.scrollHeight;
}
#blue {
background: blue;
width: 160px;
height: 160px;
position: relative;
}
#red {
background: red;
width: 70px;
height: 70px;
position: absolute;
left: 45px;
top: 45px;
}
#text {
display: block;
height: 100px;
width: 400px;
}
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="blue" onmouseenter="log(event)" onmouseleave="log(event)">
<div id="red"></div>
</div>
<textarea id="text"></textarea>
<input type="button" onclick="text.value=''" value="Clear">
<script src="script.js"></script>
</body>
</html>
Olay delegasyonu (Event delegation)
mouseenter/leave
olaylarının kullanımı çok basittir. Ancak kabarcıklanma (bubble) yapmazlar. Bu yüzden bu olaylarla olay delegasyonu yapamayız.
Tablo hücreleri için fare giriş / çıkışını işlemek istediğimizi hayal edin. Ve yüzlerce hücre var.
Doğal çözüm – işleyiciyi “
” üzerinde meydana gelirse, o zaman sadece “ | ” üzerindeki bir işleyici onu yakalayabilir.
Bu problem değil – Basit bir işleyici şöyle görünebilir:
Sonuç script.js style.css index.html
Bu işleyiciler, herhangi bir öğeden tablonun içindeki herhangi bir diğer ogeye giderken çalışır. Ancak biz Çözümlerden biri:
Bu, “ | ” nin çocukları arasında hareket ettiğimizde “ekstra” olayları filtreler.
Bütün detaylarıyla bir örnek verecek olursak: Sonuç script.js style.css index.html
İmleci tablo hücrelerinin içine, dışına ve içlerine taşımaya çalışın. Hızlı veya yavaş olamsı önemli değil. Önceki örnekten farkı burada yalnızca “ | ” nin bir bütün olarak ışıklandırılmış olmasıdır.
Summary
Not edilmesi gerekenler:
Görevlerönem: 5 Fare ile bir elementin üzerinden geçildiğinde Buradaki göreve benziyor Tooltip behavior, ancak burada gösterilen öğeler iç içe geçmiş olabilir. En içteki tooltip gösterilmelidir. Örneğin:
Sonuç iframe üzerinde: Not ipucu: aynı anda yalnızca bir araç ipucu (tooltip) görünebilir. önem: 5 Kullanıcı fareyle bir elementin üzerinden geçtiğinde ancak üzerinden geçip gitmediğinde tooltip (ipucu) gösteren bir fonksiyon yazın. Diğer kelimelerle, eğer kullanıcı faresiyle bir ögenin üzerine gelirse ve durursa – tooltipi göster. Ancak eğer faresiyle bu ögenin üzerinden hızlıca geçip giderse, tooltip gösterme. Teknik olarak, bir öğenin üzerindeki fare hızını ölçebiliriz, eğer hızı yavaşsa biz bunu elementin üzerinden geçiyor kabul ederek tooltipi göstermeliyiz. Hızı fazla ise o zaman görmezden gelmeliyiz. Bunun için global obje
Tooltip için böyle bir objeyi kullanmaya bir örnek:
demo: Fareyi “saat” üzerine hızlı bir şekilde hareket ettirirseniz hiçbir şey olmaz ve bunu yavaş yaparsanız veya durdurursanız, bir tooltip gösterecektir. Lütfen dikkat: imleç saat alt öğeleri arasında hareket ettiğinde tooltip “gelip gitmez”. The algorithm looks simple:
The question is: “How to measure the speed?” The first idea would be: to run our function every Unfortunately, there’s no way to get “current mouse coordinates” in JavaScript. There’s no function like The only way to get coordinates is to listen to mouse events, like So we can set a handler on P.S. Please note: the solution tests use |