组件通信
2021-08-21 23:14:30 大约 4 分钟
vue的组件用于组件之间相互传递数据,比如父子组件或兄弟组件的数据传递。
组件通信常用方式
- props
- eventbus
- vuex
- 自定义事件
- 边界情况
- $parent
- $children
- $root
- $refs
- provide/inject
- 非prop特性
- $attrs
- $listeners
# props
- 父给子传值。
- 父组件传递给子组件的数据是**
只读
的,即只可以用,不可以改
**。- 用props完成父组件给子组件传值 传值的属性都是定义在子组件的标签上,可以采用v-bind的形式传递动态值。
- 在子组件中声明接收的属性。
- props是组件的选项 用于定义接收属性
<div id="app">
<!-- 1.定义属性 => 给谁传就在谁的标签上写属性 属性名随便写-->
<food-meat :foods="list" a="1" b="2"></food-meat>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
list: ["红烧肉", "回锅肉", "四喜丸子", "刀削面"]
},
components: {
"food-meat": {
// 2 接收属性 props => 字符串/数组
template: `<div>我是饭--{{foods}}{{b}}<button @click="oncl">按钮</button></div>`,
props: ["foods", "b"],
methods: {
oncl() {
console.log(this.foods,this.b,this.list,this instanceof Vue)
},
}
}
}
});
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# eventbus
利用发布订阅,进行数据的传递;
<!-- child1.vue-->
<template>
<button @click="onClick">我是child1</button>
</template>
<script>
import eventBus from '../utils/eventBus.js'
export default {
methods: {
onClick() {
eventBus.$emit('child1', '我是child1')
}
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- child1.vue-->
<template>
<div>我是child2</div>
</template>
<script>
import eventBus from '../utils/eventBus.js'
export default {
created() {
eventBus.$on('child1', (val) => {
console.log(val);
})
},
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- index.vue-->
<template>
<div>
<child-1></child-1>
<child-2></child-2>
</div>
</template>
<script>
import child1 from './child1.vue'
import child2 from './child2.vue'
export default {
name: 'HelloWorld',
components: {
child1,
child2
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// eventBus.js
import Vue from 'vue';
export default new Vue()
1
2
3
2
3
在
index.vue
中,引入child1.vue
和child2.vue
,然后通过eventBus进行数据传递;
提示
要想触发订阅的事件,那么就需要在组件加载时,先完成事件的订阅;
# vuex
vue的状态管理插件,vue默认不提供这个功能,需要你安装它;
// store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex)
export default new Vuex.Store({
state: {
text: ''
},
mutations: {
saveText(state, val) {
state.text = val;
}
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- child1.vue-->
<template>
<button @click="onClick">我是child1</button>
</template>
<script>
export default {
methods: {
onClick() {
this.$store.commit('saveText', '我是child1')
}
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- child2.vue-->
<template>
<div>我是child2
<h1>{{ text }}</h1>
</div>
</template>
<script>
export default {
computed: {
text() {
return this.$store.state.text;
}
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
我们通过在child1组件中设置,然后把数据保存在vuex,这样我们就可以在child2中直接取处vuex中的数据使用了;
# 自定义事件
这种方式其实就是发布订阅;
<!-- child1.vue-->
<template>
<button @click="onClick">我是child1</button>
</template>
<script>
export default {
methods: {
onClick() {
this.$emit('child1', '我是child1')
}
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- index.vue-->
<template>
<div>
<child-1 @child1="onChild1"></child-1>
</div>
</template>
<script>
import child1 from './child1.vue'
export default {
components: {
child1,
},
methods: {
onChild1(val) {
console.log(val);
}
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
通过在child1中发布,然后在index.vue中 child1的组件上订阅这个事件就可以了;
# $parent
可以通过祖辈搭桥来使用发布订阅;
<!--child1-->
<template>
<button @click="onClick">我是child1</button>
</template>
<script>
export default {
methods: {
onClick() {
this.$parent.$emit('child1', '我是child1')
}
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!--child2-->
<template>
<div>我是child2
<h1>{{ text }}</h1>
</div>
</template>
<script>
export default {
data() {
return {
text: '',
}
},
created() {
this.$parent.$on('child1', (val) => {
this.text = val
} )
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!--index-->
<template>
<div>
<child-1></child-1>
<child-2></child-2>
</div>
</template>
<script>
import child1 from './child1.vue'
import child2 from './child2.vue'
export default {
name: 'HelloWorld',
components: {
child1,
child2
},
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# $children
父组件可以通过$children访问子组件实现父子通信
this.$children[0].xx = 'xxx'
1
注意
$children不能保证子元素顺序
# provide/inject
由于vue有$parent属性可以让子组件访问父组件。但孙组件想要访问祖先组件就比较困难。通过provide/inject可以轻松实现跨级访问祖先组件的数据
<!--index-->
<template>
<div>
<child-1></child-1>
</div>
</template>
<script>
import child1 from './child1.vue'
export default {
components: {
child1,
},
provide() {
return { Hello: this }
},
data() {
return {
HelloWorld: 'HelloWorld'
}
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!--child1 省略 -->
<!--child2-->
<template>
<div>我是child2
<h1>{{ text }}</h1>
</div>
</template>
<script>
export default {
data() {
return {
text: '',
}
},
inject: ['Hello'],
created() {
console.log(this.Hello.HelloWorld);
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# $attrs/$listeners
包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 ( class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 ( class 和 style 除外),并且可以通过 vbind="$attrs" 传入内部组件——在创建高级别的组件时非常有用;
// child:并未在props中声明foo
<p>{{$attrs.foo}}</p>
// parent
<HelloWorld foo="foo"/>
1
2
3
4
5
2
3
4
5
# refs
获取子节点引用
// parent
<HelloWorld ref="hw"/>
mounted() {
this.$refs.hw.xx = 'xxx'
}
1
2
3
4
5
2
3
4
5