流星:使用 2 种不同的布局(铁:路由器)

Meteor: use 2 different layouts (iron:router)

我想在客户端上呈现两种不同的布局。

Router.route('/',  {
    template: 'register',
    layoutTemplate: 'home'
});

Router.route('/main', {
    layoutTemplate: 'layout'
});

在这种情况下,只有第一个 Router.route 函数有效。此代码示例中似乎存在什么问题?

在控制台中,弹出这个错误:

Exception in defer callback: TypeError: Cannot read property 'handler' of undefined

此外,我不希望用户在未登录的情况下访问 'main' 模板。iron:router documentation 没有向我提供有关如何处理这两个问题的足够信息。

我的猜测是您还需要为 '/main' 路由定义模板——这就是您的错误中的 undefined。如果您有一个带有 name="main" 属性的模板,我需要查看更多代码,尤其是任何模板处理程序。

重定向可以通过 onBeforeAction 回调完成:

onBeforeAction: function() {
    if (!Meteor.userId()) {
        this.redirect('/');
    } else {
        this.next();
    }
}

这是您的路线的外观。

 //Layout Configuration.
    Router.configure({
      layoutTemplate:"register"
    });

    Router.configure({
      layoutTemplate:"layout"
    });

   //Simple Routes Config.
    Router.route('/',  {
        layoutTemplate: 'register'
    });

    Router.route('/main', {
        layoutTemplate: 'layout'
    });

/client/views/layout.html

<template name="layout">
  {{> yield}}
</template>

<template name="register">
  {{> yield}}
</template>

我绝对认为您上面的路由代码的问题在于您没有为路径 '/main' 的路由的 template 属性指定值。至少,我建议您为给定路由定义该属性(如果没有其他属性的话)。 Iron-router 尝试确定路由使用哪个模板的第一件事是查看 URL 的路径,这对于给定路由的确定并不总是显而易见的。我建议像这样定义上面的路线:

    Router.route('/', function() {
        template: 'register',
        layoutTemplate: 'home'
    });

    Router.route('/main', function() {
        template: 'main',
        layoutTemplate: 'layout'
    });

定义了此路由逻辑后,您还需要确保正确定义模板。

对于布局模板,执行如下操作:

    <template name="home">
        {{> yield}}
    </template>

    <template name="layout">
        {{> yield}}
    </template>

布局模板中的 {{> yield}} 部分是必需的,因为 iron-router 将在此处呈现您通过 template 属性为路由定义的模板。

对于您的常规模板,执行如下操作:

    <template name="register">
        <h1>Register</h1>
    </template>

    <template name="main">
        <h1>Main</h1>
    </template>

这样做之后,您的路由是否有效?或者,您可以使用 Route.configure 设置全局路由属性,或使用一系列 RouteController 对象来定义您的路由,以便公共路由可以利用公共属性定义。

关于你的第二个问题,我建议使用以下两种方法之一:

为了仅针对 '/main' 路由定义您描述的逻辑,请执行以下操作:

    Router.route('/main', function() {
        template: 'main',
        layoutTemplate: 'layout',
        onBeforeAction: function() {
            if(!Meteor.userId()) {
                this.render('register'); // Use either this one
                this.redirect('register'); // or this one
            } else {
                this.next();
            }
        }
    });

使用此选项需要您向 '/' 路由 name: 'register' 添加一个附加属性。或者,您可以在 this.render()this.redirect() 函数调用中直接引用所需路由的实际 URL 路径,然后您不必为模板定义 name 属性.就个人而言,我更喜欢通过给它们所有名称并使用它们的名称引用它们来明确和公开我的路由定义。

第二个选项是全局定义您想要的逻辑,这样它不仅适用于 '/main' 路由,而且适用于您将来碰巧定义的任何其他路由。为此,请执行以下操作:

    Router.onBeforeAction(function() {
        if(!Meteor.userId()) {
            this.render('register'); // Use either this one
            this.redirect('register'); // or this one
        } else {
            this.next();
        }
    },
    {
        except: ['register']
    });

再次强调,此选项需要为您的 '/' 路由定义 name 属性,但如果您不想那样做,也可以按照我上面描述的方式进行。最后,请注意此选项末尾的 except 属性定义。这会通知 iron-router 不要 运行 指定路由数组的全局定义逻辑。显然,您不希望在将当前未登录的用户重定向到的页面上 运行 此逻辑,因此我上面的 except 属性定义。