VUE組件通信的十種姿勢

父子組件通信

1、父子組件通過prop傳遞數據

父組件可以將一條數據傳遞給子組件,這條數據可以是動態的,父組件的數據更改的時候,子組件接收的也會變化。

子組件被動的接收父組件的數據,子組件不要再更改這條數據了。

組件實例的作用域是孤立的,父組件不能直接使用子組件的數據,子組件也不能直接使用父組件的數據。

父組件在調用子組件的時候給子組件傳遞數據:

<template id="father">
        <div class="father">
            <p>我是父組件,這是我的fMsg:{{fMsg}}</p>
            <input type = "text" v-model = "fMsg">
            <hr>
            <son msg = "你好"></son>
        </div>
    </template>

父組件給子組件傳遞數據的時候,子組件需要利用props的屬性來確定自己的預期數據,如果兒子沒有通過props屬性接受傳遞過來的數據,則數據會以自定義屬性的方式,放在兒子最外層的根元素上面。

image

子組件通過props來接受父組件傳遞過來的數據,并且通過{{msg}}使用

components:{
            son:{
                template:"<div>我是son子組件!這是父組件傳遞給我的msg:{{msg}}</div>",
                //接收父組件傳遞來的屬性  msg
                props:["msg"]
            }
        }
image

2、父組件通過v-bind指令傳遞自身變量給子組件

我們可以用 v-bind 來動態地將 prop 綁定到父組件的數據。每當父組件的數據變化時,該變化也會傳導給子組件。

<template id="father">
        <div class="father">
            <p>我是父組件,這是我的fMsg:{{fMsg}}</p>
            <input type = "text" v-model = "fMsg">
            <hr>
            <!-- <son msg = "你好"></son> -->
            <son :msg = "fMsg"></son>
        </div>
    </template>

如果如果父組件傳遞屬性給子組件的時候鍵名有'-'

<son :f-msg = "fMsg"></son>

子組件接收、使用的時候寫成小駝峰的模式

components:{
            son:{
                template:"<div>我是son子組件!這是父組件傳遞給我的msg:{{fMsg}}</div>",
                //接收父組件傳遞來的屬性  msg
                props:["fMsg"]
            }
        }

3、prop驗證傳遞過來的數據

我們可以為組件的 prop 指定驗證規則。如果傳入的數據不符合要求,Vue 會發出警告。這對于開發給他人使用的組件非常有用

驗證主要分為:類型驗證、必傳驗證、默認值設置、自定義驗證

類型驗證

// 類型驗證
// num:Number //父組件傳遞過來的num必須是Number類型

// 添加多個類型
num: [Number,String],

規定傳遞過來的數值類型必須是number,否則系統會報錯

image

必傳驗證

規定父組件必須給子組件傳遞該值

//必傳驗證
// num:{
//     required: true
// }

默認值設置

當父組件不給子組件傳遞該值的時候,給子組件設定一個默認值

// 默認值設置
// num:{
//     default:100
// }

自定義驗證

//自定義驗證
                            num:{
                                validator(val){
                                    return val > 100
                                }
                            }

規定傳遞過來的數值必須要大于100,否則系統會報錯

image

4、父子組件依靠應用類型的地址傳遞共享數據

單向數據流

Prop 是單向綁定的:當父組件的屬性變化時,將傳遞給子組件,但是反過來不會。這是為了防止子組件無意間修改了父組件的狀態,來避免應用的數據流變得難以理解。

<template id="father">
        <div class="father">
            <input type = "text" v-model = "message">
            <hr>
            <son :message = "message"></son>
        </div>
    </template>

    <template id = "son">
        <div>
            <p>這是子組件</p>
            <input type = "text" v-model = "message"></input>
        </div>
    </template>

另外,每次父組件更新時,子組件的所有 prop 都會更新為最新值。這意味著你不應該在子組件內部改變 prop。如果你這么做了,Vue 會在控制臺給出警告。

image

所以如果我們想實現父子間的數據共享,依靠的就是應用類型的地址傳遞,應將message寫成對象的形式,傳遞的時候將對象傳遞給子組件,子組件引用的時候使用對象的value值。

<template id="father">
        <div class="father">
            <input type = "text" v-model = "message.value">
            <hr>
            <!-- 傳遞的時候將對象傳遞給子組件 -->
            <son :message = "message"></son>
        </div>
    </template>

    <template id = "son">
        <div>
            <p>這是子組件</p>
            <!-- 引用的時候使用對象的value值 -->
            <input type = "text" v-model = "message.value"></input>
        </div>
    </template>

這時候更改父組件的value值,子組件的數據同步更改,子組件修改value值的時候也同步修改了父組件的數據。這是因為不管是子組件還是父組件,我們操作的都是同一個對象,父組件直接把引用類型的地址傳遞給子組件,子組件沒有直接修改對象,只是更改了里面的屬性值。

父組件如果將一個引用類型的動態數據傳遞給子組件的時候,數據會變成雙向控制的,子組件改數據的時候父組件也能接收到數據變化,因為子組件改的時候不是在改數據(地址),而是在改數據里的內容,也就是說引用類型數據的地址始終沒有變化,不算改父組件數據。

注意:在 JavaScript 中對象和數組是引用類型,指向同一個內存空間,如果 prop 是一個對象或數組,在子組件內部改變它會影響父組件的狀態。 message:{val:""}

父子間數據共享(雙向控制),基本不會使用,違背了單向數據流(父=》子)

5、viewmodel關系鏈

在組件間可以用過ref形成ref鏈,組件還擁有一個關系鏈($parent),通過這兩種鏈;理論來說,任意的兩個組件都可以互相訪問,互相進行通信。

$parent:父組件

$children:子組件

$root:根組件

image

當子組件在set方法中修改父組件傳遞過來的值時,系統會報錯,因為子組件不能修改父組件的數據。

Vue.component("bbb",{
        template:"#bbb",
        props:["msg"],
        computed:{
            /* ownMessage(){
                return this.msg;
            } */
            ownMessage:{
                get(){
                    return this.msg;
                },
                set(val){
                    this.msg = val //系統報錯:子組件不能更改父組件傳遞的數據
                }
            }
        }
    })
image

所以這時候要使用$parent,讓父組件自己更改自己的數據

set(val){
                    // this.msg = val //系統報錯:子組件不能更改父組件傳遞的數據
                    // console.log(this)
                    // 相當于父組件自己更改了msg數據
                    this.$parent.msg = val;
                }

6、父組件通過ref標記獲取子組件的數據

父組件在調用子組件的時候使用ref做標記

<template id="aaa">
        <div>
            <button @click = "get">點擊獲取bbb數據</button>
            <!-- 組件間不僅可以用過$root/$parent/$children來獲取對應關系的組件,父組件還可以主動的通過ref為子組件做標記 -->
            <bbb ref = "b"></bbb>
        </div>
    </template>

父組件的this屬性上有$refs標記,通過refs標記拿到子組件

image
// 通過ref標記更改子組件的數據
// this.$refs.b.message = "哈哈"

組件間不僅可以用過$parent/children/root來獲取對應關系的組件,父組件還可以主動的通過ref為子組件做標記 也可以給dom做標記,也會形成ref鏈,也可以交互.

<button ref="btn" @click="get">get</button>
<bbb ref="b></bbb>  
image

注意多個子組件標記的是同一個鍵名,獲取到的應該是一個數組

<bbb ref = "b" v-for = "(item,index) in 3" :key = "index"></bbb>
image
// 通過下標修改對應的數值
this.$refs.b[0].message = "哈哈"

運行效果:

image

子父組件通信

1、子組件通過父組件傳遞的方法來更改父組件的數據

父組件可以將更改自身數據的方法傳遞給子組件,子組件調用這個方法的時候,就可以給父組件傳遞數據,父組件被動的接收子組件的數據。

子組件聲明一條自身的msg

Vue.component("son",{
        template:"#son",
        // 子組件接收父組件傳遞過來的方法
        props:["change"],
        data(){
            return{
                msg:"我是子組件"
            }
        }
    })

父組件先聲明一條自己的數據

data(){
            return{
                // 父組件先聲明一條自己的數據
                parentMsg:""
            }
        }

再寫一個可以更改自身數據的方法

methods:{
            // 寫一個可以更改自身數據的方法
            change(msg){
                this.parentMsg = msg
            }
        }

將寫好的change方法傳遞給子組件

<template id="father">
        <div>
            <p>這是父組件</p>
            <p>子組件傳遞過來的值是:{{parentMsg}}</p>
            <hr>
            <!-- 調用子組件的時候,將更改自身數據的方法傳遞給子組件 -->
            <son :change = "change"></son>
        </div>
    </template>

子組件通過props接收父組件傳遞過來的change方法

props:["change"]

給p標簽添加點擊事件,點擊即觸發change方法,同時將自身的msg傳遞給父組件,相當于父組件的change方法被執行。

<template id="son">
        <div>
            <p>子組件說:{{msg}}</p>
            <p @click = "change(msg)">點擊我觸發父親的change方法</p> 
        </div>
    </template>

父組件可以在頁面中渲染子組件傳遞過來的數據

<p>子組件傳遞過來的值是:{{parentMsg}}</p>

運行效果:

image

2、通過自定義事件實現子父通信

每一個組件或者實例都會有自定義事件,和觸發事件的能力,父組件給子組件綁定一個自定義事件,這個事件的處理程序卻是父組件的一個方法,當子組件觸發這個事件的時候,相當于父組件的方法被執行。

父組件想獲取子組件的數據時,在調用子組件的時候給子組件綁定一個自定義事件change-event

<template id="father">
        <div>
            <p>這是父組件</p>
            <p>子組件傳遞過來的值是:{{parentMsg}}</p>
            <hr>
            <!-- 給子組件綁定一個自定義事件 -->
            <son @change-event = "change"></son>
        </div>
    </template>

在子組件中定義一個點擊事件,點擊p標簽執行changeWord方法

<p @click = "changeWord">點擊我觸發父親的change方法</p> 

在方法中編寫changeWord方法,通過this.$emit來觸發綁定在自己身上的自定義事件,第一個參數為事件名稱change-event,第二個參數為觸發這個函數的時候給他傳遞的數值:自身的msg。

methods:{
            changeWord(){
                //觸發自身綁定的change事件
                this.$emit("change-event",this.msg)//第一個參數為觸發事件的名字,第二個參數為觸發這個函數的時候給他傳遞的數值
            }
        }

一旦觸發綁定在自身上的自定義事件,相當于父組件的change方法被執行。

兄弟組件通信

1、通過viewmodel關系鏈

定義哥哥組件,給哥哥組件添加一個點擊事件,點擊觸發hitLittle方法

<template id = "big-brother">
        <div>
            <p>我是哥哥</p>
            <button @click = "hitLittle">打弟弟</button>
        </div>
    </template>

定義弟弟組件,給弟弟組件添加一個p標簽,由crying數據控制其顯示與隱藏

<template id="little-brother">
        <div>
            <p>我是弟弟</p>
            <p v-if = "crying">嗚嗚嗚</p>
        </div>
    </template>

在弟弟組件的data中聲明crying數據,默認為false

Vue.component("little-brother",{
        template:"#little-brother",
        data(){
            return{
                crying:false
            }
        }
    })

在哥哥組件的methods中定義hitLittle方法,通過viewmodel關系鏈更改弟弟組件中的crying方法

 Vue.component("big-brother",{
        template:"#big-brother",
        methods:{
            hitLittle(){
                //在兄弟組件之間的通信,可以采用關系鏈和ref鏈去使用,解決兄弟之間通信問題。
                this.$parent.$children[1].crying = true;//讓littel改變自身的crying狀態
            }
        }
    })

運行效果:

image

2、viewmodel關系鏈+ref鏈

在弟弟組件中添加ref標記

<little-brother ref = "little"></little-brother>

在哥哥組件的hitLittle方法中通過viewmodel和ref鏈配合使用更改弟弟組件中的crying數據

hitLittle(){
                //在兄弟組件之間的通信,可以采用關系鏈和ref鏈去使用,解決兄弟之間通信問題。
                // this.$parent.$children[1].crying = true;//讓littel改變自身的crying狀態
                
                //viewmodel鏈和ref鏈配合使用
                this.$parent.$refs.little.crying = true;
            }

3、eventbus事件總線

創建一個空的實例

var angle = new Vue();

弟弟組件自己定義一個更改自身狀態的方法

methods:{
            cry(){
                this.crying = true
            }
        }

在mounted生命周期函數中綁定一個自定義事件,第一個參數為自定義事件名,第二個函數為需要處理的函數

mounted(){
            // 綁定一個自定義事件,第一個參數為自定義事件名,第二個函數為需要處理的函數
            angle.$on("hit-little",this.cry)
        }

在哥哥組件中觸發自定義事件

hitLittle(){
                //觸發little-brother組件的hit-little事件
                angle.$emit("hit-little")
            }

4、vuex狀態管理

vuex是vue提供的一個全局的狀態管理工具,主要處理項目中多組件間狀態共享。

Vuex是vue官方的一款狀態管理工具,什么是狀態呢?我們在前端開發中有一個概念:數據驅動,頁面中任意的顯示不同,都應該有一條數據來控制,而這條數據又叫做state,狀態。

在vue中。組件間進行數據傳遞、通信很頻繁,而父子組件和非父子組件的通信功能也比較完善,但是,唯一困難的就是多組件間的數據共享,這個問題由vuex來處理

(1)創建store

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

(2)設置state

state就是一個純對象,上面有一些狀態掛載

state: {
    num:0,
    name:"list"
  }

(3)在根實例里配置store

這樣,我們就可以在任意的組件中通過this.$store來使用關于store的api

import store from './store/index'

Vue.config.productionTip = false

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

(4)在Home組件中使用state

computed:{
    ...mapState({
      num:state=>state.num
    })
  },

(5)使用mutations更改state

mutations也是一個純對象,里面包含很多更改state 的方法,這些方法的形參接收到state,在函數體里更改,這時,組件用到的數據也會更改,實現響應式。

mutations: {
    changeNum(state){
      state.num++
    }
  }

(6)在組件中調用mutations方法,更改組件中的state。

//使用vuex提供的mapMutations幫助我們在組件中調用mutations方法
...mapMutations(["changeNum"]),

//給按鈕添加點擊事件
<button @click = "changeNum">點擊更改num值</button>

運行效果:

image
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,818評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,185評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,656評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,647評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,446評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,951評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,041評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,189評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,718評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,800評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,419評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,420評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,755評論 2 371

推薦閱讀更多精彩內容

  • 什么是組件? 組件 (Component) 是 Vue.js 最強大的功能之一。組件可以擴展 HTML 元素,封裝...
    youins閱讀 9,507評論 0 13
  • 作為一個合格的開發者,不要只滿足于編寫了可以運行的代碼。而要了解代碼背后的工作原理;不要只滿足于自己的程序...
    六個周閱讀 8,466評論 1 33
  • 組件(Component)是Vue.js最核心的功能,也是整個架構設計最精彩的地方,當然也是最難掌握的。...
    六個周閱讀 5,632評論 0 32
  • 此文基于官方文檔,里面部分例子有改動,加上了一些自己的理解 什么是組件? 組件(Component)是 Vue.j...
    陸志均閱讀 3,838評論 5 14
  • 我們都是一個人來,最后也是一個人離開,從頭到尾,我們都是一個人的存在。可人最開始是由群居動物進化而來,所以...
    書冉Daisy閱讀 614評論 2 12