設計模式在vue中的應用(二)

hailx發表於2019-01-22

前言

目錄整理:
設計模式在vue中的應用(一)
設計模式在vue中的應用(二)
設計模式在vue中的應用(三)
設計模式在vue中的應用(四)
設計模式在vue中的應用(五)
設計模式在vue中的應用(六)
設計模式在vue中的應用(七)

為什麼要寫這些文章呢。正如設計模式(Design Pattern)是一套被反覆使用、多數人知曉的、經過分類的、程式碼設計經驗的總結(來自百度百科)一樣,也是想通過分享一些工作中的積累與大家探討設計模式的魅力所在。
在這個系列文章中為了輔助說明引入的應用場景都是工作中真實的應用場景,當然無法覆蓋全面,但以此類推也覆蓋到了常見的業務場景



這篇內容比較簡單隻涉及到一個設計模式——狀態模式。

一,需求

圖片來自iView文件截圖

設計模式在vue中的應用(二)
在服務端輸出頁面的開發模式下每完成一步常規做法是跳轉一個新頁面到下一步,當然在SPA的開發模式下大多場景也是通過路由處理每一步的邏輯。

現在的需求是:這整個過程是連續的,除非整個過程處理完成,否則不管進行到哪一步當重新整理頁面都要從第一步重新開始,也就是在同一個路由下處理這四步操作

二,分析

在文章開頭我們提到了狀態模式,通過上面的需求我們很容易聯想:

  • 第一步操作完成改變狀態到第二步
  • 第二步操作完成改變狀態到第三步
  • 第三步操作完成改變狀態到第四步

三,設計

先看狀態模式的介紹

一下內容來自網路

設計模式在vue中的應用(二)

1,首先需要一個context環境角色
// context.vue
<template>
  <div>
    <Steps :current="status">
      <Step title="已完成" content="這裡是第一步"></Step>
      <Step title="進行中" content="這裡是第二步"></Step>
      <Step title="待進行" content="這裡是第三步"></Step>
      <Step title="待進行" content="這裡是第四步"></Step>
    </Steps>
    <!-- 動態渲染當前狀態元件 -->
    <component :is="statusCom" @onChangeStatus="changeStatus" />
  </div>
</template>
<script>
  // 引入各狀態元件
  import Step1 from './Step1'
  import Step2 from './Step2'
  import Step3 from './Step3'
  import Step4 from './Step4'
  
  export default {
    data() {
      return {
        status: 1
      }  
    },
    computed: {
      // 具體狀態角色
      statusCom() {
        const statusMap = {
          1: Step1,
          2: Step2,
          3: Step3,
          4: Step4,
        } 
        return statusMap[this.status]
      }    
    },
    methods: {
      // 代表每一步的狀態元件都有改變status的能力
      changeStatus(val) {
        this.status = val
      }    
    }  
  }
</script>
複製程式碼
2,實現State抽象狀態角色
// Step1.vue
<template>
  <div>
    <!-- do something -->
    <button @click="handleClick">完成</button>
  </div>
</template>
<script>
  export default {
    methods: {
      handleClick() {
        // 第一步完成,將狀態變為狀態2
        // context角色接受狀態改變動態渲染Step2.vue的操作
        this.$emit('onChangeStatus', 2)
      }
    }  
  }
</script>
複製程式碼
Step2.vue
Step3.vue
Step4.vue
同Step1.vue
複製程式碼
3,總結
  • context角色只負責具體狀態的切換——渲染哪一步的元件
  • state角色負責處理當前狀態的實現和切換下一個狀態——每一步邏輯的具體實現

四,優化

通過上面的實現,我們發現整個狀態的改變都交給了各狀態元件,如果這時我操作到了第3步想回退到第2步怎麼辦?

給每個狀態元件加一個回退到上一個狀態的功能?
在我們這個需求中狀態從1->2->3->4是單向的,這個方式或許能行,假設在一個比較複雜的狀態場景下,各狀態的改變毫無章法很難確定當前狀態的上一個狀態是什麼

解決辦法:為每一次狀態改變做一次快取

// 優化後的context.vue
<template>
  <div>
    <Steps :current="status">
      <Step title="已完成" content="這裡是第一步"></Step>
      <Step title="進行中" content="這裡是第二步"></Step>
      <Step title="待進行" content="這裡是第三步"></Step>
      <Step title="待進行" content="這裡是第四步"></Step>
    </Steps>
    <!-- 返回上一步 -->
    <button v-if="canGoBack" @click="goBack">返回上一步</button>
    <!-- 動態渲染當前狀態元件 -->
    <component :is="statusCom" @onChangeStatus="changeStatus" />
  </div>
</template>
<script>
  // 引入各狀態元件
  import Step1 from './Step1'
  import Step2 from './Step2'
  import Step3 from './Step3'
  import Step4 from './Step4'
  
  const DEFAULT_STATUS = 1
  
  export default {
    data() {
      return {
        status: DEFAULT_STATUS,
        cache: [] // 快取狀態
      }  
    },
    computed: {
      // 具體狀態角色
      statusCom() {
        const statusMap = {
          1: Step1,
          2: Step2,
          3: Step3,
          4: Step4,
        } 
        return statusMap[this.status]
      },
      canGoBack() {
        return this.cache.length > 0
      }
    },
    methods: {
      // 代表每一步的狀態元件都有改變status的能力
      changeStatus(val) {
        // 快取每一次的狀態變化
        this.cache.push(val)
        this.status = val
      },
      goBack() {
        // 彈出當前狀態
        this.cache.pop()
        // 改變狀態為上一個狀態
        this.status = this.cache[this.cache.length - 1] || DEFAULT_STATUS
      }
    }  
  }
</script>
複製程式碼

總結

通過工作中的一個功能設計為大家介紹了狀態模式。或許有的同學會說我通過if else不也能做嗎,當然隨著需求不斷的變更你的if else最終只有你自己看的懂,慢慢的bug出現的機率也越高,狀態模式正是用來解決這種問題的


本文實現同樣適用於react,為什麼文章以vue做題?vue的template讓我們在理解一些概念的時候可能會有點不適應,而react的jsx可以看做就是在寫JavaScript對各種概念實現更靈活
友情提示:設計模式在vue中的應用應該會寫一個系列,喜歡的同學記得關注下

相關文章