六种通信方式

一、Props

  • 父与子组件通信
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <Child :name='name' :func='func' />

    // 三种子组件接收形式
    props: ['name']
    props:{
    name:String
    }
    props:{
    name:{
    type:String,
    required:true,
    default:'name'
    }
    }
  • 路由Props
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    {
    name:'home',
    path:'/home',
    componenet: Home,

    // 三种形式
    props:true,
    props:{key:'value'},
    props:($route)=>{
    return {
    id: $route.query.id,
    title: $route.query.title
    }
    }
    }

二、自定义事件

  • 适用子与父组件通信
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // 两种事件绑定方式
    <Child @parentEvent='eventFunc' ref='child' />
    mounted(){
    this.$refs.child.$on('parentEvent',this.eventFunc);
    this.$refs.child.$once('parentEvent',this.eventFunc);
    }

    // 触发
    emitFunc(){
    this.$emit('parentEvent',params),
    }
    // 取消绑定
    unbindFunc(){
    this.$off('parentEvent')
    this.$off(['parentEvent','event2'])
    }

三、全局事件总线

  • 任意组件间通信
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // Vue原型链上绑定$bus
    beforeCreate(){
    Vue.prototype.$bus = this;
    },

    // 组件1事件绑定
    component1Func(){
    this.$bus.$on('event',this.func)
    }
    // 取消绑定
    beforeDestroy(){
    this.$bus.$off('event',this.func)
    }
    // 组件2事件触发
    component2Func(){
    this.$bus.$emit('event',params)
    }

四、pubsub-js

  • 任意组件间通信
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import pubsub from 'pubsub-js'
    // 订阅与取消订阅
    mounted(){
    this.pubId = pubsub.subscribe('newsName',this.callbackFunc)
    }
    beforeDestroy(){
    pubsub.unsubscribe(this.pubId)
    }
    // 发布
    sendNewsFunc(){
    pubsub.publish('newsName',params)
    }

五、Vuex

  • 任意组件间通信

store/index.js

1
2
3
4
5
6
7
8
9
// 模块化
Vue.use(Vuex)
import user from './user.js'
export default {
modules: {
user
}
}

store/user.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 处理业务逻辑 
const actions = {
action1(context,params){
let result = requestData();
context.commit('MUTATIONS1',result.data);
}
};
// 修改 state
const mutations = {
MUTATIONS1(state,data){
state.data = data
}
};
// 数据存储
const state = {
data:''
};
// state 的计算返回
const getters = {
dataToUp(state){
return state.data.toUpperCase()
}
};

export default {
namespaced: true,
actions,
mutations,
state,
getters
}

组件中使用 Home.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

mounted(){
// 触发action/mutation
this.$store.dispath('user/action1',params)
this.$store.commit('user/MUTATIONS1',params)
// 简化形式
this.action1(params)
this.Mutation1(params)
}
computed:{
data(){
return this.$store.state.user.data
}
dataToUp(){
return this.$store.getters['user/dataToUp']
}
// 简化形式 通过挂载到组件实例VC
...mapState('user',['data'])
...mapGetters('user',['dataToUp'])
}
methods:{
// 触发action/mutation 的简化形式 挂载到组件实例VC
...mapActions('user',{action:'action1'}),
...mapMutations('user',{Mutation1:'MUTATIONS1'})
}

六、插槽

  • 父子组件通信(结构)

  • 子组件结构不定,由父组件确定

默认插槽

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// -- 子组件
{{title}}
<slot>定义插槽,插槽默认显示值</slot>
props:['title']

// -- 父组件中 传数据给子组件
<Child title='美食'>
<img src='1.jpg' /> // 展示在slot插槽中
</Child>
<Child title='游戏'>
<ul>
<li v-for="(g,index) in games" :key="index">{{g}}</li>
</ul>
</Child>

具名插槽 :适用多个插槽时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// -- 子组件
{{title}}
<slot name='center'>默认值1</slot>
<slot name='footer'>默认值2</slot>

// 父组件
<Child title='游戏'>
<ul slot='center'> // 展示在center插槽
<li v-for="(g,index) in games" :key="index">{{g}}</li>
</ul>
<template slot='footer'>
<a src='baidu.com' />
<a src='baidu.com' />
</template>
// 用template可以使用 v-slot:
<template v-slot:footer>
<a src='baidu.com' />
<a src='baidu.com' />
</template>
</Child>

作用域插槽: 子组件通过props回传数据给父组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// -- 数据提供者子组件 结构由父组件确定
{{title}}
<slot :games='games'>默认内容</slot>
data(){
return {
games: ['game1','game2','game3']
}
}

// -- 使用者父组件 必须用template包裹 可以使用解构赋值 {games}
<template scope='data'>
<ul>
<li v-for="(g,index) in data.games" :key="index">{{g}}</li>
</ul>
</template>

通信其他相关

自定义事件与原生事件

1
2
3
4
5
6
7
8
9
// click为自定义事件
<Home @click='callback' />

// click为原生DOM事件,绑定在Home组件根元素
<Home @click.native='callback' />

// :value结合@input实现v-model
<span>{{msg}}</span>
<input type='text' :value='msg' @input='msg = $event.target.value' />

父子组件数据同步

1
2
3
4
5
6
7
8
// -- 父组件 :value为props @input为自定义事件 $event接收回调函数参数
<Child :value='msg' @input='msg = $event' />

// -- 子组件
props: ['value']

// 原型DOM的value绑定props的value和原生事件
<input type='text' :value='value' @input='$emit("input",$event.target.value)' />
1
2
3
4
5
6
7
8
// 效果同上
<Child v-model='msg' />

// -- 子组件
props: ['value']

// 原型DOM的value绑定props的value 和原生事件
<input type='text' :value='value' @input='$emit("input",$event.target.value)' />
1
2
3
4
5
6
7
// 效果同上
<Child :money.sync='money' />

// 子组件
<span>{{money}}</span>
<button @click='$emit("update:money",money-100)' />
props:['money']

$attrs与$listeners

1
2
3
4
5
6
7
8
9
10
11
12
13
// 组件属性在 $attrs与props互斥存在
// 绑定父组件传入的所有属性 $attrs打包除去props接收的属性
// $listeners 获取父组件给子组件传递的自定义事件
<Child title='标题' type='primary' value='value' @click='callbackfunc' />

// 子组件中v-bind='$attrs',将父组件传过来中除了props声明过的属性重新绑定到子组件
<template>
<a :title='title'>
<el-button v-bind='$attrs' v-on='$listeners'></el-button>
</a>
</templte>
props:['title']

$children与$parent

1
2
3
4
5
6
7
8
// 获取所有子组件实例
this.$children.forEach(child=>{
child.money -= 100;
})

// 获取父组件实例
this.$parent.money += 100;

混入mixin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 功能逻辑复用
// myMixin/index.js
export default {
// 重复业务逻辑
methods:{
giveMoney(money){
this.money -= money
this.$parent.money += money
}
},
// computed
// mounted
}

// 组件中引入
import myMixin from 'myMixin/index.js'
export default {
name:'home',
mixins:['myMixin'],
data(){return{}}
}