實現一個簡單的 JavaScript 狀態機

做者:Nalla Senthilnathanjavascript

翻譯:瘋狂的技術宅html

原文:dzone.com/articles/a-…前端

未經容許嚴禁轉載java

使用簡單的狀態機建立乾淨且健壯的 UI

使用狀態機能夠構建健壯的 UI,其好處已有詳細的描述—— 例如你能夠參見Edward J. Pring 的文章和 David Khourshid 的視頻。 另外Krasimir Tsonev 描述了 JavaScript 中狀態機的一些經常使用方法。一些比較流行的 JavaScript 庫是 jakesgordon/javascript-state-machinedavidkpiano/xstatejquery

在本文中,我將實現一個用於 JavaScript UI 的簡單的狀態機。爲了保持內容簡潔,我使用了 jQuery。git

經典十字旋轉門問題

狀態機的經典 「Hello,World」 示例是 Turnstile。如下步驟描述了怎樣把狀態機應用於十字旋轉門問題:github

步驟1:編寫狀態轉換表如:

defaultState coinEvent handleCoin() coinSuccessEvent coinSuccessState
defaultState coinEvent handleCoin() coinErrorEvent coinErrorState
coinErrorState coinEvent handleCoin() coinSuccessEvent coinSuccessState
coinSuccessState pushEvent pushHandler() pushSuccessEvent pushEventState

步驟2:捕獲數據結構中的狀態:

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

步驟3:捕獲事件和事件處理

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 配置,由於咱們在狀態轉換表中看到過後指示的下一個狀態應該是什麼。服務器

步驟4:編排控制器中的狀態和事件(在咱們的例子中是 jQuery body):

//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。

歡迎關注前端公衆號:前端先鋒,領取前端工程化實用工具包。

相關文章
相關標籤/搜索