vue數據傳遞--我有特殊的實現技巧

轉載
vue數據傳遞–我有特殊的實現技巧

項目背景:
pc管理後臺,自己封裝了一個彈窗組件,是個空的盒子,用意是在每次需要的時候,直接調用此組件,形成彈窗。
後面有個需求,需要在彈窗中實現一個form表單的填寫與校驗,需求不復雜,但是代碼數量較大,所以選擇單獨做一個組件,形成了嵌套組件。
現在需要在組件間傳值
類似:

import
import
父組件
子組件
通用的彈窗組件
在彈窗組件中寫入的表單

組件之間傳值有這麼幾種數據傳遞方式,vuex、props、eventBus和特殊的eventBus

vuex:

適合大型項目

props:

父子組件傳值,只能父子組件
父向子傳值–>props
子向父傳值–>子組件綁定事件回調定義在父組件,子組件觸發此事件。
不推薦子組件內直接修改父組件傳入的props,需使用自定義事件。

eventBus

bus皆爲導入的bus實例

// bus
const bus = new Vue()
// 數據接收組件
// 當前組件接收值則
bus.$on('event1', (val)=>{})
// 數據發出組件
// 當前組件發出值則
bus.$emit('event1', val)

可以看出本質是一個vue實例充當事件綁定的媒介
在所有實例中使用其進行數據的通信。
雙(多)方使用同名事件進行溝通

問題:

$emit時,必須已經$on,否則將無法監聽到事件,也就是說對組件是有一定的同時存在的要求的。(注:路由切換時,新路由組件先created,舊路由組件再destoryed,部分情況可以分別寫入這兩個生命週期,見此問題)。
$on在組件銷燬後不會自動解除綁定,若同一組件多次生成則會多次綁定事件,則會一次$emit,多次響應,需額外處理。
數據非“長效”數據,無法保存,只在$emit後生效。

特殊的eventBus?

bus皆爲導入的bus實例。

// bus
const bus = new Vue({
  data () {
    return {
      // 定義數據
      val1: ''
    }
  },
  created () {
    // 綁定監聽
    this.$on('updateData1', (val)=>{
      this.val1 = val
    })
  }
})

// 數據發出組件

import bus from 'xx/bus'
// 觸發在bus中已經綁定好的事件
bus.$emit('update1', '123')

// 數據接收組件

{{val1}}
// 使用computed接收數據
computed {
  val1 () {
    // 依賴並返回bus中的val1
    return bus.val1
  }
}
不同

正統的eventBus只是用來綁定和觸發事件,並不關心數據,不與數據發生交集。而這個方案多一步將數據直接添加在bus實例上。且事件監聽與數據添加需提前定義好。
數據接收方不再使用$on來得知數據變化,而是通過計算屬性的特徵被動接收。

解決的問題

通信組件需同時存在?數據在bus上存儲,所以沒有要求。
多次綁定?綁定監聽都在bus上,不會重複綁定。
數據只在$emit後可用?使用計算屬性直接讀取存在bus上的值,不需要再次觸發事件。

探討

爲什麼使用計算屬性
其實應該是爲什麼不能直接添加到data上,如data1: bus.data1?我們可以再看一段代碼,線上代碼。
將bus修改爲

data () {
  return {
    // 多一層結構
    val: {
      result: 0
    }
  }
},
created () {
  this.$on('update1', val => {
    console.log('觸發1', i1++)
    this.val.result = val
  })
}

數據接收組件改爲

// template
data中獲取直接修改值:{{dataResult}}
data中獲取直接修改值的父層:{{dataVal}}
computed中依賴直接修改值:{{computedResult}}
// js
data () {
    return {
      // 獲取直接修改值
      dataResult: bus.val.result,
      // 獲取直接修改值的父層
      dataVal: bus.val
    }
  },
  computed: {
    computedResult () {
      // 依賴直接修改值
      return bus.val.result
    }
  }

可以看到,data中獲取直接修改值時值的數據是無法動態響應的。
其實不用$emit觸發,使用bus.val = 1直接賦值也是可以的,那麼爲什麼不這麼做呢?
其實這種eventBus就是簡化版的vuex。
vue文檔中有這樣一段話:

組件不允許直接修改屬於 store 實例的 state,而應執行 action 來分發 (dispatch) 事件通知 store 去改變,我們最終達成了 Flux 架構。這樣約定的好處是,我們能夠記錄所有 store 中發生的 state 改變。

那麼可以用vuex中store對應bus實例,state對應data,action對應事件,dispatch對應$emit。
同時vuex中組件獲取數據的方式正是通過計算屬性,那麼其實vuex和Flux架構的理解和使用也沒有那麼難。


$emit,$on,$off 銷燬

關於 事件 的 激活與銷燬 來自github上Vue作者尤大大關於這問題的解答:
vm.$on() from within components stores component state in vm but doesn’t remove it when destroyed

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章