降低前端业务复杂度:状态机(2)——前端状态机业务使用

168 阅读3分钟

前言

希望能够把一些有很多复杂状态的页面分离清楚,方便后续针对不同的情况加功能。

使用前

computed: {
  // 状态名称
  statusText () {
    switch (this.status) {
      case 1:
        return '未处理'
      case 2:
        return '处理中'
      case 3:
        return '已发布'
      case 4:
        return '已下架'
      case 5:
        return '无效批'
    }
    return ''
  },
  // 状态tag的颜色
  statusColor () {
    switch (this.status) {
      case 1:
        return 'blue'
      case 2:
        return 'green'
      case 3:
        return 'orange'
      case 4:
      case 5:
        return 'default'
    }
    return ''
  },
  // 展示“设置为无效”按钮
  showInvalidBtn () {
    const _no_attach = this.statusText === '处理中' && !this.hasAttachment
    const _has_attach = this.hasAttachment && ['处理中', '已下架'].includes(this.statusText)
    return _no_attach || _has_attach
  },
}

问题所在

不容易看懂这个业务状态的走向,不方便后面加功能,容易混淆加犯错。\

使用状态机(vue2)

  • State (状态)。一个状态机至少要包含两个状态。例如上面任务状态,有 未处理 和 处理中 等等状态。
  • Event (事件)。事件就是执行某个操作的触发条件或者口令。
  • Action (动作)。事件发生以后要执行动作。对于上面的statusText,statusColor,就是一个动作。
  • Transition (变换)。也就是从一个状态变化为另一个状态。

代码层面

创建状态机

class StatusMaker {
  constructor (detail) {
    if (!detail) return
    this.state = this.setState(detail.status)
    this.detail = detail
  }
}

传入任务的详情数据

增加状态(state)

class StatusMaker {
  constructor (detail) {
    if (!detail) return
    this.state = this.setState(detail.status)
    this.detail = detail
  }
  setState (status) {
    if (status === 1) {
      return 'type1' // '未处理'
    } else if (status === 2) {
      return 'type2' // '处理中'
    } else if (status === 3) {
      return 'type3' // '已发布'
    } else if (status === 4) {
      return 'type4' // '已下架'
    } else if (status === 5) {
      return 'type5' // '无效批'
    }
  }
}

状态是控制状态机运行的关键属性,所以首先得控制传入的任务类型

增加动作(action)

根据当前类型执行需要的不同的方法。

class StatusMaker {
  constructor (detail) {
    if (!detail) return
    this.state = this.setState(detail.status)
    this.detail = detail
  }
  setState (status) {
    if (status === 1) {
      return 'type1' // '未处理'
    } else if (status === 2) {
      return 'type2' // '处理中'
    } else if (status === 3) {
      return 'type3' // '已发布'
    } else if (status === 4) {
      return 'type4' // '已下架'
    } else if (status === 5) {
      return 'type5' // '无效批'
    }
  }
  type1 = {
    statusText() {
      return '未处理'
    },
    statusColor () {
      return 'blue'
    }
  }
  type2 = {
    statusText() {
      return '处理中'
    },
    statusColor () {
      return 'green'
    },
    showInvalidBtn () {
      return true
    },
    showReasonModal () {
      return this.detail.hasAttachment // 含附件
    }
  }
  type3 = {
    statusText() {
      return '已发布'
    },
    statusColor () {
      return 'orange'
    }
  }
  type4 = {
    statusText() {
      return '已下架'
    },
    statusColor () {
      return 'default'
    },
    showInvalidBtn () {
      return this.detail.hasAttachment // 含附件
    },
    showReasonModal () {
      return this.detail.hasAttachment // 含附件
    }
  }
  type5 = {
    statusText() {
      return '无效批'
    },
    statusColor () {
      return 'default'
    }
  }
}

增加执行事件event

class StatusMaker { 
 constructor (detail) {
    if (!detail) return
    this.state = this.setState(detail.status)
    this.detail = detail
  }
  setState (status) {
    if (status === 1) {
      return 'type1' // '未处理'
    } else if (status === 2) {
      return 'type2' // '处理中'
    } else if (status === 3) {
      return 'type3' // '已发布'
    } else if (status === 4) {
      return 'type4' // '已下架'
    } else if (status === 5) {
      return 'type5' // '无效批'
    }
  }
  type1 = {
    ...
  }
    ...
// ++ start
  getEvent (method, ...args) {
    const state = this.state
    if (!this[state] || !this[state][method]) {
      return false
    }
    // 通过call让action内部能够获取当前实例this,并且将参数args传入
    return this[state][method].call(this, ...args) 
  }
  // ++ end
}

vue2使用

import StatusMaker from '@/libs/statusMaker/powerBox.js'
export default {
  data() {
     return {
         statusMaker: null
     }
  },
  created () {
    this.init_status()
  },
   methods: {
     init_status () {
       this.statusMaker = new StatusMaker(this.detail)
       this.statusText = this.statusMaker.getEvent('statusText')
       this.statusColor = this.statusMaker.getEvent('statusColor')
       this.showInvalidBtn = this.statusMaker.getEvent('showInvalidBtn')
     }
   }
}

状态机代码

class StatusMaker {
  constructor (detail) {
    if (!detail) return
    this.state = this.setState(detail.status)
    this.detail = detail
  }
  setState (status) {
    if (status === 1) {
      return 'type1' // '未处理'
    } else if (status === 2) {
      return 'type2' // '处理中'
    } else if (status === 3) {
      return 'type3' // '已发布'
    } else if (status === 4) {
      return 'type4' // '已下架'
    } else if (status === 5) {
      return 'type5' // '无效批'
    }
  }
  type1 = {
    statusText() {
      return '未处理'
    },
    statusColor () {
      return 'blue'
    }
  }
  type2 = {
    statusText() {
      return '处理中'
    },
    statusColor () {
      return 'green'
    },
    showInvalidBtn () {
      return true
    },
    showReasonModal () {
      return this.detail.hasAttachment // 含附件
    }
  }
  type3 = {
    statusText() {
      return '已发布'
    },
    statusColor () {
      return 'orange'
    }
  }
  type4 = {
    statusText() {
      return '已下架'
    },
    statusColor () {
      return 'default'
    },
    showInvalidBtn () {
      return this.detail.hasAttachment // 含附件
    },
    showReasonModal () {
      return this.detail.hasAttachment // 含附件
    }
  }
  type5 = {
    statusText() {
      return '无效批'
    },
    statusColor () {
      return 'default'
    }
  }
  // ++ start
  getEvent (method, ...args) {
    const state = this.state
    if (!this[state] || !this[state][method]) {
      return false
    }
    return this[state][method].call(this, ...args) // 通过call让action内部能够获取当前实例this,并且将参数args传入
  }
  // ++ end
}
export default StatusMaker