1. 程式人生 > >【Vue】淺談Vue不同場景下組件間的數據交流

【Vue】淺談Vue不同場景下組件間的數據交流

事件 不同 name usm quest 數據流 這就是 ring des

淺談Vue不同場景下組件間的數據“交流” Vue的官方文檔可以說是很詳細了。在我看來,它和react等其他框架文檔一樣,講述的方式的更多的是“方法論”,而不是“場景論”,這也就導致了:我們在閱讀完文檔許多遍後,寫起代碼還是不免感到有許多困惑,因為我們不知道其中一些知識點的運用場景。這就是我寫這篇文章的目的,探討不同場景下組件間的數據“交流”的Vue實現

父子組件間的數據交流

父子組件間的數據交流可分為兩種: 1.父組件傳遞數據給子組件 2.子組件傳遞數據給父組件

父組件傳遞數據給子組件——props

技術分享 這是組件數據溝通中最常見的場景:你讓父組件掌握了數據源,然後傳遞給子組件,供子組件使用 技術分享

許多人會說,這很簡單!用props嘛! 對,正因如此,它不是我要講的主要內容,不過我們還是用代碼簡單過一遍: 父組件
<template>
  <div id="father">
    {{ ‘我是父組件‘ }}
    <son :text = "text"></son>
  </div>
</template>
 
<script>
import son from ‘./son.vue‘
export 
default { data: function () { return { text: ‘從父組件傳來的數據‘ } }, components: { son: son } } </script> <style scoped> </style>

子組件:
<template>
  <div>
    {{ ‘我是子組件,我接收了‘ + text }}
  </div>
</template>
 
<script>
export 
default { props: { text: { type: String, default: ‘‘ } } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> </style>

demo: 技術分享

在這個demo裏面,我們把“從父組件傳來的數據”這一個字符串通過props傳遞給了子組件 如果我們希望在子組件中改變父組件的數據的話,可以在父組件中定義一個能改變父組件數據的函數,然後通過props將該函數傳遞給子組件,並在子組件在適當時機調用該函數——從而起到在子組件中改變父組件數據的效果

子組件傳遞數據給父組件

子組件傳遞數據給父組件 方式一:回調傳參

技術分享 父組件:
<template>
  <div id="father">
    {{ ‘我是父組件,名稱是‘ + componentName }}
    <son  :changeComponentName = "changeComponentName"></son>
  </div>
</template>
 
<script>
import son from ‘./son.vue‘
export default {
  data: function () {
    return {
      componentName: ‘組件A‘
    }
  },
 
  methods: {
    changeComponentName: function (newComponentName) {
      this.componentName = newComponentName
    }
  },
 
  components: {
    son: son
  }
}
</script>
 
<style scoped>
  #father div{
    padding: 10px;
    margin: 10px;
    border: 1px solid gray;
  }
</style>

子組件:
<template>
  <div>
    <p>我是子組件:一個button</p>
    <button @click="() => changeComponentName(newComponentName)">
      把父組件的名稱修改為:彭湖灣的組件
    </button>
  </div>
</template>
 
<script>
export default {
  data: function () {
    return {
      newComponentName: ‘彭湖灣的組件‘
    }
  },
  props: {
    changeComponentName: {
      type: Function,
      default: () => { }
    }
  }
}
</script>
 
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

demo:

點擊前:

技術分享

點擊後:

技術分享

圖解:

技術分享

技術分享 點擊子組件(按鈕)的時候,將父組件的名稱從“A”修改為“彭湖灣的組件” 我們從父組件向子組件傳遞了一個函數(changeComponentName)。並在子組件調用這個函數的時候,以參數的形式傳遞了一個子組件內部的數據(newComponentName)給這個函數,這樣,在父組件中定義的函數(changeComponentName)就可以取得子組件傳來的參數了 【PS】 命名太長不好意思

子組件傳遞數據給父組件 方式二:自定義事件

技術分享 父組件:
<template>
  <div id="father">
    <div>
      {{ ‘我是父組件,我的名稱是:‘ + fatherComponentName }}
      <son  v-on:changeComponentName = "changeComponentName"></son>
    </div>
  </div>
</template>
 
<script>
import son from ‘./son.vue‘
export default {
  data: function () {
    return {
      fatherComponentName: ‘A組件‘
    }
  },
 
  methods: {
    changeComponentName: function (componentName) {
      this.fatherComponentName = componentName
    }
  },
 
  components: {
    son: son
  }
}
</script>
 
<style scoped>
  #father div{
    padding: 10px;
    margin: 10px;
    border:1px solid grey;
  }
</style>

子組件:
<template>
  <div>
    <p>我是子組件:一個按鈕</p>
    <button @click="clickCallback">
      修改父組件的名稱為:彭湖灣的組件
    </button>
  </div>
</template>
 
<script>
export default {
  data: function () {
    return {
      fatherComponentName: ‘彭湖灣的組件‘
    }
  },
  methods: {
    clickCallback: function () {
      this.$emit(‘changeComponentName‘, this.fatherComponentName)
    }
  }
}
</script>
 
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

demo:

點擊前:

技術分享

點擊後:

技術分享 技術分享 圖解: 技術分享

通過$emit(event, [...參數]),所有的參數將被傳遞給監聽器回調,也就是我們在父組件中定義的changeComponentName方法,從而實現從子組件中給父組件傳參

兄弟組件間的數據交流(有共同父組件的兄弟組件)

技術分享 父組件:
<template>
  <div id="father">
    <div>
      {{ ‘我是父組件:father‘ }}
      <eldest-son :text = "text"></eldest-son>
      <youngest-son :changeText="changeText"></youngest-son>
    </div>
  </div> 
</template>
 
<script>
import eldestSon from ‘./eldestSon.vue‘
import youngestSon from ‘./youngestSon.vue‘
 
export default {
  data: function () {
    return {
      text: ‘我是一行文本‘
    }
  },
 
  methods: {
    changeText: function () {
      this.text = ‘我是經過改動的一行文本‘
    }
  },
 
  components: {
    eldestSon: eldestSon,
    youngestSon: youngestSon
  }
}
</script>
 
<style>
    #father div{
      border: 1px solid grey;
      padding: 10px;
      margin: 10px;
    }
</style>

兄弟組件1:
<template>
  <div>
    <p>我是兄弟組件:eldestSon</p>
    <p>我有一個可變數據text:{{ text }}</p>
  </div>
</template>
 
<script>
export default {
  props: {
    text: {
      type: String,
      default: ‘‘
    }
  }
}
</script>
 
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

兄弟組件2:
<template>
  <div>
    <p>我是兄弟組件:youngestSon</p>
    <button @click="changeText">更改eldestSon兄弟組件中的文本</button>
  </div>
</template>
 
<script>
export default {
  props: {
    changeText: {
      type: Function,
      default: () => {}
    }
  }
}
</script>
 
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

點擊前:

技術分享

技術分享 點擊後: 技術分享

圖解:

技術分享

技術分享 如果兩個兄弟組件間存在這種數據關系的話,我們可以嘗試尋找其共同的父組件,使數據和相關方法“提升”到父組件內部,並向下傳給兩個子組件 這樣,其中一個子組件取得了數據,另外一個子組件取得了改變數據的方法,便可以實現上述的數據溝通 【註意】這種場景存在局限性,它要求兩個組件有共同父組件。對於這種場景之外的處理方法,請看下文

全局組件間的數據交流——Vuex

我上述的許多場景裏面,都運用到了props或者函數傳參的方式去處理組件間的數據溝通。然而在稍大型的應用裏面,它們都不約而同地給我們帶來了很大的麻煩 例如: 1.通過props從父組件向子組件傳遞數據 對於直接的父子關系的組件,數據流顯得很簡潔明確,但在大型應用裏面,我們上下嵌套許多個組件的時候,這就會導致我們的代碼非常地繁瑣,並難以維護 2.對於沒有共同的父組件的兄弟組件,函數傳參的數據傳遞方式也無能為力了,Vue文檔裏介紹到,你可以通過以$emit和$on函數為基礎的“事件總線”溝通數據,但它無法應對更加大型的應用 這個時候Vuex就成為了實現全局組件間數據交流的最佳方案了 技術分享 Vuex擁有一個包含全部頂層狀態的單一數據源(state) 1.所有的組件都可以使用這個單一數據源裏面的數據 2.所有的組件都可以通過派發 動作(actions)修改這個單一數據源裏的數據 技術分享

原本要“走很多彎路”才能實現溝通的數據流,一下子就找到了最短的捷徑

實現View層的數據和model層的解耦

在1,2小節中處理的數據(Vue)和第三小節中處理的數據(Vuex),在很多時候是兩種不同類型的數據,前者是屬於View層,僅負責單純的UI展示,而model層的大多是從後端取得後註入的數據。 一點建議: 1.Vue部分的代碼負責構建View層 2.Vuex部分的代碼負責構建model層 (上述的Vue指的是Vuex之外的框架體系) 以上述兩點為基礎,決定某部分的代碼到底要寫進Vue裏面還是寫進Vuex裏面,並盡量將兩者分開,從而實現View層和model層的解耦,提高前端代碼的可維護性和擴展性 技術分享

【Vue】淺談Vue不同場景下組件間的數據交流