Практически все, кому приходилось работать с backbone, представляют себе, что это за штука такая — Router. Конечно, в приложении можно обойтись и без него, но удобство работы с приложением сильно проиграет.
Итак, роутер определяет, какую функцию (контроллер) следует использовать, опираясь на URL в строке браузера. Или, если быть точным, на хэш. Т.е. вы могли понаставить в интерфейсе своего приложения ссылок вида:
<a href="http://myapp.com/catalog/#action1">Сделать что-то полезное</a>
или даже
<a href="http://myapp.com/catalog/#action1/42">Сделать что-то полезное с параметром</a>
и всё прекрасно работало. Пользователь, в свою очередь, мог сохранить каждую из этих ссылок, и, в последствии, перейти по ним, сразу же активировав нужную функциональность. Единственный негативный момент во всём этом великолепии — наличие символа "#" (решетка). Не то, чтобы она была плоха сама по себе, но читабельность и «красивость» (с задних рядов мне ещё кто-то про RESTful что-то подсказывает) URL она портила.
До пришествия html5 приходилось с этим мириться. С появлением же нового html появилась возможность управлять историей переходов браузера (а вместе с ней и внешим видом URL в адресной строке). Соответствующая функциональность появилась и в backbone (естественно, fallback для старых браузеров поддерживается). Попробуем ею воспользоваться, чтобы наше приложение выглядело модно и современно.
Документация (и даже StackOverflow) по этому поводу нам говорит просто: «Хотите роутинга без хэшей? Делайте при старте приложения так:»
Backbone.history.start({pushState: true})
Конечно же, как только мы добавлем к своему существующему коду определение параметра pushState, все идёт, так как ожидается. Т.е. ничего не работает. Происходит это из-за двух проблем:
- теперь приложение не знает, какая часть URL является собствено адресом, а какая — именем backbone-контроллера (поэтому по умолчанию считает этим именем всё после имени домена);
- если в href у ссылки указан URL без хэша, браузер не будет разбираться с тем, что мы там именно хотели, а просто перейдёт по указанному адресу (что для нашего приложения означает в лучшем случае полный рестарт).
Первую проблему можно решить относительно просто. У метода start имеется помимо параметра pushState ещё парочка параметров. Нам особено интересен root. Для нашего примера в начале текста запуск роутера будет выглядеть так:
Backbone.history.start({pushState: true, root: "/catalog"})
Теперь можно смело писать:
<a href="http://myapp.com/catalog/action1/42">Сделать что-то полезное с параметром</a>
Но пока страница всё равно перегружается. Дальнейшее чтение документации нам говорит, что ссылки придётся теперь делать немного посложнее. Например:
<a onclick="Router.navigate("http://myapp.com/catalog/action1/42", {trigger: true} )" href="javascript:">Сделать что-то полезное с параметром</a>
Т.е. теперь мы принудительно обновляем состояние приложения при каждом клике. Надо не забыть установить параметр trigger чтобы наш роутер всё-таки вызвался (а не просто сменился URL в адресной строке).
Остаётся предоставить пользователю возможность скопировать ссылку. Для этого сделаем простую функцию-обработчик ссылок, которую будем вызывать перед history.start. У меня эта функция вешает обработчик onclick для всех ссылок с id=«backbone» (но я не настаиваю на единственности такого подхода):
<a id="barebone" href="/catalog/action1/42">Сделать что-то полезное с параметром</a>
Не забываем, что в href указывается всё-таки URL, а не routes (хотя меня лично подмывает написать просто «action1/42»). Ну и сама функция (используется jQuery, что совсем не обязательно):
var fRouterLinks = function()
{
$("#barebone").click(function(){
Router.navigate($(this).attr("href"), {trigger: true, replace: true} );
return false;
});
}
Всё. Наслаждаемся красивыми URL.
Как видим, тьюториал получился вполне элементарным, но именно разрозненность информации по этому вопросу и заставила меня его написать.
Автор: kosyag