VUE組件通信的十種姿勢

父子組件通信

1餐禁、父子組件通過prop傳遞數(shù)據(jù)

父組件可以將一條數(shù)據(jù)傳遞給子組件血久,這條數(shù)據(jù)可以是動態(tài)的,父組件的數(shù)據(jù)更改的時候帮非,子組件接收的也會變化氧吐。

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

組件實例的作用域是孤立的,父組件不能直接使用子組件的數(shù)據(jù)末盔,子組件也不能直接使用父組件的數(shù)據(jù)筑舅。

父組件在調用子組件的時候給子組件傳遞數(shù)據(jù):

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

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

image

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

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

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

我們可以用 v-bind 來動態(tài)地將 prop 綁定到父組件的數(shù)據(jù)。每當父組件的數(shù)據(jù)變化時链峭,該變化也會傳導給子組件畦娄。

<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驗證傳遞過來的數(shù)據(jù)

我們可以為組件的 prop 指定驗證規(guī)則。如果傳入的數(shù)據(jù)不符合要求驳癌,Vue 會發(fā)出警告滑燃。這對于開發(fā)給他人使用的組件非常有用

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

類型驗證

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

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

規(guī)定傳遞過來的數(shù)值類型必須是number,否則系統(tǒng)會報錯

image

必傳驗證

規(guī)定父組件必須給子組件傳遞該值

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

默認值設置

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

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

自定義驗證

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

規(guī)定傳遞過來的數(shù)值必須要大于100乐严,否則系統(tǒng)會報錯

image

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

單向數(shù)據(jù)流

Prop 是單向綁定的:當父組件的屬性變化時衣摩,將傳遞給子組件昂验,但是反過來不會。這是為了防止子組件無意間修改了父組件的狀態(tài)昭娩,來避免應用的數(shù)據(jù)流變得難以理解凛篙。

<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

所以如果我們想實現(xiàn)父子間的數(shù)據(jù)共享,依靠的就是應用類型的地址傳遞升薯,應將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值谅海,子組件的數(shù)據(jù)同步更改,子組件修改value值的時候也同步修改了父組件的數(shù)據(jù)扭吁。這是因為不管是子組件還是父組件,我們操作的都是同一個對象侥袜,父組件直接把引用類型的地址傳遞給子組件,子組件沒有直接修改對象枫吧,只是更改了里面的屬性值。

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

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

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

5、viewmodel關系鏈

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

$parent:父組件

$children:子組件

$root:根組件

image

當子組件在set方法中修改父組件傳遞過來的值時,系統(tǒng)會報錯摊溶,因為子組件不能修改父組件的數(shù)據(jù)。

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

所以這時候要使用$parent莫换,讓父組件自己更改自己的數(shù)據(jù)

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

6、父組件通過ref標記獲取子組件的數(shù)據(jù)

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

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

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

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

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

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

注意多個子組件標記的是同一個鍵名巩掺,獲取到的應該是一個數(shù)組

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

運行效果:

image

子父組件通信

1、子組件通過父組件傳遞的方法來更改父組件的數(shù)據(jù)

父組件可以將更改自身數(shù)據(jù)的方法傳遞給子組件研儒,子組件調用這個方法的時候,就可以給父組件傳遞數(shù)據(jù)端朵,父組件被動的接收子組件的數(shù)據(jù)。

子組件聲明一條自身的msg

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

父組件先聲明一條自己的數(shù)據(jù)

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

再寫一個可以更改自身數(shù)據(jù)的方法

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

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

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

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

props:["change"]

給p標簽添加點擊事件,點擊即觸發(fā)change方法碗硬,同時將自身的msg傳遞給父組件瓤湘,相當于父組件的change方法被執(zhí)行砌创。

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

父組件可以在頁面中渲染子組件傳遞過來的數(shù)據(jù)

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

運行效果:

image

2、通過自定義事件實現(xiàn)子父通信

每一個組件或者實例都會有自定義事件住涉,和觸發(fā)事件的能力信柿,父組件給子組件綁定一個自定義事件醒第,這個事件的處理程序卻是父組件的一個方法,當子組件觸發(fā)這個事件的時候稠曼,相當于父組件的方法被執(zhí)行。

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

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

在子組件中定義一個點擊事件漠吻,點擊p標簽執(zhí)行changeWord方法

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

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

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

一旦觸發(fā)綁定在自身上的自定義事件试读,相當于父組件的change方法被執(zhí)行。

兄弟組件通信

1鹏往、通過viewmodel關系鏈

定義哥哥組件,給哥哥組件添加一個點擊事件伊履,點擊觸發(fā)hitLittle方法

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

定義弟弟組件,給弟弟組件添加一個p標簽唐瀑,由crying數(shù)據(jù)控制其顯示與隱藏

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

在弟弟組件的data中聲明crying數(shù)據(jù),默認為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狀態(tài)
            }
        }
    })

運行效果:

image

2当窗、viewmodel關系鏈+ref鏈

在弟弟組件中添加ref標記

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

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

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

3巫员、eventbus事件總線

創(chuàng)建一個空的實例

var angle = new Vue();

弟弟組件自己定義一個更改自身狀態(tài)的方法

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

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

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

在哥哥組件中觸發(fā)自定義事件

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

4唱遭、vuex狀態(tài)管理

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

Vuex是vue官方的一款狀態(tài)管理工具,什么是狀態(tài)呢司致?我們在前端開發(fā)中有一個概念:數(shù)據(jù)驅動,頁面中任意的顯示不同脂矫,都應該有一條數(shù)據(jù)來控制,而這條數(shù)據(jù)又叫做state霉晕,狀態(tài)。

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

(1)創(chuàng)建store

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

Vue.use(Vuex)

(2)設置state

state就是一個純對象渐溶,上面有一些狀態(tài)掛載

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荔茬,在函數(shù)體里更改竹海,這時,組件用到的數(shù)據(jù)也會更改斋配,實現(xiàn)響應式灌闺。

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

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

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

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

運行效果:

image
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蕉斜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌宅此,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件父腕,死亡現(xiàn)場離奇詭異,居然都是意外死亡璧亮,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進店門杜顺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蘸炸,你說我怎么就攤上這事〈钊澹” “怎么了?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵淹禾,是天一觀的道長。 經(jīng)常有香客問我铃岔,道長,這世上最難降的妖魔是什么毁习? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮纺且,結果婚禮上,老公的妹妹穿的比我還像新娘载碌。我一直安慰自己猜嘱,他們只是感情好,可當我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布弦撩。 她就那樣靜靜地躺著,像睡著了一般论皆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上纯丸,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天,我揣著相機與錄音觉鼻,去河邊找鬼。 笑死坠陈,一個胖子當著我的面吹牛,可吹牛的內容都是我干的仇矾。 我是一名探鬼主播庸蔼,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼姐仅,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了刻盐?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤敦锌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后乙墙,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡听想,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了哗魂。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡录别,死狀恐怖,靈堂內的尸體忽然破棺而出组题,到底是詐尸還是另有隱情,我是刑警寧澤崔列,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站赵讯,受9級特大地震影響盈咳,放射性物質發(fā)生泄漏边翼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一组底、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧债鸡,春花似錦、人聲如沸厌均。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽晶密。三九已至镊屎,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間缝驳,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工用狱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人夏伊。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像溺忧,于是被迫代替她去往敵國和親咏连。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,440評論 2 359

推薦閱讀更多精彩內容

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