vue 組件通訊

組件之間的通訊簡(jiǎn)述:
父子組件的關(guān)系可以總結(jié)為 props 向下傳遞,事件event向上傳遞
祖先組件和后代組件(跨多代)的數(shù)據(jù)傳遞,可以使用provide和inject來實(shí)現(xiàn)
跨組件或者兄弟組件之間的通信,可以通過eventBus或者vuex等方式來實(shí)現(xiàn)

  1. 頁面級(jí)組件傳值
    • 通過路由帶參數(shù)進(jìn)行傳值
    • 通過設(shè)置 sessionStorage緩存的形式進(jìn)行傳遞
  2. 父子組件傳值
    • 父?jìng)髯?code>props,子傳父$emit
      • .sync
      • v-model
    • $parent$children
  3. 后代組件傳值
    • provide / inject
    • $attrs$listeners
  4. 跨組件或者兄弟組件之間傳值
    • 小項(xiàng)目少頁面用eventBus
    • 大項(xiàng)目多頁面使用 vuex

頁面級(jí)組件傳值

1. 通過路由帶參數(shù)進(jìn)行傳值

//兩個(gè)組件 A和B,A組件通過query把orderId傳遞給B組件(觸發(fā)事件可以是點(diǎn)擊事件、鉤子函數(shù)等)
this.$router.push({ path: '/f4', query: { orderId: 123 } }) //跳轉(zhuǎn)到f4
//在B組件中獲取A組件傳遞過來的參數(shù)
this.$route.query.orderId
<router-link to="/f4?orderId=123">router-link 進(jìn)入Father4</router-link>
<router-view></router-view>

2. 通過設(shè)置 Session Storage緩存的形式進(jìn)行傳遞

//兩個(gè)組件A和B,在A組件中設(shè)置緩存orderData
const orderData = { 'orderId': 123, 'price': 88 }
sessionStorage.setItem('orderInfo', JSON.stringify(orderData))

//B組件就可以獲取在A中設(shè)置的緩存了
const orderInfo = JSON.parse(sessionStorage.getItem('orderInfo'))

父子組件傳值

1. 父?jìng)髯?code>props,子傳父$emit

  • .sync
//父組件
<template>
    <div>
        父組件:{{title}}
        <childDom :title.sync="title"></childDom>
    </div>
</template>

<script>
import childDom from '../components/Father3-Child'
export default {
    data(){
        return {
            title:'簡(jiǎn)單我的簡(jiǎn)單'
        }
    },
    components:{childDom}
}
</script>
//子組件
<template>
    <div>
        <div>子組件:{{title}}</div>
        <button @click="$emit('update:title','哈哈哈')">點(diǎn)我更新父組件的數(shù)據(jù)</button>
    </div>
</template>

<script>
export default {
    props:['title'],
}
</script>
  • v-model
//父組件
<template>
  <div>
    <aa class="abc" v-model="test" ></aa> 
    {{'外面的值:' + test}}
    <button @click="fn">外面改變里面</button> 
  </div>
</template>

<script>
  import aa from './aa'
  export default {
    data () {
      return {
        test: ''
      }
    },
    methods: {
      fn () {
        this.test += 1 
      }
    },
    components:{
      aa
    }
  }
</script>
//子組件
<template>
  <div>
    {{'里面的值:'+ msg}}
    <button @click="fn2">里面改變外面</button>
  </div>
</template>

<script>
  export default {
    /**
     * 使用model, 這里有2個(gè)屬性
     * prop屬性說,父組件的v-model的值就是msg
     * event說,我emit ‘cc’ 的時(shí)候,父組件v-model的值就是參數(shù)的值
     */
    model: {
      prop: 'msg',
      event: 'cc'
    },
    props: {
      msg: ''
    },
    methods: {
      fn2 () {
        this.$emit('cc', this.msg+2)
      }
    }
  }
</script>

2. $parent$children

在組件內(nèi)部可以直接通過子組件$parent對(duì)父組件進(jìn)行操作,父組件通過$children對(duì)子組件進(jìn)行操作.

//父組件
<template>
    <div>
        <p>fatherMessage:{{fatherMessage}}</p>
        <button @click="changeChildValue">改變子組件的數(shù)據(jù)childMessage</button >
        <child></child>
        <child2></child2>
    </div>
</template>

<script>
import child from '../components/Father4-Child'
import child2 from '../components/Father4-Child2'
export default {
    data(){
      return {
        fatherMessage:'hello'
      }
    },
    components:{child,child2},
    methods:{
        changeChildValue(){
            this.$children[0].childMessage = 'hello';
            this.$children[1].childMessage = 'hello2';
        }
    }
}
</script>
//子組件1
<template>
    <div class="container">
        child
        <input type="text" v-model="childMessage" @input="changeValue">
    </div>
</template>

<script>
export default {
    // props:{
    //   value:String, //v-model會(huì)自動(dòng)傳遞一個(gè)字段為value的prop屬性
    // },
    data(){
      return {
        childMessage:this.value
      }
    },
    methods:{
      changeValue(){
        this.$parent.fatherMessage = this.childMessage;//通過如此調(diào)用可以改變父組件的值
      }
    },
}
</script>
//子組件2
<template>
    <div class="container">
        child2
        <input type="text" v-model="childMessage" @input="changeValue">
    </div>
</template>

<script>
export default {
    // props:{
    //   value:String, //v-model會(huì)自動(dòng)傳遞一個(gè)字段為value的prop屬性
    // },
    data(){
      return {
        childMessage:this.value
      }
    },
    methods:{
      changeValue(){
        this.$parent.fatherMessage = this.childMessage;//通過如此調(diào)用可以改變父組件的值
      }
    },
}
</script>

后代組件傳值(父組件與子、孫子、曾孫子組件傳值)

1. provide / inject

provide / inject 可以以一個(gè)祖先組件向所有子孫后代注入依賴。
簡(jiǎn)單的來說就是在父組件中通過provide來提供變量,然后在后代組件中通過inject來注入變量,不僅限于prop的父子組件數(shù)據(jù)交互,只要在上一層級(jí)的聲明的provide,那么下一層級(jí)無論多深都能夠通過inject來訪問到provide的數(shù)據(jù)

//父組件
<template>
    <div>
        <son></son>
    </div>
</template>

<script>
import son from '../components/son';
export default {
    provide: {
        foo: 'bar'
    },
    components:{son}
}
</script>
//子組件
<template>
    <div>
        我是子組件{{foo}}
        <grandson></grandson>
    </div>
</template>

<script>
import grandson from '../components/grandson'
export default {
    inject: ['foo'],
    components:{grandson}
}
</script>
//孫子組件
<template>
    <div>
        我是孫子組件{{foo}}
    </div>
</template>

<script>
export default {
    inject: ['foo'],
}
</script>
通過 provide / inject 后代組件都可以訪問父組件的數(shù)據(jù)

2. $attrs$listeners

通過$attrs屬性將父組件的數(shù)據(jù)(不作為 prop 被識(shí)別的數(shù)據(jù))傳遞給子組件、孫子組件、曾孫子組件等后代組件

$listeners屬性是一個(gè)對(duì)象,里面包含了作用在這個(gè)組件上的所有監(jiān)聽器,我們?cè)谧咏M件上綁定v-on=”$listeners”, 就可以在父組件中監(jiān)聽孫子組件、曾孫子組件觸發(fā)的事件,就能把孫子組件、曾孫子組件等后代組件發(fā)出的數(shù)據(jù),傳遞給父組件。

//父組件
<template>
 <div>
    {{coo}}
   <child-dom
    :foo="foo"
    :coo="coo"
     @upRocket="reciveRocket">
   </child-dom>
 </div>
</template>
<script>
 import childDom from "../components/Father2-Child";
 export default {
   name:'demoNo',
   data() {
        return {
            foo:"Hello, world",
            coo:"Hello,rui"
        }
    },
    components:{childDom},
    methods:{
        reciveRocket(ev){
            this.coo = ev;//改變數(shù)據(jù)
            console.log(this.coo)
        }
    }
}
</script>
//子組件
<template>
    <div>
        <p>foo:{{foo}}</p>
        <p>attrs:{{$attrs}}</p>
        <childDomChild v-bind="$attrs" v-on="$listeners"></childDomChild>
    </div>
</template>
<script>
import childDomChild from '../components/Father2-Child-Child';
export default {
    props:["foo"],
    components:{childDomChild}
}
</script>
//孫子組件
<template> 
    <div>
    <p>coo:{{$attrs.coo}}</p>
    <button @click="startUpRocket">我要發(fā)射火箭</button>
    </div>
</template>
<script>
 export default {
    methods:{
        startUpRocket(){
            this.$emit("upRocket",'簡(jiǎn)單我的簡(jiǎn)單');
        }      
    }
 }
</script>

跨組件或者兄弟組件之間傳值

小項(xiàng)目少頁面用eventBus

總結(jié):
EventBus 又稱為事件總線,在Vue中可以使用 EventBus 來作為溝通橋梁,就像是所有組件共用相同的事件中心,可以向該中心注冊(cè)發(fā)送事件或接收事件,所有組件都可以上下平行地通知其他組件
在需要傳值的組件中用eventBus.$emit觸發(fā)一個(gè)自定義事件,并傳遞參數(shù)
在需要接收數(shù)據(jù)的組件中用eventBus.$on監(jiān)聽自定義事件,并在回調(diào)函數(shù)中處理傳遞過來的參數(shù)
EventBus原理是發(fā)布訂閱
eventBus容易導(dǎo)致命名沖突,所以大項(xiàng)目要用vuex

<template>
    <div>
        <brother1></brother1>
        <brother2></brother2>
    </div>
</template>

<script>
import {eventBus} from '../components/eventBus.js';
let brother1 = {
    template:'<div>{{color}} <button @click="fnEmit2">變紅</button></div>',
    data(){
        return {color:'紅色',old:'紅色'}
    },
    created(){
        eventBus.$on('changeColor1',(val)=>{ // 綁定自定義事件
            this.color = val;
        })
    },
    methods:{
        fnEmit2(){
            eventBus.$emit('changeColor2',this.old) // 觸發(fā)自定義事件
        }
    }
}
let brother2 = {
    template:'<div>{{color}} <button @click="fnEmit1">變綠</button></div>',
    data(){
        return {color:'綠色',old:'綠色'}
    },
    created(){
        eventBus.$on('changeColor2',(val)=>{
            this.color = val;
        })
    },
    methods:{
        fnEmit1(){
            eventBus.$emit('changeColor1',this.old)
        }
    }
}

export default {
    components:{
        brother1,brother2
    }
}

</script>
//eventBus.js
import Vue from 'vue';
export const eventBus = new Vue();

大項(xiàng)目多頁面使用 vuex

vuex主要借鑒了flux redux,vuex只能在vue中使用(單獨(dú)為vue開發(fā)的)
vuex為大型項(xiàng)目而生,主要是(狀態(tài))管理,狀態(tài)指的是數(shù)據(jù),將數(shù)據(jù)統(tǒng)一管理
每一個(gè)vuex應(yīng)用的核心是store,store是一個(gè)容器
不能直接改變store中的狀態(tài),通過commit一個(gè)mutation來更改狀態(tài)

vuex計(jì)數(shù)器項(xiàng)目架構(gòu)圖
//main.js
import Vue from 'vue';
import App from './App.vue';
import store from './store'

//計(jì)數(shù)器
new Vue({
    el:'#app',
    ...App,
    store, //store被注冊(cè)到了實(shí)例上 所有組件都會(huì)有this.$store這個(gè)屬性
})
//store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
import logger from 'vuex/dist/logger'; //logger是一個(gè)日志插件
Vue.use(Vuex);
//容器是唯一的 不可以更改 所以用const比較好 
const state={count:0}; 
const getters={ //相當(dāng)于computed
    val:(state)=>state.count%2 ? '奇數(shù)' : '偶數(shù)'
};
import mutations from './mutations';
export default new Vuex.Store({
    state,
    mutations,
    getters, 
    plugins:[logger()],
    strict:true //嚴(yán)格模式 只能通過mutation(管理員)來更改狀態(tài),mutation不支持異步
})
//App.vue
<template>
    <div>
        <Counter></Counter>
    </div>
</template>

<script>
import Counter from './components/Counter'
export default {
    data(){
        return {
            msg:'hello',
        }
    },
    components:{
        Counter
    }
}
</script>
//Counter.vue
 <template>
     <div>
         計(jì)數(shù)器:<button @click="reduce">-</button>
         <br>
         當(dāng)前:{{$store.state.count}}<br>
         計(jì)數(shù)器:<button @click="add">+</button><br>
         {{$store.getters.val}}
     </div>
 </template>
 
 <script>
 import * as Types from '../store/mutations-types'; 
 export default {
    data(){
        return {
            msg:'hello',
        }
    },
    methods:{
        add(){ 
            this.$store.commit(Types.INCREMENT,2); //提交add的mutation, 2是載荷payload
        },
        reduce(){
            this.$store.commit(Types.DECREMENT,1);
        }
    }
 }
 </script>
// store/mutations.js
import * as Types from './mutations-types';
const mutations={
    [Types.INCREMENT](state,count){ //state是自動(dòng)放入的,默認(rèn)指的就是當(dāng)前的state
        state.count+=count;
    },
    [Types.DECREMENT](state,count){
        state.count-=count;
    }
};
export default mutations;
// store/mutations-types.js
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 有三種,分別是1、父組件向子組件傳值;2、子組件向父組件傳值;3、非父子組件傳值; 父向子傳值:父組件定義一個(gè)屬性...
    hudaren閱讀 172評(píng)論 0 0
  • 前言 組件是 vue.js最強(qiáng)大的功能之一,而組件實(shí)例的作用域是相互獨(dú)立的,這就意味著不同組件之間的數(shù)據(jù)無法相互引...
    用技術(shù)改變世界閱讀 2,304評(píng)論 1 3
  • 組件是vue最主要的語法特性之一,組件可以擴(kuò)展 HTML 元素,封裝可重用的代碼。在較高層面上,組件是自定義元素,...
    前端一菜鳥閱讀 387評(píng)論 0 4
  • 父子通訊 父組件向子組件通訊(單向數(shù)據(jù)流傳遞,子組件不應(yīng)該改變父組件里面數(shù)據(jù)的值),父組件代碼如下 父組件在調(diào)用子...
    Hachiman閱讀 304評(píng)論 0 1
  • 摘要: 總有一款合適的通信方式。 作者:浪里行舟 Fundebug經(jīng)授權(quán)轉(zhuǎn)載,版權(quán)歸原作者所有。 前言 組件是 v...
    Fundebug閱讀 15,646評(píng)論 3 57

友情鏈接更多精彩內(nèi)容