Budeme potřebovat knihovnu jquery (v příkladu používám verzi 1.10.2) a její šikovný selector ":visible". Tento selektor umí rozpoznat jestli element, ke kterému se váže je skutečně vidět - tzn. není to je tupá kontrola css-kové vlastnost visibility, ale projde si i všechny rodičovské elementy v DOMu, jestli náhodou nemá vidtelnost vypnutou některý z nich.
Následně budeme kontrolovat v pravidelném intervalu stav daného elementu (nebo více elementů), aktuální hodnotu viditelnosti si uložíme do "data-" atributu a v jakmile dojde ke změně vystřelíme událost.
Vytvoříme si obslužnou třídu VisibilityChangedObserver, která bude mít public metody
- register($selector, callback)
- zaregistruje událost visibilityChanged na zadaném prvku/prvcích dle použitého selektoru a zavolá callback s parametrem event (jquery event object), který v propertě result nese booleanovou hodnotu jestli je cílová element viditelný - deregister($selector)
- odregistruje událost visibilityChanged na zadaném prvku/prvcích - start(interval = 100)
- sputí smyčku sledování a kontroluje stav v pravidelných intervalech 9pokud není zadáno tak po 100 milisekundách) - stop()
- ukončí smyčku sledování
var VisibilityChangedObserver = function () {
var registrations = [];
var timerId = null;
var self = this;
var checkVisiblities = function() {
"use strict";
for (var i = 0; i < registrations.length; i++) {
var registration = registrations[i];
var wasVisible = $(registration).data("visibilityChangedPrevious") == "visible";
var isVisible = $(registration).is(":visible");
if (wasVisible != isVisible) {
$(registration).data("visibilityChangedPrevious", isVisible ? "visible" : "hidden");
$(registration).trigger("visibilityChanged");
}
}
};
this.register = function($selector, callback) {
"use strict";
$selector.each(function() {
registrations.push(this);
$(this).on("visibilityChanged", function(event) {
event.result = $(this).is(":visible");
callback(event);
});
});
return this;
};
this.deregister = function($selector) {
"use strict";
var index = registrations.indexOf($selector);
if (index > -1) {
registrations = registrations.splice(index, 1);
}
};
this.start = function() {
"use strict";
timerId = window.setInterval(checkVisiblities, 100);
return this;
};
this.stop = function() {
"use strict";
if (timerId != null) {
window.clearInterval(timerId);
}
return this;
};
};
V následujícím příkladu si můžete uvedenou funkcionalitu vyzkoušet. Spustitelné demo na http://jsfiddle.net/8gPq6/. Čtyři tlačítka v headeru zobrazují/skrývají odpovídající elementy, do patičky pak právě pomocí nové události přicházejí zprávy o viditelnosti.
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Sample</title>
<link rel="stylesheet" type="text/css" href="site.css" />
<script type="text/javascript" src="jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="visibilityChangedObserver.js"></script>
<script type="text/javascript">
var messageStack = [];
var updateStatusMessage = function(message){
messageStack.push(message);
while (messageStack.length > 3) {
messageStack.shift();
}
$("footer").html("<p>" + messageStack.join("<br />") + "</p>");
};
$(document).ready(
function(){
$("button").on("click", function(event){
var asociated = $(this).data("asociated");
$(asociated).toggle();
});
var observer = new VisibilityChangedObserver()
.register($(".visibilityCheck"), function(event){
var message = "Element with #id = '" + $(event.target).attr("id") + "' is " + ((event.result) ? "visible." : "hidden.");
updateStatusMessage(message);
})
.start();
}
);
</script>
</head>
<body>
<header>
<button id="btnOuter" data-asociated="#outer">Toggle outer</button>
<button id="btnInner1" data-asociated="#inner1">Toggle inner1</button>
<button id="btnInner2" data-asociated="#inner2">Toggle inner2</button>
<button id="btnInner3" data-asociated="#inner3">Toggle inner3</button>
</header>
<div id="main">
<div id="outer">
<p>Outer DIV</p>
<div id="inner1" class="inner visibilityCheck">
<p>Inner DIV1</p>
</div>
<div id="inner2" class="inner visibilityCheck">
<p>Inner DIV2</p>
</div>
<div id="inner3" class="inner visibilityCheck">
<p>Inner DIV3</p>
</div>
</div>
</div>
<footer>
</footer>
</body>
</html>
