1

我创建了一个 Sencha Touch 2 应用程序并构建了一个生产模式版本。但是,我在生产版本中遇到了一个大问题,它在手机/平板电脑模式下运行。

ST2 的当前配置文件实现似乎存在缺陷,因为即使您激活了特定配置文件,所有视图仍会加载。在我的应用程序中,我希望能够使用视图配置中的 xtype 别名指定视图,并拥有正确的视图用于在没有任何特殊编码的情况下加载的手机或平板电脑配置文件。如果加载了配置文件中的所有视图,那么这将不起作用(一个视图将始终覆盖另一个视图)。

我能做到这一点的唯一方法是在启动阶段(在 app.js 中)动态添加配置文件,如下所示:

Ext.application({
    name: 'MyTestApp',

    var activeProfile = Ext.os.is.Phone ? ['Phone'] : ['Tablet'];

    requires: [ ... ],

    profiles: activeProfile

});

这工作得很好。这意味着我可以加载正确的视图,并且仍然只在另一个视图的配置中使用 xtype 别名和/或控制器中的 ref。但是,我注意到当我生成生产版本并加载控制台窗口时,定义了以下两个:

MyTestApp.views.phone.Login
MyTestApp.views.tablet.Login

通常,平板电脑或手机版本将根据配置文件未定义。我假设是这种情况,因为生产模式构建已解析所有依赖项,然后包含所有视图,而不管配置文件如何。

所以在我的启动控制器中,我有一个按钮处理程序,然后从 xtype 创建一个登录视图。

控制器:

refs: {                
            loginView: {
                selector: 'loginview',
                xtype: 'loginview',
                autoCreate: true
            }
 }

处理程序:

var loginView = this.getLoginView();

在开发模式下,loginView 变量将是MyTestApp.views.tablet.LoginMyTestApp.views.phone.Login,具体取决于配置文件。

在生产模式下,如何确保此处实例化的登录视图根据配置文件获得正确的版本?

4

3 回答 3

2

我一直在为此苦苦挣扎,当我将任何一种解决方案移动到设备上时,我会被所有视图都引用的事实所困扰,并且总是会遇到一些 xtype 冲突给我电话视图。(我最终不得不改用别名——不知道为什么:()。我终于设法为我的用例破解了这个,只是分享以供将来参考。

我正在使用最新的 cmd 4.0.2.67 运行 touch 2.3.1 和 cordova 3.3.1

我使用 Christopher 的解决方案,除了我必须更改 sencha touch 源目录中的源代码,而不是将其保留在 app.js 中

此外,我必须按以下方式配置视图,以便:

  • define a base class for the view with an alias so the controller to understand the ref as it loads first
  • dynamically assign the alias to the view instantiated by the profile
  • strip out (using Christopher code)

Base class for the views

    Ext.define('MyApp.view.CatalogView', {
        extend: 'Ext.Container',
        alias: 'widget.catalogview'
    });        

Assign an alias to the profile specific view

    Ext.define('MyApp.profile.Phone', {
        extend: 'Ext.app.Profile',

        config: {
            name: 'Phone',
            views: ['CatalogView'],
        },

       isActive: function() {
           return Ext.os.is('Phone');
       },

       launch: function() {
           Ext.ClassManager.setAlias('MyApp.view.phone.CatalogView', 'widget.catalogview');
       }
    });

Repeat for the tablet view

于 2014-03-08T14:26:57.480 回答
1

对于所有想知道我是如何解决这个问题的人,我现在把头发都拔掉后就秃了;)

我希望 xtype 名称保持不变的所有配置文件视图,即使它们可能属于手机或平板电脑配置文件,我必须删除类上的别名/xtype 配置。然后,我使用共享辅助函数定义了一个配置文件基类:

Ext.define('MyApp.profile.Base', {
    extend: 'Ext.app.Profile',

    config: {

    },

    mapViewAliases: function () {
        var self = this;

        var views = this.getDependencies().view;
        var newAliasMap = null;

        Ext.each(views, function (view) {
            Ext.Array.some(self.getViewsToAliasMap(), function (map) {
                if (map[view]) {
                    if (!newAliasMap) {
                        newAliasMap = {};
                    }

                    newAliasMap[view] = [map[view]];                    
                    return true;
                }
            });
        });

        if (newAliasMap) {
            console.log('view aliases being mapped for: ' + this.$className);
            Ext.ClassManager.addNameAliasMappings(newAliasMap)
        }
    }
});

然后我有从基类继承的配置文件类(这与平板电脑配置文件重复,除了 viewsToAliasMap 包含属于平板电脑配置文件而不是手机配置文件的类):

Ext.define('MyApp.profile.Phone', {
    extend: 'MyApp.profile.Base',

    config: {
        name: 'Phone',
        views: ['Login', 'Home', 'Welcome' ],

        viewsToAliasMap: [
             { 'MyApp.view.phone.Login': 'widget.loginview' },
             { 'MyApp.view.phone.Home': 'widget.homeview' },
             { 'MyApp.view.phone.Welcome': 'widget.welcomeview' }
        ]
    },

    isActive: function () {
        return Ext.os.is.Phone;
    },

    launch: function () {
        console.log("Phone profile launched");

        this.mapViewAliases();

    }
});

所以基本上,配置文件在启动函数中调用基类上的函数 mapViewAliases()。mapViewAliases() 使用类管理器的配置文件中定义的别名注册视图类名称。因此,xtype 名称有效地在运行时解析。

我确信这段代码可以改进和/或更好的方法来做到这一点。请随时告诉我。

于 2013-04-23T21:35:11.530 回答
0

我正在使用一个非常幼稚的实现......我确信它可以变得更强大,但我已经在这个方面进行了 5 个小时左右的破解。

Ext.define('MyApp.override.Application', {
    override : 'Ext.app.Application',

    onProfilesLoaded: function() {
        var profiles  = this.getProfiles(),
            length    = profiles.length,
            instances = [],
            requires  = this.gatherDependencies(),
            current, i, profileDeps;

        for (i = 0; i < length; i++) {
            var instance = Ext.create(profiles[i], {
                application: this
            });

            /*
             * Note that we actually require all of the dependencies for all Profiles - this is so that we can produce
             * a single build file that will work on all defined Profiles. Although the other classes will be loaded,
             * the correct Profile will still be identified and the other classes ignored. While this feels somewhat
             * inefficient, the majority of the bulk of an application is likely to be the framework itself. The bigger
             * the app though, the bigger the effect of this inefficiency so ideally we will create a way to create and
             * load Profile-specific builds in a future release.
             *
             CMK - PSHAW!
             */

            if (instance.isActive() && !current) {
                console.log('Profile active: ' + instance.getName());
                current = instance;

                profileDeps = instance.getDependencies();
                requires = requires.concat(profileDeps.all);
                var ns = instance.getNamespace();

                this.setCurrentProfile(current);

                // Merge Controllers, Models, Stores, and Views
                this.setControllers(this.getControllers().concat(profileDeps.controller));
                this.setModels(this.getModels().concat(profileDeps.model));
                this.setStores(this.getStores().concat(profileDeps.store));
                this.setViews(this.getViews().concat(profileDeps.view));

                // Remove the view ref and requires for default views, when a profile specific one exists
                Ext.each(profileDeps.view, function(className) {
                    if (className.indexOf('view.' + ns + '.') !== -1) {

                        // Requires
                        var index = requires.indexOf(className.replace('view.' + ns, 'view'));
                        if (index !== -1) {
                            requires.splice(index, 1);
                        }
                        // Views
                        index = this.getViews().indexOf(className.replace('view.' + ns, 'view'));
                        if (index !== -1) {
                            this.getViews().splice(index, 1);
                        }
                    }
                }, this);

                instances[0] = instance;
                break;
            }
        }

        this.setProfileInstances(instances);
        Ext.require(requires, this.loadControllerDependencies, this);
    }
});

把它放在你的 Ext.application 之前,它会替换配置文件加载器...这个删除与活动配置文件命名空间中同名的默认视图。

它要求您为匹配的视图定义一个 xtype,然后即使您在控制器中的 refs 也可以工作......

我需要继续对此进行测试,但到目前为止它看起来很有希望。

于 2013-09-25T06:57:24.390 回答