【问题标题】:App-wide state with RequireJS使用 RequireJS 的应用程序范围的状态
【发布时间】:2014-07-18 11:24:28
【问题描述】:

Durandal 视图是 AMD 模块。 shell是一个特例视图,也是一个模块。

我的理解是,如果我编写一个模块来返回一个对象实例,那么我将在任何需要它的模块中获得对同一实例的引用;而对于返回构造函数的模块,构造函数将被调用以产生一个私有实例。

我有一个登录视图(惊喜,惊喜)验证用户并显示属性IsAuthenticated。这是一个可观察到的淘汰赛,并且各种 UI 都绑定到它,因此当login.IsAuthenticated() 返回 false 时,您将获得登录 UI,当它返回 true 时,您将获得以身份验证为先决条件的任何内容。

所有这些都有效,但只有一次。当我在服务器添加了一个使会话令牌过期并在客户端设置login.IsAuthenticated(false) 的注销功能时,所有成功响应登录的 UI 都完全无法响应注销。

注销功能是在 shell 中实现的,因为它是应用程序范围内的。 shell.js 的开头是这样的:

define(['plugins/router', 'knockout', 'config', 'viewModels/login'],
  function (router, ko, config, login) {
  var shell = {
    login: login,
    check: function () {
      alert(login.IsAuthenticated());
    },

check 方法在那里,因为在解决这个问题的过程中,我在 shell 中放置了一个按钮,调用 check 来告诉我 login.IsAuthenticated() 返回什么。实验结果表明,每个引用 login 的模块似乎都获得了一个副本,其中包含导入时的值。

我认为这里的问题是对 RequireJS 行为的误解。

实现这种应用范围状态的正确方法是什么?

【问题讨论】:

  • 我不会在登录视图模型中包含身份验证逻辑。我会将它作为一个单独的security 模块,应用程序中的任何模块都可以访问它。当我过去实现这类事情时,我参考了Durandal Auth 寻求指导。
  • 您说“我的理解是,如果我编写一个模块来返回一个对象实例,那么我将在任何需要它的模块中获得对同一实例的引用;[...]”是的,这正是 RequireJS 的工作原理。如果你得到一些不同的东西,那么就会有一些东西会干扰这种基本行为。

标签: knockout.js requirejs durandal-2.0


【解决方案1】:

答案是把app状态放在app对象中。

根据 Louis 的观察,如果单例不起作用,则会出现问题,在 shell 视图模型中声明对视图模型的依赖存在问题。

如果你这样做了,那么你最终会得到两个副本。我不知道为什么,但它确实发生了,这就是我所看到的所有奇怪现象的基础。

如果你不能做到这一点,那么可以做什么?

shell 实际上不需要引用任何视图模型。

当然,有时存在视图和视图模型以允许用户操作应用程序状态,例如设置或身份验证。

在这种情况下,信息实际上属于整个应用程序:应用程序对象就是模型。这不仅在逻辑上是正确的,而且使问题完全消失了。例如,我的登录视图模型现在由可观察的 app.IsAuthenticated() 支持,它已经在 shell 的范围内。

现在,shell 视图确实需要这个 observable 在绑定阶段之前存在。它还需要在绑定器范围内的应用程序对象的名称,因此我在 shell 实现中设置了这些名称。

define(['durandal/app', 'knockout', ...], (function (app, ko, ...) {

  app.IsAuthenticated = ko.observable();

  var shell = {
    app: app,
    ...
  };

  return shell;
}

鲍勃是你的叔叔!有了这个基础设施,您就可以使用如此薄的包装器来保护内容。

查看模型

define(['durandal/app'], function (app) {

  return {
    activeView: ko.computed(function () {
      return app.IsAuthenticated() ? 
        "viewmodels/upload-queue" : 
        "viewmodels/login";
    }, null)
  };

});

查看

<div data-bind="compose: activeView"></div>

请注意非常简单的占位符标记。回到 shell,我们现在可以很好地在标记中使用这些信息:

<div class="btn btn-default pull-right" 
     data-bind="click: app.logout, visible: app.IsAuthenticated">
  <i class="icon-signout" title="Log out"></i>
</div>

精明的读者会想知道应用程序是如何获得注销方法的。实际上这是登录对象的一个​​方法,它在登录视图模型模块中分配给应用程序,如下所示:

app.logout = login.logout;

【讨论】:

    猜你喜欢
    • 2020-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-28
    • 2017-01-15
    • 1970-01-01
    相关资源
    最近更新 更多