[JavaScript] Pseudo MVC na jQuery

Kod HTML coraz częściej naszpikowany jest wieloma artybutami pomocnymi przy wdrażaniu kodu JS do projektu. Czy nie da się z tym czegoś zrobić? Dodatkowo bardzo często kod JS jest „brudny” przez mieszanie wartw: danych, prezentacji i logiki. W małym projekcie to znośne, ale w dużych zaczyna być nie do ogarnięcia. Spróbuję pokazać co można zmienić w tej kwestii.

Strona „spaghetti”

Dawniej stosowało się określenia „spaghetti HTML”, mając na myśli kod HTML naszpikowany atrybutami nadającym stronie wygląd. Aby temu zapobiegać zaczęto stosować CSS. W przypadku JS także można zostawić kod HTML czystym od wszelkim artybutów „zdarzeniowych” (`onclick’, `onmouseover’ itp.). Najpierw kod, gdzie tego nie zrobię i atrybuty będą zaszyte w kodzie HTML:

[html]<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
</head>
<body>
<div id="content">Tu się coś zmieni</div>
<button onclick="document.getElementById(‚content’).innerHTML=’Cześć’">
Akcja 1
</button>
</body>
</html>[/html]

Po kliknięciu na przycisk w kontenerze `#conent’ zostanie podmieniony ciąg znaków. Czy jednak nie wydaje Ci się to nieeleganckie?

Zebranie wszystkich akcji w jednym miejscu

Spróbujmy do tego podejść trochę inaczej. Zamiast wstrzykiwać kod JS do atrybutów znaczników, dajmy ten kod w jednym miejscu strony. W poniższym przykładzie użyję frameworka jQuery.

[html]<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.4.2.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$(‚#action’).click(function() {
$(‚#content’).html(‚Cześć’);
});
});
</script>
</head>
<body>
<div id="content">Tu się coś zmieni</div>
<button id="action">Akcja 1</button>
</body></html>[/html]

Kod HTML od razu stał się bardziej przejrzysty. Jednak nikt nie powiedział, że ten cały system będzie tak prosty. Mało który skrypt JS nie korzysta dzisiaj z Ajaksa, często zmienia duże kawałki kodu HTML operując na modelu DOM. Może warto więc byłoby zrobić to trochę inaczej:

[html]<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.4.2.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
var oController = yController();

$(‚#action’).click(oController.clickHandler);
});

var yController = function()
{
function fClickHandler()
{
$(‚#content’).html(‚Cześć’);
}

return {
clickHandler : fClickHandler
};
};
</script>
</head>
<body>
<div id="content">Tu się coś zmieni</div>
<button id="action">Akcja 1</button>
</body></html>[/html]

Tym sposobem ograniczyliśmy do jednej linii kod odpowiedzialny za przypisanie zdarzeniu jakiejś funkcji. Jednak skrypt rozrósł się nam trochę. Na dobrą sprawę w obiekcie `yController’ dzieje się to samo, co działo się wcześniej w ciele anonimowej funkcji. Spróbujmy dodać jeszcze dodatkowe obiekty – jeden, który będzie dokonywał zmian w  strukturze DOM, a drugi który będzie uzyskiwał wymagane dane.

Model – View – Controller

[html]<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="mvc.js"></script>

</head>
<body>
<div id="content">Tu się coś zmieni</div>
<button id="action1">Akcja 1</button>
</body>
</html>[/html]

Oraz kod pliku ‚mvc.js’:

[javascript]$(document).ready(function() {
var oController = yController();
$(‚#action1’).click(oController.clickHandler);
});

var ySrc = function() {
function fGetLabel(fSuccess, fErorr)
{
// tu jakis ajax, ja podaje na sztywno dane,
// tak jakbym przekazal do funkcji callback
var fakeData = { result : "cześć" };
fSuccess(fakeData);
}
return {
getLabel : fGetLabel
};
};

var yView = function()
{
function fDisplayContent( data )
{
$(‚#content’).html(data.result);
}
return {
displayContent : fDisplayContent
};
};

var yController = function()
{
var oSrc = ySrc(),
oView = yView();
function fClickHandler()
{
var label = oSrc.getLabel(oView.displayContent);
}
return {
clickHandler : fClickHandler
};
};[/javascript]

Jak widać bardzo często korzystam tu z faktu że w JS bardzo przyjemnie przekazuje się funkcje jako parametry do innych funkcji. Zobacz linię 36. Kiedy stwierdzisz, że co dane powinny się pojawić gdzie indziej ograniczysz liczbę zmian do jednego miejsca – w konstruktorze obiektu `yView’. A być może – patrząc przyszłościowo – także kod z `displayContent’ da się wykorzystać jeszcze w kilku miejscach?

W kodzie wykorzystałem wzorzec fabryki.

Przykład wykorzystania tego podejścia w większym projekcie:

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *