65.9K
CodeProject 正在变化。 阅读更多。
Home

BackBone 教程 – 第 7 部分:理解 Backbone.js 路由和 History

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (15投票s)

2014年8月1日

CPOL

6分钟阅读

viewsIcon

65210

downloadIcon

1436

在本文中,我们将尝试理解路由在大型单页应用程序中的作用,以及如何使用路由根据请求的 URL 执行操作。

引言

在本文中,我们将重点介绍 Backbone.js 中的路由。我们将尝试理解路由在大型单页应用程序中的作用,以及如何使用路由根据请求的 URL 执行操作。

背景

我们使用 Web 应用程序已经超过 20 年了。这让我们习惯了网站提供的一些功能。其中一项功能是能够复制 URL 并用于查看我们之前查看过的确切应用程序区域。另一个例子是使用浏览器导航按钮来向前或向后导航页面。

当我们创建单页应用程序时,屏幕上只渲染一个页面。每个页面没有单独的 URL。浏览器不会为每个屏幕加载单独的页面。那么,即使有了单页应用程序,我们如何才能执行上述操作呢?答案是 Backbone 路由。

完整系列链接

  1. BackBone 教程 – 第 1 部分:Backbone.Js 简介[^]
  2. BackBone 教程 – 第 2 部分:理解 Backbone Models 的基础知识[^]
  3. BackBone 教程 – 第 3 部分:更多关于 Backbone Models[^]
  4. BackBone 教程 – 第 4 部分:使用 HTTP REST 服务对 BackboneJs Models 进行 CRUD 操作[^]
  5. BackBone 教程 – 第 5 部分:理解 Backbone.js Collections[^]
  6. BackBone 教程 – 第 6 部分:理解 Backbone.js Views[^]
  7. BackBone 教程 – 第 7 部分:理解 Backbone.js 路由和 History[^]
  8. BackBone 教程 – 第 8 部分:理解 Backbone.js Events[^]

Using the Code

Backbone 路由和 History 为我们提供了复制 URL 并使用它们来访问确切视图的机制。它还使我们能够将浏览器导航与单页应用程序结合使用。实际上,路由实现了深度复制 URL 的可能性,而 History 则实现了使用浏览器导航的可能性。

没有路由器的生活

让我们尝试创建一个不使用路由器的简单应用程序。让我们创建三个简单的视图,这些视图将根据用户的选择在应用程序的同一区域渲染。让我们创建 3 个非常简单的视图。

var View1 = Backbone.View.extend({
   
    initialize: function() {
        this.render();
    },

    render: function() {
        this.$el.html(this.model.get('Message') + " from the View 1"); 
        return this;
    }
});

var View2 = Backbone.View.extend({
   
    initialize: function() {
        this.render();
    },

    render: function() {
        this.$el.html(this.model.get('Message') + " from the View 2"); 
        return this;
    }
});

var View3 = Backbone.View.extend({
    
    initialize: function() {
        this.render();
    },

    render: function() {
        this.$el.html(this.model.get('Message') + " from the View 3"); 
        return this;
    }
});

现在,我们需要一个视图来包含这些视图,并在用户在屏幕上做出选择时渲染它们。

var ContainerView = Backbone.View.extend({
     myChildView: null,
     
     render: function() {
        this.$el.html("Greeting Area"); 

        this.$el.append(this.myChildView.$el); 
        return this;
    }
});

现在,让我们在 UI 上创建一个简单的 div,它将作为 ContainerViewel。然后,我们将在 UI 上放置三个按钮,让用户更改视图。以下代码显示了应用程序设置,该设置创建了容器视图以及当用户从屏幕中选择视图时将调用的函数。

var greeting = new GreetModel({ Message: "Hello world" });

var container = new ContainerView({ el: $("#AppContainer"), model: greeting });
var view1 = null;
var view2 = null;
var view3 = null;

function showView1() {
    if (view1 == null) {
        view1 = new View1({ model: greeting });
    }

    container.myChildView = view1;
    container.render();
}

function showView2() {
    if (view2 == null) {
        view2 = new View2({ model: greeting });
    }

    container.myChildView = view2;
    container.render();
}

function showView3() {
    if (view3 == null) {
        view3 = new View3({ model: greeting });
    }

    container.myChildView = view3;
    container.render();
}

现在让我们运行应用程序并查看结果。

当我们点击按钮时,我们可以看到实际的视图正在改变,但 URL 没有改变。这意味着我无法复制 URL 并直接跳转到任何视图。此外,第二个要注意的是,如果我们按下浏览器的后退按钮,应用程序将消失(因为它仍然是浏览器眼中的同一个单页)。

注意:请下载并运行示例代码以实际查看。

Hello Backbone 路由

现在,可以使用 Backbone 的 routesHistory 非常轻松地解决上述问题。所以,让我们先看看 Backbone 路由是什么。

Backbone 路由是简单的对象,它们处理 URL 中的传入路由值,然后调用任何函数。让我们为我们的应用程序创建一个非常简单的路由类。

var myRouter = Backbone.Router.extend({

});

在我们的路由类中,我们将不得不定义我们的应用程序将支持的路由以及我们希望如何处理它们。所以,首先,让我们创建一个简单的路由,其中只存在 URL。这通常是我们应用程序的起始页面。对于我们的应用程序,当路由中没有任何内容时,我们将打开 view1。然后,如果请求是针对任何特定视图,我们将简单地调用负责渲染相应视图的函数。

var myRouter = Backbone.Router.extend({
    
    greeting: null,
    container: null,
    view1: null,
    view2: null,
    view3: null,
    
    initialize: function() {
        this.greeting = new GreetModel({ Message: "Hello world" });
        this.container = new ContainerView({ el: $("#rAppContainer"), model: this.greeting });
    },

    routes: {
        "": "handleRoute1",
        "view1": "handleRoute1",
        "view2": "handleRoute2",
        "view3": "handleRoute3"
    },

    handleRoute1: function () {
        if (this.view1 == null) {
            this.view1 = new View1({ model: this.greeting });
        }

        this.container.myChildView = this.view1;
        this.container.render();
    },

    handleRoute2: function () {
        if (this.view2 == null) {
            this.view2 = new View2({ model: this.greeting });
        }

        this.container.myChildView = this.view2;
        this.container.render();
    },

    handleRoute3: function () {
        if (this.view3 == null) {
            this.view3 = new View3({ model: this.greeting });
        }

        this.container.myChildView = this.view3;
        this.container.render();
    }
});

现在这个路由类包含了处理 URL 请求和相应渲染视图的完整逻辑。不仅如此,我们还可以看到之前在全局作用域中编写的代码,即控制器和视图创建,所有这些都放在了路由中。这也意味着路由不仅为我们提供了可深度复制的 URL,还可以提供更多选项来获得更好的结构化代码(因为我们可以有多个路由类,每个路由类可以处理已定义路由的所有相应视图)。

Backbone History 和实例化路由

Backbone History 是一个全局路由器,它将跟踪历史记录并允许我们在应用程序中启用路由。要实例化一个路由并开始跟踪导航历史,我们只需创建路由类并调用 Backbone.history.start,让 Backbone 开始监听路由并管理历史。

$(document).ready(function () {
    router = new myRouter();
    Backbone.history.start();
})

调用和请求路由

路由可以从应用程序的其他部分调用,也可以由用户直接请求。

  1. 调用路由:应用程序想要导航到特定路由(可以通过调用 router.navigate('view1'); 来实现:
  2. 路由请求用户输入完全限定的 URL(这将无缝工作)

让我们运行应用程序并查看结果。

在路由中传递参数

我们也可以在路由中传递参数。让我们尝试创建一个新的路由,用户将以参数化的方式请求视图。参数可以定义为“route/:param”。

var myRouter = Backbone.Router.extend({

    greeting: null,
    container: null,
    view1: null,
    view2: null,
    view3: null,

    initialize: function () {
        this.greeting = new GreetModel({ Message: "Hello world" });
        this.container = new ContainerView({ el: $("#rAppContainer"), model: this.greeting });
    },

    routes: {
        "": "handleRoute1",
        "view/:viewid": "handleRouteAll"
    },

     handleRouteAll: function (viewid) {

        if (viewid == 1) {
            this.handleRoute1();
        }
        else if (viewid == 2) {
            this.handleRoute2();
        }
        else if (viewid == 3) {
            this.handleRoute3();
        }
    },

    handleRoute1: function () {
        if (this.view1 == null) {
            this.view1 = new View1({ model: this.greeting });
        }

        this.container.myChildView = this.view1;
        this.container.render();
    },

    handleRoute2: function () {
        if (this.view2 == null) {
            this.view2 = new View2({ model: this.greeting });
        }

        this.container.myChildView = this.view2;
        this.container.render();
    },

    handleRoute3: function () {
        if (this.view3 == null) {
            this.view3 = new View3({ model: this.greeting });
        }

        this.container.myChildView = this.view3;
        this.container.render();
    }   
});

可以通过将 view/2 作为 URL 来调用上述路由。传递给路由器的 viewId 将是 2

在路由中拥有可选参数

我们也可以在路由中传递可选参数。让我们尝试在上面定义的路由中传递一个简单的参数,看看它是如何工作的。可选参数可以定义为“route(/:param)”。

var myRouter = Backbone.Router.extend({

    routes: {
        "": "handleRoute1",
        "view1": "handleRoute1",
        "view2": "handleRoute2",
        "view3": "handleRoute3",
        "view/:viewid(/:msg)": "handleRouteAll"
    },

    handleRouteAll: function (viewid, msg) {

        if (msg) {
            alert(msg);
        }
    }
});

在上面的代码中,如果我们传递第二个参数,即 view/2/test,则会显示警报,否则不会。

注意:如果需要一个路由来根据某些正则表达式处理多个 URL,则路由定义也可以包含复杂的基于正则表达式的模式。

看点

在本文中,我们了解了 backbone.js 路由。我们了解了路由如何使我们能够创建可添加书签的 URL,并允许用户根据 URL 请求视图。我们还了解了如何使用 Backbone History 来利用浏览器导航。本文是从初学者的角度撰写的。希望对您有所帮助。

历史

  • 2014 年 8 月 1 日:第一个版本
© . All rights reserved.