阅读 1844

设计模式在vue中的应用(二)

前言

目录整理:
设计模式在vue中的应用(一)
设计模式在vue中的应用(二)
设计模式在vue中的应用(三)
设计模式在vue中的应用(四)
设计模式在vue中的应用(五)
设计模式在vue中的应用(六)
设计模式在vue中的应用(七)

为什么要写这些文章呢。正如设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结(来自百度百科)一样,也是想通过分享一些工作中的积累与大家探讨设计模式的魅力所在。
在这个系列文章中为了辅助说明引入的应用场景都是工作中真实的应用场景,当然无法覆盖全面,但以此类推也覆盖到了常见的业务场景



这篇内容比较简单只涉及到一个设计模式——状态模式。

一,需求

图片来自iView文档截图

在服务端输出页面的开发模式下每完成一步常规做法是跳转一个新页面到下一步,当然在SPA的开发模式下大多场景也是通过路由处理每一步的逻辑。

现在的需求是:这整个过程是连续的,除非整个过程处理完成,否则不管进行到哪一步当刷新页面都要从第一步重新开始,也就是在同一个路由下处理这四步操作

二,分析

在文章开头我们提到了状态模式,通过上面的需求我们很容易联想:

  • 第一步操作完成改变状态到第二步
  • 第二步操作完成改变状态到第三步
  • 第三步操作完成改变状态到第四步

三,设计

先看状态模式的介绍

一下内容来自网络

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中的应用应该会写一个系列,喜欢的同学记得关注下

关注下面的标签,发现更多相似文章
评论