Vue2元件間通訊

2022-11-28 12:02:07

Vue2元件通訊的基礎方式

自己的理解:元件化通訊,無非就是資料你傳我,我傳你,兩個元件的相互交流,方法很多,下方有圖示(此篇建議小白閱讀,大神的話也不會看,哈哈哈哈!僅供參考,有不同的意見可以一起交流!)

  1. 父傳子(父元件傳給子元件資料)
  2. 子傳父(子元件傳給父元件資料)
  3. 任意元件間通訊

父元件給子元件傳資料

​ 我的理解是:如果建議使用props的方式,那我們就來了解一下props

props傳資料:
	解釋:一個元件需要顯式宣告它所接受的 props,這樣 Vue 才能知道外部傳入的哪些是 props
	(你要是想用父元件的傳下來的資料,你肯定得先傳呀,父元件傳完之後,就是子元件接收了,這之後就要用到props來接收了,接收的型別很多,字串呀,物件呀,陣列呀,布林值呀,其中props中的屬性,最終都會出現在VueComponent的範例物件上,也就是說,會暴露在當前this上)
	1.props宣告:
		1.1 為什麼要宣告?你不宣告怎麼知道外部傳來的是哪個props
		1.2 宣告定義的型別有很多
			1.2.1 最簡單的字串陣列的宣告方式(只接收): props:['foo'] 
			1.2.2 稍微微微的有點小變化(限制型別):props:{name:'String'}
			1.2.3 稍微有點多的物件方式來宣告(可以指定傳遞的型別進行校驗,限制必要性):
				 props:{
                    name:{
                    type:String, //型別
                    required:true, //必要性
                    default:'xxx' //預設值
                    }
       	備註:props是唯讀的,Vue底層會監測你對props的修改,如果進行了修改,就會發出警告,若業務需求確實需要修改,那麼請複製props的內容到data中一份,然後去修改data中的資料。
		2. 細節
			2.1很多小夥伴困擾,該怎麼起名字,要有什麼規範嗎?
		 	我平常起名字的話也是有點小隨意,但是正在改進,主要還是英語限制了,跑題了!!!
			如果一個 prop 的名字很長,強烈建議使用 camelCase 形式或者 kebab-case ,建議Vue官方的推薦,這種方式不管從美觀度還是可讀性都是極好的,也是JavaScript合法的識別符號,不比我們自己起的好?如果英語基礎不是很好,可以去有道之類的一些查詞軟體上查,不斷提升自己的命名能力!
			那我們在多說一點吧,可以大說是小夥伴都知道,對於元件名我們推薦使用 PascalCase 寫法,使用元件單閉合的形式,這樣能更好的區分原生的標籤
		 2.2 props 動態和靜態的理解
		  分為動態和靜態,但是在我們實際開發中,用的動態還是比較多的,很少傳靜態,
			動態: 我們可以通過 v-bind 來動態繫結 props
                <!-- 根據一個變數的值動態傳入 -->
                <BlogPost :title="post.title" />
                <!-- 根據一個更復雜表示式的值動態傳入 -->
                <BlogPost :title="可以傳遞一個方法,表示式等" />
		 	2.3 實際上任何型別的值都可以作為 props 的值被傳遞。String,Number,Boolean,Array,Object
			2.4 有時候我們傳遞的不只是一個屬性,把物件傳遞過去,使用一個物件傳遞多個props,
		   		如果你想要將一個物件的所有屬性都當作 props 傳入,你可以使用沒有引數的 v-bind,即只使用 v-bind 而非 :prop-name
					   <BlogPost v-bind="post" />
				等價於:<BlogPost :id="post.id" :title="post.title" />

嵌入程式碼更易於理解

子元件給父元件傳資料

1.最笨重的方法,但是有效

​ 就是利用props傳遞,有人會說,props不是父給子傳嗎?其實有一種方法是可以實現子給父傳遞資料的

我們需要利用props給子元件傳遞有參方法,子元件接收並呼叫傳遞引數,資料以引數的形式傳遞給父元件,此時父元件拿到的引數就是子元件中的資料來實現,以此子傳父.

嵌入程式碼

2.相對於方法1稍微好點

​ 2.1 一種元件間通訊的方式,適用於:子元件 ===> 父元件

​ 2.2 使用場景:A是父元件,B是子元件,B想給A傳資料,那麼就要在A中給B繫結自定義事件(事件的回撥在A中)。

​ 2.3 繫結自定義事件:第一種方式,在父元件中:<Demo @taoTao="test"/><Demo v-on:taoTao="test"/>

​ 第二種方式,在父元件中:

<Demo ref="demo"/>
......
mounted(){
   this.$refs.xxx.$on('taoTao',this.test)
}
  1. 若想讓自定義事件只能觸發一次,可以使用once修飾符,或$once方法。

  2. 觸發自定義事件:this.$emit('taoTao',資料)

  3. 解綁自定義事件this.$off('taoTao')

  4. 元件上也可以繫結原生DOM事件,需要使用native修飾符。

  5. 注意:通過this.$refs.xxx.$on('taoTao',回撥)繫結自定義事件時,回撥要麼設定在methods中要麼用箭頭函數,否則this指向會出問題!

任意元件間通訊(全域性事件匯流排(GlobalEventBus))

任意元件間通訊的方法:全域性事件匯流排

​ 前面兩種父傳子,子傳父,也只能解決比較簡單的問題,如果跨級傳遞,或者是兄弟之間傳遞,操作起來就很繁瑣,所以我們就定義出來了一種 全域性事件匯流排的方法來解決任意元件間通訊,說白了就是:

​ 1.全域性事件匯流排的介紹:A元件和B元件是兄弟元件,現在我想把A元件的資料傳遞給B元件進行使用,我們就需要把一個東西作為傀儡(中間人),然後A元件把資料傳給傀儡,B元件從傀儡中獲得A元件傳遞的值,這樣就可以實現任意元件間的通訊,你可能會有疑問,那麼多元件都給傀儡的話,如何區分是哪個元件傳遞的,這是就需要傳遞過來的資料攜帶一個標識,方便使用,使用完要銷燬,不然壓力會很大,這就是全域性事件匯流排的工作流程。那我們應該如何書寫呢?

​ 2.安裝全域性事件匯流排

那我就要給你們細講了:全域性事件匯流排有兩個特點:首先我們得叫所有的元件都能存取到這個事件,其次是能有$emit,$on,$off等這些屬性,我們就會想到Vue或者是VueComponent,其中我們會用

一個重要的內建關係:VueComponent.prototype.__proto__ === Vue.prototype

我們可以這樣定義全域性事件匯流排:

new Vue({
	......
	beforeCreate() {
		Vue.prototype.$bus = this //安裝全域性事件匯流排,$bus就是當前應用的vm
	},
    ......
}) 

3.使用全域性事件匯流排

​ 3.1 接收資料:A元件想接收資料,則在A元件中給$bus繫結自定義事件,事件的回撥留在A元件自身。

methods(){
  demo(data){......}
}
......
mounted() {
  this.$bus.$on('xxxx',this.demo)
}

​ 3.2 提供資料:this.$bus.$emit('xxxx',資料)

  1. 最好在beforeDestroy勾點中,用$off去解綁當前元件所用到的事件。

訊息訂閱與釋出(pubsub)

  1. 一種元件間通訊的方式,適用於任意元件間通訊

  2. 使用步驟:

    1. 安裝pubsub:npm i pubsub-js

    2. 引入: import pubsub from 'pubsub-js'

    3. 接收資料:A元件想接收資料,則在A元件中訂閱訊息,訂閱的回撥留在A元件自身。

      methods(){
        demo(data){......}
      }
      ......
      mounted() {
        this.pid = pubsub.subscribe('xxx',this.demo) //訂閱訊息
      }
      
    4. 提供資料:pubsub.publish('xxx',資料)

    5. 最好在beforeDestroy勾點中,用PubSub.unsubscribe(pid)取消訂閱。

插槽

  1. 作用:讓父元件可以向子元件指定位置插入html結構,也是一種元件間通訊的方式,適用於 父元件 ===> 子元件

  2. 分類:預設插槽、具名插槽、作用域插槽

  3. 使用方式:

    1. 預設插槽:

      父元件中:
              <Category>
                 <div>html結構1</div>
              </Category>
      子元件中:
              <template>
                  <div>
                     <!-- 定義插槽 -->
                     <slot>插槽預設內容...</slot>
                  </div>
              </template>
      
    2. 具名插槽:

      父元件中:
              <Category>
                  <template slot="center">
                    <div>html結構1</div>
                  </template>
      
                  <template v-slot:footer>
                     <div>html結構2</div>
                  </template>
              </Category>
      子元件中:
              <template>
                  <div>
                     <!-- 定義插槽 -->
                     <slot name="center">插槽預設內容...</slot>
                     <slot name="footer">插槽預設內容...</slot>
                  </div>
              </template>
      
    3. 作用域插槽:

      1. 理解:資料在元件的自身,但根據資料生成的結構需要元件的使用者來決定。(games資料在Category元件中,但使用資料所遍歷出來的結構由App元件決定)

      2. 具體編碼:

        父元件中:
        		<Category>
        			<template scope="scopeData">
        				<!-- 生成的是ul列表 - ->
        				<ul>
        					<li v-for="g in scopeData.games" :key="g">{{g}}</li>
        				</ul>
        			</template>
        		</Category>
        
        		<Category>
        			<template slot-scope="scopeData">
        				<!-- 生成的是h4標題 -->
        				<h4 v-for="g in scopeData.games" :key="g">{{g}}</h4>
        			</template>
        		</Category>
        子元件中:
                <template>
                    <div>
                        <slot :games="games"></slot>
                    </div>
                </template>
        		
                <script>
                    export default {
                        name:'Category',
                        props:['title'],
                        //資料在子元件自身
                        data() {
                            return {
                                games:['紅色警戒','穿越火線','勁舞團','超級瑪麗']
                            }
                        },
                    }
                </script>
        

最後一種就是Vuex

之後再更新..........