Backbone.js: отримати поточний маршрут


137

Використовуючи хребет, чи можна мені назвати поточний маршрут? Я знаю, як прив’язати події до зміни маршруту, але я хотів би мати можливість визначити поточний маршрут в інший час, між змінами.


Під "ім'ям" ви маєте на увазі функцію, до якої цей маршрут пов'язує, або просто те, що є поточною URL-адресою або хеш-частиною URL-адреси?
— Джон Мюнш

1
О так, я мав би бути більш конкретним. Я хотів би знати назву функції. (Я знаю, як отримати хеш-частину URL-адреси, виконавши location.hash або Backbone.history.fragment.)
— Дрю Дара-Абрамс

Відповіді:


209

Якщо ви застосували маршрутизатор у вашій програмі, наступний рядок повертає поточний фрагмент:

Backbone.history.getFragment();

З документації Backbone.js :

"[...] Історія служить глобальним маршрутизатором (за кадром), щоб обробляти події хеш-зміни або pushState, відповідати відповідному маршруту та викликати зворотні виклики. Ніколи не потрібно було самостійно створювати один з них - ви повинні використовувати посилання до Backbone.історії, яка буде створена для вас автоматично, якщо ви використовуєте маршрутизатори з маршрутами. [...] "

Якщо вам потрібна назва функції, пов'язаної з цим фрагментом, ви можете зробити щось подібне всередині сфери вашого маршрутизатора:

alert( this.routes[Backbone.history.getFragment()] );

Або так із-за маршрутизатора:

alert( myRouter.routes[Backbone.history.getFragment()] );

Спасибі, це чудово. Я ніколи не згадую у документі Backbone.history.fragment. Це нове доповнення чи просто недокументоване?
— Дрю Дара-Абрамс

Я думаю, що це недокументовано. Насправді я не пам’ятаю, де я його бачив вперше, якийсь блог чи, можливо, магістральний вихідний код.
— Роберт

25
FYI, це не працює з такими маршрутами, як 'foo /: id' або 'bar * params'
— wprl

2
Краще використовувати Backbone.history.getFragment(), тому що Backbone.history.fragmentце приватне приховане майно.
— Вад

1
Я виправив відповідь після пропозиції @Vad. Я вже не використовую Backbone, але його коментар звучить мені правильно. (Попередня відповідь була: Backbone.history.fragment замість Backbone.history.getFragment ())
— Роберт

57

Відповідь Роберта цікава, але, на жаль, вона спрацює лише в тому випадку, якщо хеш точно такий, як визначено в маршруті. Якщо у вас, наприклад, є маршрут, user(/:uid)він не буде збігатися, якщо Backbone.history.fragmentє "user"або "user/1"( або обидва, що є двома найбільш очевидними випадками використання для такого маршруту). Іншими словами, відповідне ім'я зворотного виклику він знайде лише в тому випадку, якщо хеш точно "user(/:uid)"(дуже малоймовірний).

Так як я потребував в цій функції я продовжив Backbone.Routerз current-функцією , що деякі з багаторазово використовує коду використання об'єкта історії та маршрутизатора відповідно до поточного фрагментом проти певних маршрутів для запуску відповідного зворотного виклику. У випадку мого використання він бере необов’язковий параметр route, який, якщо встановлено щось істинне, поверне відповідну назву функції, визначену для маршруту. Інакше він поверне поточний хеш-фрагмент з Backbone.History.fragment.

Ви можете додати код до наявного розширення, де ви ініціалізуєте та встановите маршрутизатор Backbone.

var Router = new Backbone.Router.extend({

    // Pretty basic stuff
    routes : {
        "home" : "home",
        "user(:/uid)" : "user",
        "test" : "completelyDifferent"
    },

    home : function() {
        // Home route
    },

    user : function(uid) {
        // User route
    },

    // Gets the current route callback function name
    // or current hash fragment
    current : function(route){
        if(route && Backbone.History.started) {
            var Router = this,
                // Get current fragment from Backbone.History
                fragment = Backbone.history.fragment,
                // Get current object of routes and convert to array-pairs
                routes = _.pairs(Router.routes);

            // Loop through array pairs and return
            // array on first truthful match.
            var matched = _.find(routes, function(handler) {
                var route = handler[0];

                // Convert the route to RegExp using the 
                // Backbone Router's internal convert
                // function (if it already isn't a RegExp)
                route = _.isRegExp(route) ? route :  Router._routeToRegExp(route);

                // Test the regexp against the current fragment
                return route.test(fragment);
            });

            // Returns callback name or false if 
            // no matches are found
            return matched ? matched[1] : false;
        } else {
            // Just return current hash fragment in History
            return Backbone.history.fragment
        }
    }
});

// Example uses:
// Location: /home
// console.log(Router.current()) // Outputs 'home'
// Location: /user/1
// console.log(Router.current(true)) // Outputs 'user'
// Location: /user/2
// console.log(Router.current()) // Outputs 'user/2'
// Location: /test
// console.log(Router.current(true)) // Outputs 'completelyDifferent'

Я впевнений, що можна вдосконалити деякі поліпшення, але це хороший спосіб розпочати роботу. Крім того, легко створити цю функціональність без розширення об’єкта Route. Я зробив це, тому що це був найзручніший спосіб для моєї налаштування.

Я ще цього не перевірив повністю, тому, будь ласка, повідомте мене, якщо щось піде на південь.


ОНОВЛЕННЯ 25.04.2013

Я вніс деякі зміни у функцію, тому замість повернення ні хешу, ні імені зворотного виклику маршруту я повертаю об’єкт з фрагментом, парамами та маршрутом, щоб ви могли отримати доступ до всіх даних з поточного маршруту, як ви хочете з маршруту- подія.

Зміни ви можете побачити нижче:

current : function() {
    var Router = this,
        fragment = Backbone.history.fragment,
        routes = _.pairs(Router.routes),
        route = null, params = null, matched;

    matched = _.find(routes, function(handler) {
        route = _.isRegExp(handler[0]) ? handler[0] : Router._routeToRegExp(handler[0]);
        return route.test(fragment);
    });

    if(matched) {
        // NEW: Extracts the params using the internal
        // function _extractParameters 
        params = Router._extractParameters(route, fragment);
        route = matched[1];
    }

    return {
        route : route,
        fragment : fragment,
        params : params
    };
}

Дивіться попередній код для подальших коментарів та пояснень, вони виглядають здебільшого однаковими.


1
Я збирався написати це сам, але спочатку Гугл знайшов рішення. Радий, що зробив. Ваше робить саме те , що я хотів, дякую!
— Дан Абрамов

Ось трохи докладніша версія, яку, на мою думку, легше зрозуміти на перший погляд.
— Дан Абрамов

4
Нічого, дякую за це! Ви щойно отримали підтвердження в нашій кодовій базі. ; P Ми трохи підмітали це для Маріонетки. До речі, в якості ярлика ви можете встановити третій параметр (задає контекст) _.findфункції як this, тим самим усуваючи потребу в Routerзмінній (@DanAbramov зробив це вже).
— Марк

@Mark Це хороші новини. Але як я можу використовувати цю функцію в маріонеті? Про це в документах немає нічого.
— darksoulsong

2
@darksoulsong Якщо ви використовуєте Marionette.AppRouter, розширити маршрутизатор з функцією вище, але заміна Router.appRoutesдля Router.routes.
— Марк

11

Щоб отримати маршрут (або URL-адресу) виклику від оброблюваного маршруту, ви можете отримати його, перевіривши

Backbone.history.location.href ... повна URL-адреса
Backbone.history.location.search ... рядок запиту, починаючи з?

Я потрапив сюди в пошуках цієї відповіді, тому, мабуть, я повинен залишити те, що знайшов.


6

Якщо ви використовуєте кореневу настройку для маршрутизатора, ви також можете включити її, щоб отримати "справжній" фрагмент.

(Backbone.history.options.root || "") + "/" + Backbone.history.fragment

6

Ось трохи більше багатослівним (або, в залежності від вашого смаку, більш зручним для читання) версії відповіді Саймона :

current: function () {
  var fragment = Backbone.history.fragment,
      routes = _.pairs(this.routes),
      route,
      name,
      found;

  found = _.find(routes, function (namedRoute) {
    route = namedRoute[0];
    name = namedRoute[1];

    if (!_.isRegExp(route)) {
      route = this._routeToRegExp(route);
    }

    return route.test(fragment);
  }, this);

  if (found) {
    return {
      name: name,
      params: this._extractParameters(route, fragment),
      fragment: fragment
    };
  }
}

4

Якщо ви подивитесь на джерело для Router, ви побачите, що, коли маршрутизатор запускає подію, кажучи, що щось змінюється, він передає ім'я разом із ним як "route: name".

http://documentcloud.github.com/backbone/docs/backbone.html#section-84

Ви завжди можете підключити подію маршруту до маршрутизатора та зберегти його, щоб отримати поточний маршрут.


Гаразд, я здогадуюсь, це така штука "побудувала сама".
— Дрю Дара-Абрамс

Так, але ви не отримаєте routeподію, якщо trigger її немає true (рекомендується та за замовчуванням).
— Дан Абрамов
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.