Пример многоуровневой навигации Backbone JS - PullRequest
2 голосов
/ 02 апреля 2011

Я пытаюсь построить надежный эксперимент Backbone JS, где у меня есть локальный файл данных JSON, содержащий мои страницы (так или иначе, у проекта, который я делаю, есть такие требования). И я кодировал этот пример, чтобы в данных страниц могли быть бесконечные вложенные подстраницы. Кажется, работает отлично. Но когда дело доходит до URL, я немного застрял.

Как мне подойти, чтобы этот пример многоуровневой навигации был полностью динамическим URL? Я имею в виду правильное использование свойства url моделей и коллекций для создания правильных URL-адресов для всех элементов верхнего уровня и вложенных элементов. Это вообще возможно? Я просто не могу думать, как это сделать.

Посмотрите живую демонстрацию того, где я сейчас нахожусь: http://littlejim.co.uk/code/backbone/multiple-level-navigation-experiment/

Просто так проще, исходный код ниже ...

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Multiple Level Navigation Experiment</title>
    <script type="text/javascript" src="../../media/scripts/jquery-1.5.1.min.js"></script>
    <script type="text/javascript" src="../../media/scripts/underscore-min.js"></script>
    <script type="text/javascript" src="../../media/scripts/backbone-min.js"></script>
    <script type="text/javascript" src="application.js"></script>
    <script type="text/javascript">
    // wait for the DOM to load
    $(document).ready(function() {
        App.initialize();
    });
    </script>
</head>
<body>
    <div id="header">
        <h1>Multiple Level Navigation Experiment</h1>
        <p>Want to get this page structure pulled from JSON locally and have a fully functional multiple level nested navigation with correct anchors.</p>
    </div>
    <div id="article">
        <!-- dynamic content here -->
    </div>
</body>
</html>

content.json

{
"pages": [
    {
    "id": 1,
    "title": "Home",
    "slug": "home"
    },
    {
    "id": 2,
    "title": "Services",
    "slug": "services",
    "subpages": [
        {
        "id": 1,
        "title": "Details",
        "slug": "details",
        "subpages": [
            {
            "id": 1,
            "title": "This",
            "slug": "this"
            },
            {
            "id": 2,
            "title": "That",
            "slug": "that"
            }
        ]
        },
        {
        "id": 2,
        "title": "Honest Service",
        "slug": "honest-service"
        },
        {
        "id": 3,
        "title": "What We Do",
        "slug": "what-we-do"
        }
        ]
    },
    {
    "id": 3,
    "title": "Contact Us",
    "slug": "contact-us"
    }
]
}

application.js

// global app class
window.App = {
    Data: {},
    Controller: {},
    Model: {},
    Collection: {},
    View: {},
    initialize : function () {
        $.ajax({
            url: "data/content.json",
            dataType: "json",
            success: function(json) {
                App.Data.Pages = json.pages;
                new App.Controller.Main();
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
                console.log(errorThrown);
            }
        });
    }
}

// main controller class
// when called it should have 'data' in JSON format passed to it
App.Controller.Main = Backbone.Controller.extend({
    initialize: function() {
        var pagesCollection = new App.Collection.Pages(App.Data.Pages);
        var pagesView = new App.View.Pages({collection: pagesCollection});
        $('#article').html(pagesView.render().el);
    }
});

// pages model class
App.Model.Page = Backbone.Model.extend({
    initialize: function() {
        if (!_.isUndefined(this.get("subpages"))) {
            this.subpages = new App.Collection.Pages(this.get("subpages"));
        } // end if
        this.view = new App.View.Page({model: this});
    },
});

// page collection class
App.Collection.Pages = Backbone.Collection.extend({
    model: App.Model.Page
});

// single page view class
App.View.Page = Backbone.View.extend({
    tagName: "li",
    initialize: function() {
        _.bindAll(this, "render");
    },
    render: function() {
        $(this.el).html(_.template("<%=title%>", {title: this.model.get("title")}));
        return this;
    }
});

// multiple pages view class
App.View.Pages = Backbone.View.extend({
    tagName: "ul",
    initialize: function() {
        _.bindAll(this, "render");
    },
    render: function() {
        var that = this;
        this.collection.each(function(page) {
            $(that.el).append(page.view.render().el);
            if (!_.isUndefined(page.subpages)) {
                var subpagesView = new App.View.Pages({collection: page.subpages});
                $(that.el).append(subpagesView.render().el);
            } // end if
        });
        return that;
    }
});

Мне просто нужно правильное указание о том, как правильно выполнять URL-адреса. Идея, которую я хочу, заключается в том, что я могу настроить свой контроллер для маршрутов, чтобы он мог ожидать любую страницу любого вложенного уровня. Модели, коллекции и вложенные коллекции должны иметь возможность самостоятельно генерировать свои URL-адреса, но URL-адрес хэша должен отражать уровень.

В идеале эта навигация должна идти по следующим URL:

... URL-адреса, использующие "slug" из данных content.json. Имеет ли это смысл? Я довольно новичок в Backbone JS и просто хочу все делать правильно. Спасибо, Джеймс

Ответы [ 2 ]

3 голосов
/ 09 мая 2011

Вот мое любимое решение этой проблемы: используйте PathJS !

2 голосов
/ 02 апреля 2011

Почему бы просто не разобрать слаг?

Таким образом, у вас может быть один маршрут в Backbone.Controller, который выглядит следующим образом:

'pages/:id' : showPage

И тогда showPage выглядит следующим образом:

showPage(id) : function(id) {
   parse out the string 'services/details/etc'
   look up the slug data based on that IE pages['services']['details']['etc']
}

или если страницы действительно нужно обрабатывать по-разному, вы можете настроить несколько маршрутов, еще более детализированных, например:

'pages/:id' : showPage
'pages/:id/:nest' : showNestedPage
'pages/:id/:nest/:more' : showNestedMorePage
...