<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>javascript-state-machine</title>
    <style>
      .on {
        background-color: #1e80ff;
        color: #fff;
      }

      .ul-popover {
        visibility: hidden;
        border: 1px dashed blueviolet;
      }
      .ul-visible {
        visibility: visible;
      }
    </style>
  </head>
  <body>
    <button type="button" id="btn-switch">Switch</button>
    <ul class="ul-popover">
      <li>Milk</li>
      <li>
        Cheese
        <ul>
          <li>Blue cheese</li>
          <li>Feta</li>
        </ul>
      </li>
    </ul>

    
  </body>
</html>
let ButtonMachine = function (btnEle, ulEle) {
  return {
    // 状态机当前状态
    currentState: 'off',
    // 初始化事件
    init: function () {
      btnEle.addEventListener('click', (event) => {
        console.log('this', this);
        this.transition();
      });
      log(this);
    },
    // 每次输入会调用 transition 方法根据输入判断更改当前状态
    transition: function (event) {
      // do something 根据用户行为(event)更改currentState
      switch (this.currentState) {
        case 'on': {
          const old = this.currentState;
          // do something 更改为 关闭 状态, 取消高亮同时隐藏菜单
          this.currentState = 'off';
          this.turnOff(old);
          break;
        }
        case 'off': {
          const old = this.currentState;
          // do something 更改状态为 打开 状态 高亮按钮、显示菜单
          this.currentState = 'on';
          this.turnOn(old);
          break;
        }
        default:
          console.log('Invalid State');
          break;
      }
    },
    turnOn: function (fromState) {
      btnEle.classList.add('on');
      ulEle.classList.add('ul-visible');
      log(this, fromState);
    },
    turnOff: function (fromState) {
      btnEle.classList.remove('on');
      ulEle.classList.remove('ul-visible');
      log(this, fromState);
    },
  };
};

function log(fsm, previousState) {
  if (!previousState) {
    console.log(`[INIT] currentState is :  ${fsm.currentState}`);
  } else {
    console.log(
      `[TRANSFORM] currentState is :  ${fsm.currentState}, and previous state is : ${previousState}`
    );
  }
}

  let machine = new ButtonMachine(
        document.querySelector('#btn-switch'),
        document.querySelector('.ul-popover')
      );
      machine.init();

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.