使用路由-Controlling an Application with Router

对于一个常规网站,用户通过点击链接或者填写表单等在不同的页面间跳转。但是,对于一个单页面应用来说,用户的一次交互不会加载新的页面。相反,是在一个页面内进行处理,由组件对用户的交互做出响应。那么如何还能让用户继续使用浏览器的前进和后退按钮呢?答案就是通过 Ext JS 的 Router 来处理 URI 的 hash 变更。

用路由做什么-What Routing Is Used For

路由通过利用浏览器的历史记录,可以用来跟踪应用程序的状态。路由还可以深入链接到应用程序的某个特定部分。

不用路由做什么-What Routing Is Not Used For

不应该使用路由存储任何数据或会话,数据应该持久化存储在数据源中,例如: cookielocalstorage 。路由只是跟踪应用程序状态的一种方式。

什么是Hash-What is the Hash?

浏览器使用 URI 进行导航,URI 由许多部分组成。一个简单的 URI 如下:

http://www.example.com/apps/users#user/1234

这个相对熟悉。但是,你可能不能识别 #user=1234。 URI 的这部分信息称为 hash 或者片段标识(fragment identifier)。hash 提供了一种方式,不用重新加载当前页面就可以控制浏览器的历史记录。一旦 hash 变了,浏览器将整个 URI 添加到历史记录中,这样就可以使用浏览的前进或者后退按钮进行导航了。例如,如果改变了 hash 的值,会发生什么:

http://www.example.com/apps/users#user/5678

浏览器触发一个 hashchange 事件,我们可以在应用程序中利用这个事件。

如果用户点击后退按钮,就会回到第一个示例的地址 #user=1234。这个事件通知允许在应用程序中对变更作出响应。需要注意一点,hash 不发送到服务器端,只是在客户端扮演 URI 的作用。 Ext JS Router 依靠浏览器的 hash 功能实现应用程序的状态跟踪和深度链接。

实现路由-Implement Routing in your Application

Router 类是 Ext JS 5 新增的功能,使得在 MVC 应用程序中,很容易处理 hash 的变更、解释和处理。还有 Ext.util.History 类,也可以用于处理 hash 变更,但是它提供更多的手动处理,并且还需要一个 Router 类。 Router 类可以通过在视图控制器中定义的路由,很容易与 MVC 应用集成在一起。一个路由是一个与 hash 对应的字符串,在 Ext 应用中可以进行深度的链接。例如:

Ext.define('MyApp.view.main.MainController', {
    extend : 'Ext.app.ViewController',

    routes : {
        'users' : 'onUsers'
    },

    onUsers : function() {
        //...
    }
});

这个路由响应 #users hash,将在控制器实例的作用域内调用 onUsers 方法。

更新Hash-Updating the Hash

可以利用控制器的 redirectTo 方法更新 Hash:

this.redirectTo('user/1234');

该示例修改 hash 为 #user/1234,能够识别该 hash 的配置方法将被调用。可能当前的 hash 与要更改的 hash 相同,这时 redirectTo 方法返回 false,并且不会执行对应的规则。 redirectTo 方法还可以接收第二个参数,如果传递 true 可以强制路由响应 hash 值。

this.redirectTo('user/1234', true);

即使当前的 hash 与传递的 hash 相同,Router 也将执行匹配的规则。

缺省路由-Default Token

当应用程序启动时,如果未提供 hash 值,可以配置缺省的 hash 值。例如:当 hash 值为 #home 时显示仪表板功能,可以在没有 hash 值时缺省使用 #home 。 想要使用缺省 hash 值,可以设置 /app/view/Application.js 文件中的 defaultToken 配置属性:

Ext.define('MyApp.Application', {
    extend : 'Ext.app.Application',

    //...

    defaultToken : 'home'
});

路由参数-Hashes with Parameters

应用程序可以在 hash 中定义参数。例如,用户标识可以放置在 hash 值中,之前示例中提到过的 #user/1234。这种情况下,我们可能希望 1234 作为 id 参数,可以如下设置控制器的路由规则:

Ext.define('MyApp.view.main.MainController', {
    extend : 'Ext.app.ViewController',

    routes : {
        'user/:id' : 'onUser'
    },

    onUser : function(id) {
        //...
    }
});

路由设置为 'user/:id' 和冒号 :。 这表示有一个参数需要传递给目标方法。方法接收参数的数量和顺序同路由中定义的数量和顺序一致。

参数格式化-Hash Parameter Formatting

应用程序可能需要强制约束用户标识(User ID)的格式。例如:我们希望是一个数字。可以使用一个对象来定义路由,并且设置 conditions 配置属性:

Ext.define('MyApp.view.main.MainController', {
    extend : 'Ext.app.ViewController',

    routes : {
        'user/:id' : {
            action     : 'onUser',
            conditions : {
                ':id' : '([0-9]+)'
            }
        }
    },

    onUser : function(id) {
        //...
    }
});

首先,'onUser' 方法放置在 action 配置属性中,这与之前使用字符串的方式类似。然后,使用对象定义一个 conditions 配置属性,要控制的关键字是冒号加参数名 :id,值是正则表达式(Regular Expression)字符串(不是正则表达式对象)。例如: 对于 :id 我们使用 ([0-9]+) 。之所以使用正则表达式字符串,是因为正则表达式对象用于匹配整个 hash 值。如果存在多个参数,我们需要将正则表达式字符串连接在一起组成一个正则表达式对象。如果没有为参数指定条件,使用如下缺省值:

([%a-zA-Z0-9\\-\\_\\s,]+)

路由处理-Route Handling

应用程序有时需要阻止路由的处理。例如:我们需要检查用户授权,判断当前用户是否能够查阅指定的程序功能。路由需要配置一个前置的操作,可以终止当前的路由,终止所有路由,或者继续执行路由。例如:

Ext.define('MyApp.view.main.MainController', {
    extend : 'Ext.app.ViewController',

    routes : {
        'user/:id' : {
            before  : 'onBeforeUser',
            action  : 'onUser'
        }
    },

    onBeforeUser : function(id, action) {
        Ext.Ajax.request({
            url     : '/security/user/' + id,
            success : function() {
                action.resume();
            }
        });
    },

    onUser : function(id) {
        //...
    }
});

onBeforeUser 方法中,接收 :id 参数,最后一个参数是 action。如果调用 actionresume 方法,路由将继续执行,调用 onUser 方法。 请注意,可以等待 AJAX 请求处理完成后再继续路由的处理。

扩展一下这个示例,调用 stop 方法终止路由:

Ext.define('MyApp.view.main.MainController', {
    extend : 'Ext.app.ViewController',

    routes : {
        'user/:id' : {
            before  : 'onBeforeUser',
            action  : 'onUser'
        }
    },

    onBeforeUser : function(id, action) {
        Ext.Ajax.request({
            url     : '/security/user/' + id,
            success : function() {
                action.resume();
            },
            failure : function() {
                action.stop();
            }
        });
    },

    onUser : function(id) {
        //...
    }
});

Ext JS 应用可能很复杂,可能存在多个控制器监听同一个路由。但是,只有一个控制器可以设置 before 配置属性,所以只有一个 ajax 请求。如果传递 trueactionstop 方法,将终止队列中所有请求处理的路由,不只是当前的路由处理:

Ext.define('MyApp.view.main.MainController', {
    extend : 'Ext.app.ViewController',

    routes : {
        'user/:id' : {
            before  : 'onBeforeUser',
            action  : 'onUser'
        }
    },

    onBeforeUser : function(id, action) {
        Ext.Ajax.request({
            url     : '/security/user/' + id,
            success : function() {
                action.resume();
            },
            failure : function() {
                action.stop(true);
            }
        });
    },

    onUser : function(id) {
        //...
    }
});

现在,当 Ajax 请求失败时, 我们传递 true 来终止所有控制器针对此路由的处理。

注意:如果没有执行 resumestop 方法,路由将被终止,而且不会正常结束。所以切记要在同一个地方,调用 resumestop 方法。

处理不匹配的路由-Handling Unmatched Routes

如果 hash 变更了,但是没有找到匹配的路由, Router 将没有任何处理动作,它不会尝试修改 hash,继续保留不匹配的 hash。Router 将触发应用程序实例的 unmatchedroute 事件,可以在 Ext.application 调用时配置该事件的监听:

Ext.application({
    name : 'MyApp',

    listen : {
        controller : {
            '#' : {
                unmatchedroute : 'onUnmatchedRoute'
            }
        }
    },

    onUnmatchedRoute : function(hash) {
        //...
    }
});

在一个Hash中使用多个路由-Using Multiple Routes in a Single Hash

由于 Ext JS 应用可能非常复杂,有时需要在单一 hash 中使用多个路由。 Router 不需要额外的设置就可以处理。只需要用管道符 | 分隔 hash 值,例如:

`#user/1234|messages`

在这个示例中,我们想要显示 1234 用户的详细信息,同时也显示提示信息。hash 中定义的每个路由都将按照定义的顺序执行。然后它们之间就相互隔离了。换句话说,如果停止 user/1234 路由,messages 路由还将继续执行。要注意路由是按照在 hash 中定义的顺序执行的。上述示例中,user/1234 路由总是在 messages 路由之前执行。

可以通过设置 Ext.app.route.RoutermultipleToken 属性改变缺省的分隔符。

results matching ""

    No results matching ""