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

前言

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

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



观察者模式对咱们来讲应该不陌生,对vue原理稍微有点了解的都知道经过Object.defineProperty 拦截数据的 get/set ,在set中收集依赖Watcher,在get中触发更新Watcher.notify(),这里就是观察者模式的应用ios

观察者(Observer)模式与发布(Publish)/订阅(Subscribe)的关系
他们的行为方式类似add,notify/trigger,最明显的区别是观察者add一个具体观察者对象,发布/订阅add一个订阅事件算法

// 观察者
class Observer {
  update () {}
}

const Observer1 = new Observer()
Subject.add(Observer1)
Subject.notify()

// 发布订阅
Publish.add('event1',function Subscribe() { 
  ...do something 1
})
Publish.add('event1',function Subscribe() { 
  ...do something 2
})
Publish.add('event1',function Subscribe() { 
  ...do something 3
})
Publist.trigger('event1')
复制代码

1、场景

  • 两个form表单——发票信息和邮寄信息
  • 邮寄信息表单只在选中增值税专用发票时才须要
  • 提交按钮需在全部存在的表单(一个或者两个)验证经过后才有效,也就是在点击提交按钮后获取表单的验证结果和输入框的值

2、分析

大多数状况咱们遇到的场景是一个表单对应一个提交按钮,如今的场景是一个提交按钮控制N个(大于1)且数量不可控的表单,咱们能够借助观察者模式解决这个问题axios

将表单对象(组件)做为观察者,点击提交按钮notify全部观察者(表单)获取值设计模式

3、设计

// invoiceForm.vue
<template>
  ... do something
</template>
<srcipt>
  export default {
    methods: {
      // 全部form组件提供统一的获取值接口
      getValue () {
        // 需返回一个promise,目前大多数vue表单验证都是异步的
        return new Promise(() => {
          // 表单验证,返回值
          ...do something
        })
      }
    }
  }
</script>
复制代码
// postForm.vue
<template>
  ... do something
</template>
<srcipt>
  export default {
    methods: {
      // 统一的获取值接口
      getValue () {
        // 需返回一个promise
        return new Promise(() => {
          ...do something
        })
      }
    }
  }
</script>
复制代码
// stage.vue
<template>
  <div>
    <!-- ref获取组件对象 -->
    <invoice-form ref="invoice" />
    <post-form v-if="isNeedPost" ref="post" />
    <button @click="handleSubmit">提交</button>
  </div>
</template>
<script>
  export default {
    data () {
      isNeedPost: true
    }
    methods: {
      async handleSubmit () {
        // 已知有invoice和post两个观察者
        let invoice = await this.$refs.invoice.getValue()
        let post = {}
        if (this.$refs.post) {
            post = await this.$refs.post.getValue()
        }
        this.$axios.post({
            invoice,
            post
        })
      }
    }
  }
</script>
复制代码

4、更复杂的场景

每次点击新增联系人按钮页面上会增长一个这样的form,点击保存按钮时全部联系人表单分别作验证,全部表单验证经过后一并提交。与上面的场景相似,你们能够尝试本文的思路。
上面的场景是已知有invoiceFormpostForm,而这个场景下联系人form能够无限制的添加

当 ref 和 v-for 一块儿使用的时候,你获得的引用将会是一个包含了对应数据源的这些子组件的数组(来自vue文档)数组

设计实现

<template>
  <div>
    <div>
      <contact-form
        v-for="(item, index) in contactGroup"
        ref="contacts"
        :key="index"
      />
    </div>
    <button @click="handleAdd">添加联系人</button>
    <button @click="handleSave">保存</button>
  </div>
</template>
<script>
  export default{
    data () {
      return {
        contactGroup: [true]
      }
    },
    methods: {
      handleAdd () {
        this.contactGroup.push(true)
      },
      async handleSave () {
        // 伪代码
        try {
          // this.$refs.contacts是一个数组
          const promises = this.$refs.contacts.map(contact => contact.getValue())
          const contacts = await Promise.all(promises)
          this.$axios.post({
            contacts
          })
        } catch (error) {
          // 表单验证不经过
          console.dir(error)
        }
      }
    }
  }
</script>
复制代码

结尾

本文的内容相对来讲比较简单,对于上面例举的场景你也可能会有更好的解决方式,不过我的以为这种需求场景对于理解观察者模式仍是蛮不错的。promise

写到这一篇以为有必要搞个小总结:

1,在这一篇为了使用观察者模式咱们须要获取观察对象(组件)——ref
2,本系列第一篇咱们用工厂模式生产input组件,为了透传type、status工厂组件设计的也须要接受
这两个props,若是这时要透传更多的prop而且还有事件那怎么办呢,最好的方案——$attrs$listeners
3,设计模式的一个主要特性可以动态的组合和决定使用哪一个对象(组件)——动态组件component
4,本系列第四篇为能自定义一个算法(组件渲染)的某一步——slot

相信你们都已经了解了一个框架API的设计背后都是有必定考量的,固然上面例举的4个都只是基于本系列
的内容不表明所有
有人说不会这样用是由于对vue的文档不熟悉,我身边有朋友没事就把vue文档从头看到尾,他是不熟?
我的以为应该是代码的设计需求驱动你去深刻了解框架,大多时候框架已经提供了知足你要求的API直
接用就好了(查文档),若是框架没有提供现成的能不能经过其它API hack一下(这个时候可能就须要深刻
源码研究),若是依旧知足不了你,在本身技术能力容许的状况下给框架源码提个PR?

复制代码

本文实现一样适用于react,为何文章以vue作题?vue的template让咱们在理解一些概念的时候可能会有点不适应,而react的jsx能够看作就是在写JavaScript对各类概念实现更灵活
友情提示:设计模式在vue中的应用应该会写一个系列,喜欢的同窗记得关注下bash

相关文章
相关标签/搜索