做者:Nalla Senthilnathanjavascript
翻譯:瘋狂的技術宅html
未經容許嚴禁轉載java
使用狀態機能夠構建健壯的 UI,其好處已有詳細的描述—— 例如你能夠參見Edward J. Pring 的文章和 David Khourshid 的視頻。 另外Krasimir Tsonev 描述了 JavaScript 中狀態機的一些經常使用方法。一些比較流行的 JavaScript 庫是 jakesgordon/javascript-state-machine 和 davidkpiano/xstate 。jquery
在本文中,我將實現一個用於 JavaScript UI 的簡單的狀態機。爲了保持內容簡潔,我使用了 jQuery。git
狀態機的經典 「Hello,World」 示例是 Turnstile。如下步驟描述了怎樣把狀態機應用於十字旋轉門問題:github
defaultState | coinEvent | handleCoin() | coinSuccessEvent | coinSuccessState |
---|---|---|---|---|
defaultState | coinEvent | handleCoin() | coinErrorEvent | coinErrorState |
coinErrorState | coinEvent | handleCoin() | coinSuccessEvent | coinSuccessState |
coinSuccessState | pushEvent | pushHandler() | pushSuccessEvent | pushEventState |
const turnstileStates = {
defaultState : function() {
$("#thankyou").hide();
$("#cointxt").val("");
$("#push").prop("disabled", true);
$("#cointxt").prop("disabled", false);
$("#turnstile_locked").show();
$("#turnstile_unlocked").hide();
$("#coinerrmsg").hide();
},
coinSuccessState : function() {
$("#turnstile_locked").hide();
$("#cointxt").prop("disabled", true);
$("#push").prop("disabled", false);
$("#coin").prop("disabled", true);
$("#turnstile_unlocked").show();
$("#coinerrmsg").hide();
},
coinErrorState : function() {
$("#thankyou").hide();
$("#cointxt").prop("disabled", false);
$("#push").prop("disabled", true);
$("#turnstile_locked").show();
$("#coinerrmsg").show();
$("#turnstile_unlocked").hide();
},
pushSuccessState : function() {
$("#thankyou").show();
$("#welcome").hide();
$("#cointxt").prop("disabled", true);
$("#turnstile_locked").hide();
$("#coin").prop("disabled", true);
$("#push").prop("disabled", true);
$("#turnstile_unlocked").hide();
$("#coinerrmsg").hide();
}
};
複製代碼
注意,能夠經過重構上面的函數體,來使用適當的數據參數調用相似 renderComponent() 的方法。我在這裏用了詳細模式,所以讀者能夠在一個地方快速看到 turnstileStates 配置背後的概念。前端工程化
在這個 「Hello,World」 示例中,我沒有使用來自於服務器的任何數據(模型)。當咱們從服務器得到這樣的模型時,turnstileStates 結構中的函數能夠存在一個模型參數。bash
const turnstileEvents = {
coinEvent : {
handleCoin : function(e) {
if (e.data.coinval() > 0) {
return turnstileEvents.coinSuccessEvent;
} else {
return turnstileEvents.coinErrorEvent;
}
}
//nextState not needed for this event
},
coinSuccessEvent : {
nextState : function() {
return turnstileStates.coinSuccessState();
}
//no handlers are needed for this event
},
coinErrorEvent : {
nextState : function() {
return turnstileStates.coinErrorState();
}
//no handlers are needed for this event
},
pushEvent : {
handlePush : function() {
return turnstileEvents.pushSuccessEvent;
}
//nextState not needed for this event
},
pushSuccessEvent : {
nextState : function() {
return turnstileStates.pushSuccessState();
}
//no handlers are needed for this event
}
};
複製代碼
注意: nextnate 屬性用於 turnstileEvents 配置而不是 turnstileStates 配置,由於咱們在狀態轉換表中看到過後指示的下一個狀態應該是什麼。服務器
//handle the page load event
turnstileStates.defaultState();
//handle the coin event
$("#coin").on("click",{ coinval : function(){return $("#cointxt").val();} },function(event) {
return turnstileEvents.coinEvent.handleCoin(event).nextState();
});
//handle the push event
$("#push").click(function() {
return turnstileEvents.pushEvent.handlePush().nextState();
});
複製代碼
你能夠查看本例的在線演示(mapteb.github.io/js-state-ma… GitHub 上找到。
值得注意的是,用於 Java 程序的方法一樣適用於JavaScript 程序。這個方法的一個特別之處在於三個組件中的關注點的清晰分離 —— 狀態、事件/事件處理handler和控制器。總之,把狀態機用於前端應用可以有助於構建乾淨且健壯的 UI。