組件之間的通訊簡(jiǎn)述:
父子組件的關(guān)系可以總結(jié)為 props 向下傳遞,事件event向上傳遞
祖先組件和后代組件(跨多代)的數(shù)據(jù)傳遞,可以使用provide和inject來實(shí)現(xiàn)
跨組件或者兄弟組件之間的通信,可以通過eventBus或者vuex等方式來實(shí)現(xiàn)
- 頁面級(jí)組件傳值
- 通過路由帶參數(shù)進(jìn)行傳值
- 通過設(shè)置
sessionStorage緩存的形式進(jìn)行傳遞
- 父子組件傳值
- 父?jìng)髯?code>props,子傳父
$emit.syncv-model
-
$parent和$children
- 父?jìng)髯?code>props,子傳父
- 后代組件傳值
provide / inject-
$attrs和$listeners
- 跨組件或者兄弟組件之間傳值
- 小項(xiàng)目少頁面用
eventBus - 大項(xiàng)目多頁面使用
vuex
- 小項(xiàng)目少頁面用
頁面級(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>

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)

//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';