Backbone.js и routes без хэшей

в 7:51, , рубрики: backbone, history, html5, javascript, Веб-разработка, Песочница, метки: , ,

Практически все, кому приходилось работать с 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, все идёт, так как ожидается. Т.е. ничего не работает. Происходит это из-за двух проблем:

  1. теперь приложение не знает, какая часть URL является собствено адресом, а какая — именем backbone-контроллера (поэтому по умолчанию считает этим именем всё после имени домена);
  2. если в 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


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js