大規模なプロジェクトの準備中に、約 10 人の開発者のチームで使用される JS MV* フレームワークをいくつか調査しています。
最初に AngularJS を試しました。これは、すべてのフレームワークの中で最高のパフォーマンスを発揮するように見えるためです ( SO トピック)。DI のような素晴らしい未来がいくつかありますが、それを扱うのはあまり好きではありません。私にとっては理解するのが難しい少し乱雑なコードであり、コードができるだけきれいで、適切に構造化され、簡単に操作できるようにするのが好きだからです。読んだ。
現在、私は EmberJS を試しています。これは ember のように見え、開発者にとって非常に使いやすく、操作も簡単です。そこで、小さな「ログイン ウィジェット」を作成して、ember アプリの構造を確認しました。開発中に、非同期リクエスト、アニメーションなどのいくつかの問題を解決しようとしました...
「ウィジェット」はすでに機能しており、私が彼にしてほしいことはすべて実行しますが、現時点ではまだいくつか質問があり、経験豊富な ember 開発者から、現在のコード構造、オブジェクトの役割、および問題についてアドバイスを聞きたいと思います。エンバーを使えば後で会える。
だからここに私が持っているいくつかの質問:
1) Ember ビューはクールですが、既存の要素のアクションとアニメーションを Ember で処理したい場合はどうすればよいでしょうか? たとえば、サーバーでレンダリングされたリンク (または AJAX で受信した HTML) がある場合、ember アクションをバインドしてクリック アクションを処理し、カスタム LinkView をインスタンス化する方法を教えてください。jQueryなどを使用してDOMイベントに「手動で」バインドすることで解決策を見つけることができると確信していますが、それを行う「Ember」方法はありますか?
2)StateManager
初期状態に入る前にプロパティを設定することはできますが、クラスレベルで設定する必要はありませんか?
3) 誰かが使用方法の例を教えてもらえますEm.Deffered
か? 私は jQuery で動作することを約束しまし$.Deferred()
たが、私のStateManager
.
4)フレームワークに、既に非表示の状態でDOMにビューを追加するように指示する他の「Ember」方法はありますか? 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>