Backbone.js: có được tuyến đường hiện tại


137

Sử dụng Backbone, tôi có thể lấy tên của tuyến đường hiện tại không? Tôi biết cách liên kết với các sự kiện thay đổi tuyến đường, nhưng tôi muốn có thể xác định tuyến đường hiện tại vào các thời điểm khác, giữa các thay đổi.


Theo "tên", bạn có nghĩa là chức năng mà tuyến đường đó liên kết hoặc chỉ phần URL hoặc phần băm hiện tại của URL là gì?
John Munsch

1
Ồ, vâng, tôi nên đã được cụ thể hơn. Tôi muốn biết tên của chức năng. (Tôi biết cách lấy phần băm của URL bằng cách thực hiện location.hash hoặc Backbone.history.fragment.)
Drew Dara-Abrams

Câu trả lời:


209

Nếu bạn đã khởi tạo Bộ định tuyến trong ứng dụng của mình, dòng sau sẽ trả về đoạn hiện tại:

Backbone.history.getFragment();

Từ tài liệu Backbone.js :

"[...] Lịch sử đóng vai trò là bộ định tuyến toàn cầu (trên mỗi khung) để xử lý các sự kiện trao đổi băm hoặc PushState, khớp với lộ trình phù hợp và kích hoạt các cuộc gọi lại. Bạn không nên tự mình tạo một trong số đó - bạn nên sử dụng tham chiếu tới Backbone.history sẽ được tạo tự động cho bạn nếu bạn sử dụng Bộ định tuyến với các tuyến đường. [...] "

Nếu bạn cần tên của hàm bị ràng buộc với đoạn đó, bạn có thể tạo một cái gì đó như thế này trong phạm vi của Bộ định tuyến của bạn:

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

Hoặc như thế này từ bên ngoài bộ định tuyến của bạn:

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

Cảm ơn, điều đó thật tuyệt. Tôi dường như chưa bao giờ đề cập đến Backbone.history.fragment trong tài liệu. Đây có phải là một bổ sung mới, hoặc chỉ là không có giấy tờ?
Drew Dara-Abrams

Tôi nghĩ rằng điều này là không có giấy tờ. Trên thực tế, tôi không nhớ lần đầu tiên tôi nhìn thấy nó ở đâu, một số blog hoặc có lẽ là mã nguồn xương sống.
Robert

25
FYI, điều này không hoạt động với các tuyến đường như 'foo /: id' hoặc 'bar * params'
wprl

2
Sử dụng tốt hơn Backbone.history.getFragment(), bởi vì Backbone.history.fragmentlà một tài sản ẩn riêng tư.
Vad

1
Tôi đã sửa câu trả lời sau gợi ý @Vad. Tôi không sử dụng Backbone nữa nhưng nhận xét của anh ấy có vẻ đúng với tôi. (Câu trả lời trước đó là: Backbone.history.fragment thay vì Backbone.history.getFragment ())
Robert

57

Câu trả lời của Robert rất thú vị, nhưng thật đáng buồn, nó sẽ chỉ hoạt động nếu hàm băm chính xác như được xác định trong tuyến đường. Ví dụ, nếu bạn có một tuyến đường cho user(/:uid)nó sẽ không được khớp nếu đó Backbone.history.fragment"user"hoặc "user/1"(cả hai trường hợp sử dụng rõ ràng nhất cho tuyến đường đó). Nói cách khác, nó sẽ chỉ tìm thấy tên gọi lại phù hợp nếu hàm băm chính xác "user(/:uid)"(rất khó xảy ra).

Vì tôi cần chức năng này, tôi đã mở rộng Backbone.Routervới một currentchức năng sử dụng lại một số mã mà đối tượng Lịch sử và Bộ định tuyến sử dụng để khớp với đoạn hiện tại so với các Tuyến được xác định để kích hoạt cuộc gọi lại thích hợp. Đối với trường hợp sử dụng của tôi, nó nhận tham số tùy chọn route, nếu được đặt thành bất kỳ giá trị trung thực nào sẽ trả về tên hàm tương ứng được xác định cho tuyến. Nếu không, nó sẽ trả về đoạn băm hiện tại từ Backbone.History.fragment.

Bạn có thể thêm mã vào Mở rộng hiện tại nơi bạn khởi tạo và thiết lập bộ định tuyến đường trục.

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'

Tôi chắc chắn một số cải tiến có thể được thực hiện, nhưng đây là một cách tốt để giúp bạn bắt đầu. Ngoài ra, thật dễ dàng để tạo chức năng này mà không cần mở rộng đối tượng Tuyến đường. Tôi đã làm điều này bởi vì đó là cách thuận tiện nhất cho việc thiết lập của tôi.

Tôi chưa thử nghiệm điều này đầy đủ, vì vậy xin vui lòng cho tôi biết nếu có bất cứ điều gì đi về phía nam.


CẬP NHẬT 25/11/2013

Tôi đã thực hiện một số thay đổi cho hàm, vì vậy thay vì trả về tên gọi lại hàm băm hoặc tuyến đường, tôi trả về một đối tượng có đoạn, thông số và tuyến để bạn có thể truy cập tất cả dữ liệu từ tuyến hiện tại, giống như bạn đi từ tuyến đường- biến cố.

Bạn có thể thấy những thay đổi dưới đây:

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
    };
}

Xem mã trước để biết thêm nhận xét và giải thích, chúng trông giống nhau.


1
Đã định viết cái này cho mình, nhưng Googled cho giải pháp đầu tiên. Vui vì tôi đã làm. Bạn làm chính xác những gì tôi muốn, cảm ơn!
Dan Abramov

Đây là một phiên bản dài hơn một chút mà tôi tin là dễ hiểu hơn từ cái nhìn đầu tiên.
Dan Abramov

4
Wow, cảm ơn vì điều này! Bạn vừa nhận được một xác nhận trong cơ sở mã của chúng tôi. ; P Chúng tôi tinh chỉnh nó một chút cho Marionette. Nhân tiện, như một phím tắt, bạn có thể đặt tham số thứ ba (đặt bối cảnh) của _.findhàm là this, do đó loại bỏ sự cần thiết của Routerbiến (@DanAbramov đã làm điều này rồi).
Đánh dấu

@Mark Đây là những tin tốt. Nhưng làm thế nào tôi có thể sử dụng tính năng này trong marionette? Không có gì về nó trong các tài liệu.
darksoulsong

2
@darksoulsong Nếu bạn đang sử dụng Marionette.AppRouter, hãy mở rộng bộ định tuyến của bạn với chức năng trên, nhưng thay thế Router.appRoutescho Router.routes.
Đánh dấu

11

Để nhận tuyến gọi (hoặc url) từ trình xử lý tuyến được gọi, bạn có thể nhận tuyến bằng cách kiểm tra

Backbone.history.location.href ... url đầy đủ
Backbone.history.location.search ... chuỗi truy vấn bắt đầu từ đâu?

Tôi đã đến đây trong quá trình tìm kiếm câu trả lời này vì vậy tôi đoán tôi nên để lại những gì tôi đã tìm thấy.


6

Nếu bạn sử dụng cài đặt gốc cho Bộ định tuyến, bạn cũng có thể bao gồm nó để lấy đoạn 'thực'.

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

6

Dưới đây là một chút dài dòng hơn (hoặc tùy theo khẩu vị của bạn, dễ đọc hơn) phiên bản của câu trả lời của Simon :

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

Nếu bạn nhìn vào nguồn cho Router, bạn sẽ thấy rằng khi bộ định tuyến kích hoạt sự kiện nói rằng có gì đó thay đổi, nó sẽ chuyển tên với tên là "tuyến đường: tên".

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

Bạn luôn có thể nối sự kiện "tuyến đường" trên bộ định tuyến và lưu trữ để có được tuyến đường hiện tại.


OK, tôi đoán đây là một loại "tự xây dựng".
Drew Dara-Abrams

Vâng, nhưng bạn sẽ không nhận được routesự kiện nếu trigger không true (được khuyến nghị & mặc định).
Dan Abramov
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.