EmberJS应用程序 - 结构等等

时间:2013-02-19 22:21:29

标签: javascript model-view-controller ember.js

在准备大型项目期间,我正在研究一些JS MV *框架,这些框架将由团队与大约10名开发人员一起使用。
首先我尝试了AngularJS,因为它的性能看起来是所有框架中最好的(SO topic)。它有一些很好的未来像DI,但我真的不喜欢用它,因为对我而言,它有点乱码,难以理解,我喜欢尽可能清洁的代码,结构良好,易于使用读。

目前我正在尝试使用EmberJS,它看起来像是ember,非常适合开发人员,并且很容易使用它。所以我写了一个小的“登录小部件”,看看应该如何构建ember应用程序。在开发过程中,我试图解决一些问题,如异步请求,动画等......

JsFiddle

“小部件”已经工作并完成我希望他做的所有事情,但此时,我仍然有一些问题,我想听听有经验的ember开发人员关于当前代码结构,对象角色,以及使用ember后我可以遇到的问题。

所以我有一些问题:

1)Ember视图很酷,但是如果我想让ember处理现有的元素动作和动画呢?我的意思是,例如我在服务器上呈现链接(或使用AJAX接收的HTML),我如何绑定ember动作来处理它的单击操作并为它实例化我的自定义LinkView?我确信我可以通过jQuery或其他东西“手动”绑定到DOM事件来找到解决方案,但确实存在“Ember”方式吗?

2)是否可以在进入初始状态之前设置StateManager属性,但不在类级别设置它?

3)有人能指出我如何使用Em.Deffered的例子吗?我承诺使用jQuery $.Deferred(),但我不希望在我的StateManager中依赖jQuery。

4)是否存在其他“Ember”方式告诉框架在已隐藏状态下向DOM添加视图?我试图设置isVisible:false,但它不起作用。

5)是否存在其他方式然后再次添加隐藏视图,以解决错误“无法对不在DOM中的Metamorph执行操作”。

以下是参考资料来源:

<script type="text/x-handlebars" data-template-name="GuestView">
        User: {{view Ember.TextField valueBinding='controller.username' placeholderBinding='controller.usernameHint'}}
        Pass: {{view Ember.TextField valueBinding='controller.password' placeholderBinding='controller.passwordHint' }}
        <br/>
        <button {{action login this}}>Login</button>
    </script>

<script type="text/x-handlebars" data-template-name="UserView">
        Hello {{ username }}
        <button {{action logout this}}>Logout</button>
    </script>

<script type="text/javascript">
        var App = Em.Application.create({
            authController: null,
            currentUserBinding: 'authController.content',

            ready: function () {
                this.set("authController", App.AuthController.create());
            }
        });

        App.AuthController = Em.ObjectController.extend({
            content: null,
            target: null,
            init: function () {
                this.set("content", this.getUserFromCookieOrDefault());

                //Is it possible in Ember, to set the controller before entering initial state,
                //but without setting it on Class level?
                this.set("target", App.AuthManager.reopen({ controller: this }).create({
                    //initialState: this.get("content").isAuthorized ? "authorized" : "guest"
                }));
                this.get("target").transitionTo(this.get("content").isAuthorized ? "authorized" : "guest");
            },

            doLogin: function (mgr, context) {
                console.log("logging in");

                //Validation, etc...
                //Imulating async Data loading, actually, it should be done with promises
                setTimeout(function () { mgr.transitionTo("authorized"); }, 1000);
            },

            doLogout: function (mgr, context) {
                console.log("logging out");

                //logout logic
                mgr.transitionTo("guest");
                this.set("content", App.Guest.create());
            },

            getUserFromCookieOrDefault: function () {
                return App.Guest.create();
                //return App.User.create({ username: "TestUser" });
            },
        });

        App.AuthManager = Em.StateManager.extend({
            controller: null,
            canTransist: true,

            // { data, commitCallback, abortCallback } 
            transitionTo: function (path, context) {
                var originalTransitionTo = this._super,
                    manager = this,
                    canTransist = "canTransist",
                    deffered = null,
                    originalTransitionToParams = context && (context.data || context.commitCallback || context.abortCallback) ?
                                                 context.data : context;

                if (!manager.get(canTransist)) {
                    Em.assert("Already in Transition");
                    return;
                }

                manager.set(canTransist, false);

                if (!manager.currentState) {
                    originalTransitionTo.apply(manager, [path, originalTransitionToParams]);
                    manager.set(canTransist, true);
                    return;
                }

                if (!manager.currentState.isAsyncExit) {
                    originalTransitionTo.apply(manager, [path, originalTransitionToParams]);
                    manager.set(canTransist, true);
                }
                else {

                    //How to use Em.Deffered?
                    deffered = $.Deferred();
                    deffered.done(commitTransition).fail(abortTransition);
                    manager.currentState.beforeExit(deffered, originalTransitionToParams);
                }

                function commitTransition() {
                    originalTransitionTo.apply(manager, [path, originalTransitionToParams]);
                    manager.set(canTransist, true);
                }

                function abortTransition() {
                    manager.set(canTransist, true);
                }
            },

            states: {
                guest: Em.State.create({
                    isAsyncExit: true,

                    enter: function (mgr) {
                        console.log("guest");

                        App.guestView = App.GuestView.create({
                            templateName: "GuestView",
                            controller: mgr.controller,
                        }).append();
                    },

                    beforeExit: function (promise, context) {
                        App.guestView.remove(promise);
                    },

                    login: function (mgr, context) {
                        mgr.controller.doLogin(mgr, context);
                    }
                }),

                authorized: Em.State.create({
                    isAsyncExit: true,

                    enter: function (mgr) {
                        console.log("authorized");

                        App.userView = App.UserView.create({
                            templateName: "UserView",
                            controller: mgr.controller,
                        }).append();
                    },

                    beforeExit: function (promise) {
                        App.userView.remove(promise);
                    },

                    logout: function (mgr, context) {
                        mgr.controller.doLogout(mgr, context);
                    }
                })
            }
        });

        App.FadingView = Em.View.extend({
            //Does exists other "Ember" way to tell framework to add view to DOM in already hidden state?
            //I tried to set isVisible: false, but it not works
            classNames: ['initialHidden'],

            didInsertElement: function () {

                //If using this.$().hide().show('slow') without 'initialHidden' class then view is still visible when alert shown
                //alert("View visible");
                this.$().hide().fadeIn(500).removeClass("initialHidden");

            },

            remove: function (promise) {

                var originalView = this,
                    originalViewElement = originalView.$(),
                    clonedView = originalView.$().clone(),
                    originalRemove = this._super;

                $(clonedView).attr("id", $(clonedView).attr("id") + "_clone").removeClass('ember-view');
                $("*", clonedView).removeClass('ember-view').remove("script[id^=metamorph]");
                originalView.$().replaceWith(clonedView);

                //This line exists, only because of Metamorph error:
                //Cannot perform operations on a Metamorph that is not in the DOM.
                $(originalViewElement).css("display", "none").appendTo("body");

                clonedView.fadeOut(1000, function () {
                    $(this).remove();
                    originalRemove.apply(originalView);
                    promise.resolve();
                });

            }
        });

        App.GuestView = App.FadingView.extend();
        App.UserView = App.FadingView.extend();

        App.User = Em.Object.extend({
            username: "",
            isAuthorized: true
        });

        App.Guest = Em.Object.extend({
            isAuthorized: false,
            password: "",
            usernameHint: "Username...",
            passwordHint: "Password..."
        });
    </script>

0 个答案:

没有答案