Введение в Spine.js Spine — небольшой фреймворк, позволяющий работать по схеме MVC, создавая приложения непосредственно на JavaScript, что обеспечивает логическое разделение кода, наследование моделей через классы и расширения.
Также во многом этот инструмент основан на API Backbone.js, поэтому те разработчики, которые имели дело с этим фреймворком, легко разберутся в Spine (однако есть ряд существенных отличий).
Spine.js может работать совместно с HTML5 и асинхронными запросами сервера.
С каждым днем появляется все больше и больше JavaScript-фреймворков.
Так что же делает Spine.js таким особенным?
- Простая реализация контроллера (на основе API Backbone)
- Поддержка локального хранилища Ajax и HTML5.
- Асинхронная связь с сервером
- Работает во всех современных браузерах (Chrome, Safari, Firefox, IE> =7)
- Позвоночник мобильный расширение
- Просто и легко
- Хорошая документация
Классы позвоночника, модели и виды
Официальная документация Позвоночник содержит самое подробное руководство, которое я когда-либо видел.Туда включено много чего: работа с валидацией, сериализацией и еще куча других фич.
Однако цель этого урока — представить три основные функции: занятия , модели И представления .
Классы
В основе Spine используется эмуляция Object.create, гарантирующая, что объекты создаются динамически и могут использоваться во время работы скрипта.Использование таких классов можно увидеть на следующем примере:
Метод init() используется для инициализации классов.var twitterClient = Spine.Class.create(); //or var twitterClientWithArgs = Spine.Class.create({ testMessage: "If it weren't for WebMD I would have never known what symptoms to mimic so I could get all these prescriptions from my doctor." });
Разработчики Spine решили не использовать функцию-конструктор, поскольку использование ключевого слова «new» могло вызвать некоторые проблемы при создании экземпляров класса.
var twitterClient = Spine.Class.create({
testMessage: "Hello world"
});
var myclient = twitterClient.init();
Все параметры, которые вы хотите использовать при инициализации объекта, должны передаваться через метод init().
Пример: var twitterClient = Spine.Class.create({
init:function(testMessage){
this.testMessage = testMessage;
}
});
Модели
В Spine модели используются для хранения данных приложения, а также любой другой логики, связанной с этими данными.Вам следует придерживаться этой идеи, потому что.
это одно из требований приложения, построенного на MVC. Данные, связанные с моделями, хранятся в Model.records и могут быть созданы с помощью функции Spine setup().
В следующем примере методу setup() присваивается имя модели и набор атрибутов: var Tweets = Spine.Model.setup("Tweet", ["username","tweet_message"]);
Функционал моделей можно расширить с помощью свойств конкретного класса следующим образом: Tweets.include({
toTweetString: function(){
return("@" + this.username + " " + this.tweet_message);
}
});
Модель создается с использованием того же простого метода .
init(): var mytweets = Tweets.init({username: "addyosmani", tweet_message: "hai twitter"});
Spine и Backbone имеют разные возможности для рендеринга шаблонов и их внедрения в модель DOM.
Контроллеры
Контроллеры Spine расширяют Spine.Class, а также наследуют все его свойства.
Пример создания контроллера в Spine: var TweetController = Spine.Controller.create({
init:function(){
//initial logic on instantiation
}
})
Контроллеры инициализируются следующим образом: var myTweetController = TweetController.init();
У каждого контроллера есть специальный элемент — «el», который можно передать через свойство экземпляра.
Пример: var myTweetController = TweetController.init({el: $('#tweets')});
Документация
Более подробная информация о занятия , модели И контролеры вы можете прочитать документацию по Spine.Ключевые различия между позвоночником и позвоночником
Разработчики, ознакомившиеся с документацией Backbone и Spine, в первые минуты не смогут обнаружить каких-либо принципиальных отличий.Однако в реальном проекте эти различия могут проявиться спонтанно.
1. Представления в Backbone больше похожи на традиционные контроллеры, а контроллеры Backbone больше отвечают за обработку URL-маршрутизации.
В Spine недавно добавили поддержку маршрутизации (потому что это очень нужный элемент), а контроллеры очень похожи на представления в Backbone. 2. Backbone использует функции-конструкторы и прототипы, а Spine использует эмулированную версию Object.create и симулируемую систему классов, что обеспечивает тот же эффект наследования и на самом деле является очень интересной техникой.
Это одно из принципиальных отличий от Backbone. Оба подхода имеют право на существование.
3. Многие разработчики обращают внимание на разницу в размере файлов той или иной библиотеки: в этой связи можно отметить тот факт, что в Spine нет маппинга, фильтрации и многих других функций, которые включены в Backbone. Если для вас размер имеет значение, то вам однозначно нужно выбрать Spine, потому что… в этом плане он выигрывает по всем параметрам.
Spine.js на практике
Пример: клиент Bit.ly
Когда вы работаете над SPA, много времени тратится на работу и взаимодействие с внешними данными (это могут быть ваши собственные данные или данные, полученные от какого-либо API).
Вы также захотите использовать маршрутизацию, чтобы иметь возможность сохранять состояние приложения.
Для этого вам, возможно, придется использовать localStorage, а также обрабатывать ajax-запросы.
Учитывая все вышесказанное, мы собираемся создать клиент bit.ly, который позволит вам:
- создавайте привлекательные URL-адреса прямо из браузера;
- архивируйте свои URL-адреса bit.ly, чтобы вы могли легко получить к ним доступ в любое время;
- предоставление статистики кликов (это будет реализовано посредством дополнительного «представления» для демонстрации маршрутизации).
Предварительные условия
Создание плагина bit.ly
Прежде чем мы начнем, нам нужно найти хороший способ доступа к сервисам bit.ly: 1. Сокращатель URL-адресов и 2. Статистика кликов.Вместо того, чтобы бороться с обычным JavaScript, мы будем использовать jQuery для более удобной и быстрой работы с ajax-запросами.
Такой подход также позволит нам написать более читаемое и понятное приложение.
Дополнительная поддержка store.js
По умолчанию Spine ориентирован на современные браузеры, и именно поэтому такие вещи, как localStorage, не будут работать одинаково во всех браузерах, поэтому, если вам нужна кроссбраузерная совместимость, вам следует использовать старые инструменты.Однако эту проблему можно решить, используя store.js (и то, на чем он основан: json2.js).
Ниже приведено содержимое файла Spine.model.local.js, который вы можете обновить для использования магазина, закомментировав отмеченные ниже строки и заменив их своими.
Spine.Model.Local = {
extended: function(){
this.sync(this.proxy(this.saveLocal));
this.fetch(this.proxy(this.loadLocal));
},
saveLocal: function(){
var result = JSON.stringify(this);
//localStorage[this.name] = result;
store.set(this.name, result);
},
loadLocal: function(){
//var result = localStorage[this.name];
var result = store.get(this.name);
if ( !result ) return;
var result = JSON.parse(result);
this.refresh(result);
}
};
Обработка шаблонов jQuery
Фреймворки Spine и Backbone могут взаимодействовать с несколькими подходами (микрошаблоны, mustache.js и т. д.).Какой из них использовать, решать вам.
В примере используется плагин jQuery tmpl для представления сокращенных записей URL-адресов и статистики кликов с использованием шаблонов.
Разработка
Список того, что необходимо реализовать:- Модель для представления данных, которые будут содержаться в каждом сокращенном URL-адресе (модель URL-адреса);
- Контроллер для представления отдельных записей и действий, которые может выполнять приложение (exports.URL);
- Контроллер вывода представления, отвечающего за ввод новой записи bit.ly (exports.UrlsList);
- Контроллер для отображения представления, отвечающего за статистику кликов по конкретной записи (exports.Stats);
- Универсальный контроллер, который будет обрабатывать маршрутизацию приложений (exports. UrlApp).
Начальное кэширование
var exports = this;
Простой плагин jQuery.
$.
fn.toggleDisplay = function(bool){
if ( typeof bool == "undefined" ) {
bool = !$(this).
filter(":first:visible")[0];
}
return $(this)[bool ? "show" : "hide"]();
};
URL-адрес модели:
var Url = Spine.Model.setup("Url", ["short_url", "long_url", "stats"]);
Url.extend(Spine.Model.Local);
Url.include({
validate: function(){
if ( !this.long_url )
return "long_url required"
if ( !this.long_url.match(/:\/\//))
this.long_url = "http://" + this.long_url
},
fetchUrl: function(){
if ( !this.short_url )
$.
bitly(this.long_url, this.proxy(function(result){
this.updateAttributes({short_url: result});
}));
},
fetchStats: function(){
if ( !this.short_url ) return;
$.
bitly.stats(this.short_url, this.proxy(function(result){
this.updateAttributes({stats: result});
}));
}
});
Url.bind("create", function(rec){
rec.fetchUrl();
});
Экспорт контроллера.
URL-адреса: exports.Urls = Spine.Controller.create({
events: {
"click .
destroy": "destroy", "click .
toggleStats": "toggleStats" }, proxied: ["render", "remove"], template: function(items){ return $("#urlTemplate").
tmpl(items);
},
init: function(){
this.item.bind("update", this.render);
this.item.bind("destroy", this.remove);
},
render: function(){
this.el.html(this.template(this.item));
return this;
},
toggleStats: function(){
this.navigate("/stats", this.item.id, true);
},
remove: function(){
this.el.remove();
},
destroy: function(){
this.item.destroy();
}
});
Контроллер экспортирует.UrlsList:
exports.UrlsList = Spine.Controller.create({
elements: {
".
items": "items",
"form": "form",
"input": "input"
},
events: {
"submit form": "create",
},
proxied: ["render", "addAll", "addOne"],
init: function(){
Url.bind("create", this.addOne);
Url.bind("refresh", this.addAll);
},
addOne: function(url){
var view = Urls.init({item: url});
this.items.append(view.render().
el);
},
addAll: function(){
Url.each(this.addOne);
},
create: function(e){
e.preventDefault();
var value = this.input.val();
if (value)
Url.create({long_url: value});
this.input.val("");
this.input.focus();
}
});
Экспорт контроллера.
Статистика: exports.Stats = Spine.Controller.create({
events: {
"click .
back": "back" }, proxied: ["change", "render"], init: function(){ Url.bind("update", this.render); }, template: function(items){ return $("#statsTemplate").
tmpl(items);
},
render: function(){
if ( !this.item ) return;
this.el.html(this.template(this.item));
},
change: function(item){
this.item = item;
this.navigate("/stats", item.id);
this.item.fetchStats();
this.render();
this.active();
},
back: function(){
this.navigate("/list", true);
}
});
Контроллер экспортирует.UrlApp:
exports.UrlApp = Spine.Controller.create({
el: $("body"),
elements: {
"#urls": "urlsEl",
"#stats": "statsEl"
},
init: function(){
this.list = UrlsList.init({el: this.urlsEl});
this.stats = Stats.init({el: this.statsEl});
this.manager = Spine.Controller.Manager.init();
this.manager.addAll(this.list, this.stats);
this.routes({
"": function(){ this.list.active() },
"/list": function(){ this.list.active() },
"/stats/:id": function(id){ this.stats.change(Url.find(id)) }
});
Url.fetch();
Spine.Route.setup();
}
});
Наконец, чтобы завершить инициализацию нашего контроллера приложения:
exports.App = UrlApp.init();
Код для сокращения URL-адресов и статистики кликов для Bit.ly
(function($){
var defaults = {
version: "3.0",
login: "legacye",
apiKey: "R_32f60d09cccde1f266bcba8c242bfb5a",
history: "0",
format: "json"
};
$.
bitly = function( url, callback, params ) {
if ( !url || !callback ) throw("url and callback required");
var params = $.
extend( defaults, params );
params.longUrl = url;
return $.
getJSON(" http://api.bit.ly/shortenЭcallback= ?", params, function(data, status, xhr){
callback(data.results[params.longUrl].
shortUrl, data.results[params.longUrl], data);
});
};
$.
bitly.stats = function( url, callback, params ) {
if ( !url || !callback ) throw("url and callback required");
var params = $.
extend( defaults, params );
params.shortUrl = url;
return $.
getJSON(" http://api.bitly.com/v3/clicksЭcallback= ?", params, function(data, status, xhr){
callback(data.data.clicks[0], data);
});
};
})(jQuery);
Индекс приложения/HTML:
Для управления приложением используется LABjs, но вы можете легко заменить его тем, с чем вы привыкли работать.
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="css/application.css" type="text/css" charset="utf-8">
<script src="lib/LAB.min.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
$LAB
.
script("lib/json.js") .
script("lib/jquery.js") .
script("lib/jquery.tmpl.js") .
script("lib/jquery.bitly.js") .
script("lib/store.min.js") .
script("lib/spine.js") .
script("lib/spine.model.local.js") .
script("lib/spine.controller.manager.js") .
script("lib/spine.route.js") .
script("app/models/url.js") .
script("app/application.js");
</script>
<script type="text/x-jquery-tmpl" id="urlTemplate">
<div class="item">
<div class="show">
<span class="short">
${long_url}
</span>
<span class="long">
{{if short_url}}
<a href="${short_url}">${short_url}</a>
{{else}}
Generating.
{{/if}}
</span>
<a class="toggleStats"></a>
<a class="destroy"></a>
</div>
</div>
</script>
<script type="text/x-jquery-tmpl" id="statsTemplate">
<div class="stats">
<a class="back">Back</a>
<h1>Click Statistics</h1>
<h1 class="longUrl">${long_url}</h1>
<p>Short URL:
{{if short_url}}
<a href="${short_url}">${short_url}</a>
{{else}}
Generating.
{{/if}}
</p>
{{if stats}}
<p>Global clicks: ${stats.global_clicks}</p>
<p>User clicks: ${stats.user_clicks}</p>
{{else}}
Fetching.
{{/if}}
</div>
</script>
</head>
<body>
<div id="views">
<div id="urls">
<h1>Bit.ly Client</h1>
<form>
<input type="text" placeholder="Введите URL-адрес">
</form>
<div class="items"></div>
</div>
<div id="stats">
</div>
</div>
</body>
</html>
Примечание:
- Для обеспечения кросс-браузерной совместимости этот пример необходимо запустить на работающем или локальном веб-сервере.
При необходимости используйте MAMP/WAMP;
- Для проверки статистики кликов я рекомендую использовать URL-адреса сайтов, которые пользуются наибольшей популярностью.
Например, информация о сайте www.google.com вероятно присутствует в базе данных Bit.ly;
- В демо используются мои собственные ключи API Bit.ly, которые необходимо заменить.
- Круговые диаграммы создаются с помощью Google Chart API. Чтобы не усложнять для вас уже новый подход, я сам решил изменить изображение диаграммы, но вы в любой момент можете легко переключиться на Visualization API;
- Структура каталогов приложения полностью зависит от вас.
Некоторые разработчики предпочитают общую структуру модель/представление/контроллер, в то время как другие предпочитают иметь универсальную папку приложения, где все содержится в одном файле.
В примере используется привычная мне структура папок.
- Если вы хотите сохранить уникальные «представления» для контента (например, одно представление для #ui/dashboard, а другое для #ui/stats), вам необходимо проанализировать способ работы spine.controller.manager.js, поскольку этот файл содержит решение этой проблемы.
Заключение
Spine — хорошая альтернатива Backbone. Документация достаточно хороша, чтобы продолжить изучение самостоятельно.Использованные материалы:
Теги: #backbone.js #Spine.js #JavaScript #MVC #JavaScript-
Критиковать Сайт Drupal
19 Oct, 24 -
Обновление Thunderbird
19 Oct, 24