設計模式在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

相關文章
相關標籤/搜索