【问题标题】:How can I use a class for my shell viewmodel in Durandal?如何在 Durandal 中为我的 shell 视图模型使用一个类?
【发布时间】:2013-03-31 10:24:18
【问题描述】:

我正在查看 Hot Towel 模板,并试图让它在 TypeScript 中工作,我在转换 shell 视图模型时遇到了问题。我正在尝试将其翻译成 TS,对我来说它应该是一个类更有意义,而不是简单地导出函数,如 here 所示。我看了this approach,但是关注了cmetshere,决定不关注了。

经过一番挖掘,我找到了this thread,这表明它应该像覆盖router.getActivatableInstance 一样简单,但我似乎还远远不够,无法调用该函数。

这是我的main.ts(也在课堂上):

/// <reference path="dts/toastr.d.ts" />
/// <reference path="dts/durandal.d.ts" />
/// <reference path="dts/require.d.ts" />

import _app = module('durandal/app');
import _system = module('durandal/system');
import _viewLocator = module('durandal/viewLocator');
import _router = module('durandal/plugins/router');
import _logger = module('services/logger');

export class HOPS {

    public init(): void {
        _logger.log('init', this, 'HOPS', false);
        _system.debug(true);
        this._startApp();
    }

    private _startApp(): void {
        _logger.log('_startApp', this, 'HOPS', false);

        _app.start().then(() => {
            toastr.options.positionClass = 'toast-bottom-right';
            toastr.options.backgroundpositionClass = 'toast-bottom-right';

            var defImpl = _router.getActivatableInstance; //default Implementation

            _router.getActivatableInstance = function (routeInfo: _router.routeInfo, paramaters: any, module: any) {
                var functionName = routeInfo.name.substring(0, 1).toUpperCase() + routeInfo.name.substring(1);
                if (typeof module [functionName] == 'function') {
                    var instance = new module [functionName]();
                    instance.__moduleId__ = module.__moduleId__;
                    return instance;
                }
                else return defImpl(routeInfo, paramaters, module );
            }

            _router.handleInvalidRoute = (route: _router.routeInfo, paramaters: any) => {
                _logger.logError('No Route Found', route, 'main', true);
            }

            _router.useConvention();
            _viewLocator.useConvention();

            _app.adaptToDevice();

            _app.setRoot('viewmodels/shell', 'entrance');
        });
    }
}

var hops: HOPS = new HOPS();
hops.init();

(此处显示 JS 的游乐场:http://bit.ly/WyNbhn

...这是我的shell.ts

import _system = module('durandal/system');
import _router = module('durandal/plugins/router');
import _logger = module('services/logger');

export class Shell{

    public router = _router;

    public activate(): JQueryPromise {
        _logger.log("activate", null, 'shell', false);
        return this.boot();
    }

    public boot(): JQueryPromise {
        _logger.log("boot", null, 'shell', false);
        this.router.mapNav('home')
        this.router.mapNav('details');
        _logger.log('SciHops SPA Loaded!', null, _system.getModuleId(this), true);
        return this.router.activate('home');
    }
}

...编译为:

define(["require", "exports", 'durandal/system', 'durandal/plugins/router', 'services/logger'], function(require, exports, ___system__, ___router__, ___logger__) {
    /// <reference path="../dts/_references.ts" />
    var _system = ___system__;

    var _router = ___router__;

    var _logger = ___logger__;

    var shell = (function () {
        function shell() {

            this.router = _router;
        }
        shell.prototype.activate = function () {
            _logger.log("activate", null, 'shell', false);
            return this.boot();
        };
        shell.prototype.boot = function () {
            _logger.log("boot", null, 'shell', false);
            this.router.mapNav('home');
            this.router.mapNav('details');
            _logger.log('SciHops SPA Loaded!', null, _system.getModuleId(this), true);
            return this.router.activate('home');
        };
        return shell;
    })();
    exports.shell = shell;    
})

使用上面的类,我收到绑定错误,因为 router 未定义。如果我添加export var router = _router,那么这个错误就会消失,但我的 shell 类上的 activate 方法永远不会被调用。

以上所有方法都适用于后续视图模型,但只是落在了外壳上。

我做错了什么,如何让 TS 类作为我的 shell Durandal 视图模型工作?

【问题讨论】:

  • 为什么你更喜欢导出类而不是函数?在打字稿中,我将 class' 视为获得继承的一种方式。您是否需要将您的外壳和主文件作为类'?通过让他们上课,你有什么好处?
  • 正是为了继承。我倾向于为许多不同的客户(或有时为一个客户构建几个相关的应用程序)构建类似的应用程序。这些应用程序的外壳可能具有共同的功能 - 我想将它们放入基类并根据需要覆盖/扩展。它不如将其他视图模型作为类重要(在一个简单的测试应用程序中,我已经有一个基础 vm 类在做常见的工作),但如果有它会很好。
  • gotchya,我很快就会调查一下,我最近很忙,但如果没有其他人回答,我明天会尝试调查。
  • Evan - 非常感谢,不用着急 - 当然,它的功能非常好。

标签: javascript typescript durandal


【解决方案1】:

问题是您的路由器没有解析您的shell.ts 模块。

您的所有其他视图模型都通过router.getActivatableInstance 方法并正在被实例化并带有__moduleId__ 附加到它们。除了你的shell.ts 模块。

这是让您的shell.ts 模块工作的快速而肮脏的方法。

在您的 main.ts 中,您可以要求您的 shell.ts 模块:

import _shell = module('shell');

然后,仍然在您的 main.ts 中,您可以实例化您的 shell 类并为其分配 moduleId。

var shell = new _shell.Shell();
shell.__moduleId__ = _shell.__moduleId__;
_app.setRoot(shell, 'entrance');

不是你见过的最漂亮的东西。但它可以完成工作。这与getActivatableInstance 覆盖您所做的几乎相同。由于您的shell 没有通过router.js 模块,因此您必须手动执行。

【讨论】:

  • Evan - 谢谢你,祝贺 Durandal:真是令人印象深刻的工作。
  • Rob Eisenberg 写了 durandal,我只是尝试帮助他人的早期采用者 :)
  • 那么恭喜你采用了这么好的框架(我向 Rob 道歉......)
【解决方案2】:

另一种选择是将类导出为 Duranal 的模块。 注意:此方法也适用于视图模型。

一个基于 nuget 的“Durandal Starter Kit”的工作示例:

    import router = require('plugins/router')
    import app = require('durandal/app')

    class Shell {
        router =  router;
        public search() {
            //It's really easy to show a message box.
            //You can add custom options too. Also, it returns a promise for the user's response.
            app.showMessage('Search not yet implemented...');
        }
        public activate() {
            router.map([
                { route: '', title: 'Welcome', moduleId: 'viewmodels/welcome', nav: true },
                { route: 'flickr', moduleId: 'viewmodels/flickr', nav: true },
            ]).buildNavigationModel();


            return router.activate();
        }
    }

    // Magic happens here:
    export = Shell;

原始 'js' 代码:

    define(['plugins/router', 'durandal/app'], function (router, app) {
        return {
            router: router,
            search: function() {
                //It's really easy to show a message box.
                //You can add custom options too. Also, it returns a promise for the user's response.
                app.showMessage('Search not yet implemented...');
            },
            activate: function () {
                router.map([
                    { route: '', title:'Welcome', moduleId: 'viewmodels/welcome', nav: true },
                    { route: 'flickr', moduleId: 'viewmodels/flickr', nav: true },
                ]).buildNavigationModel();


                return router.activate();
            }
        };
    });

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-29
    • 1970-01-01
    • 2021-12-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多