做者:Nalla Senthilnathan翻譯:瘋狂的技術宅javascript
原文:https://dzone.com/articles/a-...html
未經容許嚴禁轉載前端
使用狀態機能夠構建健壯的 UI,其好處已有詳細的描述—— 例如你能夠參見Edward J. Pring 的文章和 David Khourshid 的視頻。 另外Krasimir Tsonev 描述了 JavaScript 中狀態機的一些經常使用方法。一些比較流行的 JavaScript 庫是 jakesgordon/javascript-state-machine 和 davidkpiano/xstate 。java
在本文中,我將實現一個用於 JavaScript UI 的簡單的狀態機。爲了保持內容簡潔,我使用了 jQuery。jquery
狀態機的經典 「Hello,World」 示例是 Turnstile。如下步驟描述了怎樣把狀態機應用於十字旋轉門問題:git
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 結構中的函數能夠存在一個模型參數。github
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(); });
你能夠查看本例的在線演示(https://mapteb.github.io/js-s...),其中能夠測試四個狀態轉換。該演示的完整源代碼可在 GitHub 上找到。segmentfault
值得注意的是,用於 Java 程序的方法一樣適用於JavaScript 程序。這個方法的一個特別之處在於三個組件中的關注點的清晰分離 —— 狀態、事件/事件處理handler和控制器。總之,把狀態機用於前端應用可以有助於構建乾淨且健壯的 UI。