Knockout.js 带有RequireJS的应用程序范围的状态

Knockout.js 带有RequireJS的应用程序范围的状态,knockout.js,requirejs,durandal-2.0,Knockout.js,Requirejs,Durandal 2.0,Durandal视图是AMD模块。shell是一个特例视图,也是一个模块 我的理解是,如果我编写一个模块来返回一个对象实例,那么我将在任何需要它的模块中获得对同一实例的引用;而对于返回构造函数的模块,将调用构造函数以生成私有实例 我有一个登录视图(惊喜,惊喜)来验证用户,并显示一个属性IsAuthenticated。这是一个可忽略的可观察项,各种UI都绑定到它,因此当login.IsAuthenticated()返回false时,您将获得登录UI,当它返回true时,您将获得身份验证作为先决条件

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

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

我有一个登录视图(惊喜,惊喜)来验证用户,并显示一个属性
IsAuthenticated
。这是一个可忽略的可观察项,各种UI都绑定到它,因此当
login.IsAuthenticated()
返回false时,您将获得登录UI,当它返回true时,您将获得身份验证作为先决条件的所有UI

所有这些都有效,但只有一次。当我添加注销功能,使服务器上的会话令牌过期,并在客户端设置
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());
    },
app.logout = login.logout;
check方法就在这里,因为在解决这个问题的过程中,我在shell中放置了一个调用check的按钮,告诉我
login.IsAuthenticated()
返回什么。实验结果表明,引用登录名的每个模块似乎都获得了一个副本,其中包含导入时的值

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


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

答案是将应用程序状态放在app对象中

根据Louis的观察,如果单例不起作用,则会出现问题,在shell viewmodel中声明对viewmodel的依赖关系存在问题

如果你这样做了,那么你最终会得到两份。我不知道为什么,但它确实发生了,正是这一点支撑了我所看到的所有怪异

如果你不能做到这一点,你能做什么

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

当然,在某些情况下,视图和视图模型允许用户操纵应用程序状态,如设置或身份验证

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

现在,shell视图确实要求在绑定阶段之前存在此可观察对象。它还需要绑定器范围内的app对象的名称,因此在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>

我不会在登录视图模型中包含身份验证逻辑。我将它作为一个独立的
安全
模块,可以被应用程序中的任何模块访问。当我在过去实现这种类型的东西时,我引用它作为指导。你说“我的理解是,如果我编写一个模块来返回一个对象实例,那么我将在任何需要它的模块中获得对同一实例的引用;[…]”是的,这正是RequireJS的工作方式。如果你得到了一些不同的东西,那么就有一些东西干扰了这个基本行为。
app.logout = login.logout;