一般情况下我们把vue中的组件关系分为父子组件通信, 和非父子组件之间通信
一: 父子传值props / $emit
-
父向子传值:在子组件的标签上通过自定义属性传递父组件的数据,子组件的内部通过 props 接收父向子传递的数据
<!-- 父组件 -->
<template>
<div class="section">
<child :msg="articleList"></child>
</div>
</template>
<script>
import child from './child.vue'
export default {
name: 'HelloWorld',
components: { comArticle },
data() {
return {
msg: '启动'
}
}
}
</script>
<!-- 子组件 child.vue -->
<template>
<div>
{{ msg }}
</div>
</template>
<script>
export default {
props: {
msg: String
}
}
</script>
2.子向父通信: 在子组件的标签上自定义事件,自定义事件的值是父组件的方法,在子组件内部通过 this.$emit()方法触发事件,第一个参数为自定义事件,第二个参数可以传递子组件的内部数据,此时父组件中的方法就可以执行了
<!-- 父组件 -->
<template>
<div class="section">
<child :msg="articleList" @changMsg="changMsg"></child>
</div>
</template>
<script>
import child from './child.vue'
export default {
name: 'HelloWorld',
components: { comArticle },
data() {
return {
msg: 'kokokokoko'
}
},
methods:{
changMsg(msg) {
this.msg = msg
}
}
}
</script>
<!-- 子组件 child.vue -->
<template>
<div>
{{ msg }}
<button @click="change">改变字符串</button>
</div>
</template>
<script>
export default {
props: {
msg: String
},
methods: {
change(){
this.$emit('changMsg', 'okokokkok')
}
}
}
</script>
二..sync 修饰符(语法糖)
当一个子组件改变了一个 prop 的值时,这个变化也会同步到父组件中所绑定。 通俗的说:.sync修饰符可以实现子组件与父组件的双向绑定,并且可以实现子组件同步修改父组件的值。
<text-document v-bind:title="doc.title" v-on:update:title="doc.title = $event" />
使用.sync
<text-document v-bind:title.sync="doc.title" />
这样,在子组件中,就可以通过下面代码来实现对这个 prop 重新赋值了
this.$emit('update:title', newTitle)
v-model(语法糖)
我们知道v-model
是用来在表单控件
或者组件
上创建双向绑定
的,他的本质是 v-bind
和 v-on
的语法糖
,在一个组件上使用 v-model
,默认会为组件绑定名为 value 的 prop
和名为 input
的事件。
//在父组件中
<template>
<div>
<myinput v-model="msg"></myinput>
</div>
</template>
<script>
import myinput from '../components/myinput.vue'
export default {
components:{myinput},
data:function(){
return {
msg: 'hello'
}
},
}
</script>
//在子组件中
<template>
<div>
<input type="text" :value="value" @input="input">
</div>
</template>
<script>
export default {
props:['value'],
methods:{
input(e){
console.log(e.target.value)
this.$emit('input',e.target.value)
}
}
}
</script>
有时,在某些特定的控件中名为 value 的属性会有特殊的含义,这时可以通过 v-model
选项来回避这种冲突。
四 :ref / $refs
ref
:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素
;如果用在子组件
上,引用就指向组件实例
,可以通过实例直接调用组件的方法或访问数据
// 子组件 A.vue
export default {
data () {
return {
name: 'Vue.js'
}
},
methods: {
sayHello () {
console.log('hello')
}
}
}
// 父组件 app.vue
<template>
<component-a ref="comA"></component-a>
</template>
<script>
export default {
mounted () {
const comA = this.$refs.comA;
console.log(comA.name); // Vue.js
comA.sayHello(); // hello
}
}
</script>
ref 这种方式,就是获取子组件的实例,然后可以直接子组件的方法和访问操作data的数据,就是父组件控制子组件的一种方式,子组件想向父组件传参或操作,只能通过其他的方式了
五: eventBus(兄弟组件通信)
EventBus
又称为事件总线。在Vue中可以使用 EventBus
来作为沟通桥梁的概念,就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件,所以组件都可以上下平行地通知其他组件,但也就是太方便所以若使用不慎,就会造成难以维护的“灾难”,因此才需要更完善的Vuex作为状态管理中心,将通知的概念上升到共享状态层次。
// 创建一个中央时间总线类
class Bus {
constructor() {
this.callbacks = {} // 存放事件的名字
}
$on(name, fn) {
this.callbacks[name] = this.callbacks[name] || []
this.callbacks[name].push(fn)
}
$emit(name, args) {
if (this.callbacks[name]) {
this.callbacks[name].forEach((cb) => cb(args))
}
}
}
// main.js
Vue.prototype.$bus = new Bus() // 将$bus挂载到vue实例的原型上
// 另一种方式
Vue.prototype.$bus = new Vue() // Vue已经实现了Bus的功能
this.$bus.$emit('foo')
this.$bus.$on('foo', this.handle)
六:provide 与 inject
- 在祖先组件定义
provide
属性,返回传递的值 - 在后代组件通过
inject
接收组件传递过来的值
祖先组件
provide(){
return {
foo:'foo'
}
}
后代组件
inject: ['foo'] // 获取到祖先组件传递过来的值