流星模板层次结构和路由逻辑冲突

Meteor template hierarchy and routing logic conflicting

我的应用程序由两个页面组成,主页和仪表板。在主页上,我想显示登录(顶部导航)和注册(主体)。如果用户已登录,则显示仪表板。在仪表板上,我想显示注销选项。注销时显示主页。

问题: 当我尝试更新仪表板模板时,所有内容最终都直接进入导航栏。同样令人困惑的是主页页面的正文内容仍在仪表板页面中呈现。我显然忽略了一些东西,但我无法判断这是我的代码错误还是我对模板和路由的理解错误。

正在使用:Iron-Router,Accounts-UI and Accounts-password,Twbs:bootstrap。

下面插入了三个主要模板 Master、Homepage 和 Dashboard。

在此先感谢您提供的任何帮助!

具有登录逻辑的主模板

<template name="MasterLayout">
    {{> yield}}
    <nav class="navbar navbar-inverse navbar-fixed-top">
    <div class="container">
      <div class="navbar-header">
        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
          <span class="sr-only">Toggle navigation</span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
        </button>
        <a class="navbar-brand" href="#">THE BRAND</a>
      </div>
      <div id="navbar" class="navbar-collapse collapse">
        {{#if currentUser}}
          {{> Dashboard}}
        {{else}}
          {{> Login}}
        {{/if}}
      </div><!--/.navbar-collapse -->
    </div>
  </nav>
</template>

主页包含主要内容

<template name="Homepage">
  <div class="jumbotron">
    <div class="container">
      <h1>Get it now..</h1>
      <p>Donec id elit</p>
      {{#if currentUser}}
        hello
      {{else}}
        {{> Register}}
      {{/if}}
    </div>
  </div>
</template>

仪表板包含一个占位符文本

<template name="Dashboard">
  <ul class="nav navbar-nav">
    <li class="navbar-text">Navigation Placeholder</li>
    <li><a href="#" class="logout">Logout</a></li>
  </ul>
</template>

我创建了以下控制器;

首页

HomepageController = RouteController.extend({
  layoutTemplate: 'MasterLayout',

  subscriptions: function() {
  },

  action: function() {
    this.render('Homepage');
  }
});

仪表板

DashboardController = RouteController.extend({
  layoutTemplate: 'Dashboard',

  subscriptions: function () {
  },

  data: function () {
  },

  action: function () {
    this.render('Dashboard', { /* data: {} */});
  }
});
  1. 在您的 DashboardController 中将 layoutTemplate: 'Dashboard', 更改为 layoutTemplate: 'MasterLayout',

  2. {{> Dashboard}} 将在那里呈现仪表板模板。然后,当您调用 this.render('Dashboard') 时,它也会呈现仪表板模板以代替 {{> yield}}。您告诉它在 2 个地方呈现相同的模板。因此,在您的 DashboardController 中,将 this.render('Dashboard', { /* data: {} */}); 更改为 this.render('Homepage', { /* data: {} */});.

您定义路由控制器的方式存在很多问题,但没有问题。当我第一次开始使用 Iron-Router 时,我也对如何正确设置它们感到困惑,但希望在我提供我的建议之后,事情对你来说变得更加清晰,就像我在使用 Iron-Router 一段时间后对我所做的那样.

首先,由于您似乎只打算使用一个名为 MasterLayout 的布局模板,我建议您在全局级别为您的应用程序定义布局模板,如下所示:

    Router.configure({
        layoutTemplate: 'MasterLayout'
    });

这确保 MasterLayout 模板用于所有路线,并且为用户当前所在的路线定义的模板将在该模板的 yield 区域中呈现。至于如何正确构建 MasterLayout 模板,因为您使用的是 Bootstrap navbar 结构,我建议您像这样构建 MasterLayout 模板:

    <template name="MasterLayout">
        <header>
            <nav class="navbar navbar-inverse navbar-fixed-top">
                <div class="container">
                    <div class="navbar-header">
                        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                            <span class="sr-only">Toggle navigation</span>
                            <span class="icon-bar"></span>
                            <span class="icon-bar"></span>
                            <span class="icon-bar"></span>
                        </button>
                        <a class="navbar-brand" href="#">THE BRAND</a>
                    </div>
                    <div id="navbar" class="navbar-collapse collapse">
                        {{> loginButtons align="right"}}
                    </div>
                </div>
            </nav>
        </header>
        <article>
            {{> yield}}
        </article>
    </template>

我建议将整个 navbar 构造放入 <header> 元素中,而将布局模板的 yield 区域放入 article 元素中。实际上,您可以将这两个不同的部分放入您想要的任何类型的标签中,但我建议这样做,以便正确利用 HTML5 标签并适当地分隔页面。

如前所述,yield 区域是将插入当前路由模板的位置。此外,为了使用 login/logout 按钮实现您的目标,只需将 {{> loginButtons}} 模板(由 Accounts-UI 包提供)引用放在 navbar也构建。它将对当前用户是登录还是注销做出反应,并相应地显示带有文本的相应按钮。如果您希望像我喜欢的那样将登录按钮对齐到 navbar 结构的右侧,您可以将 navbar-right class 添加到 <ul> 元素以及将 align="right" 属性添加到 {{> loginButtons}} 模板引用。这确保了当按钮被一直拉到页面的右边缘时,登录按钮将在按钮的左侧和页面上打开,而不是在页面的右侧和页面外打开。

为了实现您在上面指定的行为,我进一步建议定义两条路线,一条用于主页,一条用于仪表板,如下所示:

    Router.route('/', {
        name: 'Homepage',
        template: 'Homepage'
    });

    Router.route('/dashboard', {
        name: 'Dashboard',
        template: 'Dashboard'
    });

定义了这些路由后,您就可以定义它们在 template 选项中引用的两个模板(加上可能的子模板),如下所示:

    <template name="Homepage">
        ...
        {{> Register}}
        ...
    </template>

    <template name="Dashboard">
        ...
    </template>

    <template name="Register">
        ...
    </template>

老实说,在这种情况下,您真的不需要定义 Register 模板,因为它已经在单独的 Homepage 模板中定义,并且您考虑放入 Register 模板你可以直接放入 Homepage 模板并保存并发症。这两个路由及其关联模板将提供您在上面指定的两个不同页面。

完成这项工作后,剩下要做的就是创建适当的 Javascript,如下所示:

    Router.onBeforeAction(function() {
        if(!Meteor.user()) {
            this.redirect('Homepage');
        }  else {
            this.next();
        }
    });

    if(Meteor.isServer) {
        Accounts.onLogin({
            Router.go('Dashboard');
        });
    }

如果用户注销,代码的第一部分会将用户重定向到 Homepage 路由,而当用户登录时,代码的第二部分会将用户重定向到 Dashboard 路由。

实际上,您真的不需要像上面那样使用路由控制器。由于您只有两条路线,因此您只需像我一样定义两条路线并根据需要添加适当的选项即可轻松摆脱困境。

如果您还没有找到它,可以找到 Iron-Router 的一个很好的参考 here