Vue组件之间如何进行通信?

目录

一、组件介绍

1、定义组件

2、注册组件

2.1 全局注册

 2.2 局部注册

3、使用组件

二、组件通信方式

1、父组件给子组件传值

2、子组件给父组件传值

3、兄弟组件之间的传值

4、祖先组件和子孙组件之间的传值

5、关于单向数据流 


一、组件介绍

组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展HTML元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue的编译器为它添加特殊功能。在有些情况下,组件也可以表现为用is特性进行了扩展的原生 HTML 元素。组件注册的时候需要为该组件指定各种参数。

因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。

组件的特点:

  • 组件可以进行任意次数的复用
  • 组件的data必须是一个函数,确保每个实例可以维护一份被返回对象的独立拷贝,也就是任何一个组件的改变不会影响到其他组件

1、定义组件

组件与new Vue有相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等,但是组件没有el选项,而是使用template

let myA={
    template:`
		<div>
			{
   
   {msgA}}
		</div>
	`,
	data(){
		return {
			msgA:'我是子组件'
		}
	}
};

2、注册组件

使用组件之前需要先注册组件,注册组件的方式有:全局注册和局部注册

2.1 全局注册

使用Vue.component('组件名', 组件); 进行全局注册,全局注册之后的组件可以在任意组件里面使用。

Vue.component('my-a',myA);

 2.2 局部注册

局部注册的组件只能在当前组件中使用,所以我们想在哪个组件中使用该组件,就在哪个组件中局部注册该组件。我们使用components配置项进行局部注册。
比如我们想要在myB组件中使用myA组件,那么我们就需要在myB组件里面对myA组件进行局部注册:

let myA={
	template:`
		<div>
			{
   
   {msgA}}
		</div>
	`,
	data(){
		return {
			msgA:'我是子组件'
		}
	}
};
let myB={
	// 局部注册
	components:{
    //组件名: 组件
		'my-a':myA
    },
	template:`
		<div>B组件
			<my-a></my-a>
		</div>
	`
}

3、使用组件

使用组件只需要在模板中使用html标签,标签名是组件名:

<div id="app">
	<my-a></my-a>
	<my-b></my-b>
</div>

二、组件通信方式

组件 A 在它的模板中使用了组件 B。它们之间必然需要相互通信:父组件可能要给子组件下发数据,子组件则可能要将它内部发生的事情告知父组件。在 Vue 中,父子组件的关系可以总结为 prop 向下传递,事件向上传递。父组件通过 prop 给子组件下发数据,子组件通过事件给父组件发送消息。

1、父组件给子组件传值

父组件给子组件传值的方式:
第一步:在子组件的标签内写入需要传递的值

第二步:在子组件内使用props配置项接收父组件传递过来的值

<body>
	<div id="app">
		<!-- 父组件传值给子组件 -->
		<!-- 1.在子组件标签上 写入传入的值 -->
		<!-- 静态传参 不使用v-bind进行数据绑定,那么传递的就是'msg'字符串本身-->
		<!-- <my-a msg1="msg"></my-a> -->
		<!-- 动态传参 使用v-bind进行数据绑定,就可以传递任意类型的值-->
		<my-a :msg2="msg" :age="18" :obj="{name:'zhangsan'}" :stu='[1,2,3]'></my-a>
	</div>
	<script>
		let myA={
			// 子组件内使用props接收父组件传递的值
			props:['msg2','stu','age','obj'],
			template:`
				<div>
					我是子组件<br>
					{
   
   {msg2}}---{
   
   {typeof msg2}}<br>
                    {
   
   {stu}}---{
   
   {typeof stu}}<br>
                    {
   
   {age}}---{
   
   {typeof age}}<br>
                    {
   
   {obj}}---{
   
   {typeof obj}}
				</div>
			`
		};
		new Vue({
          // 局部注册组件
			components:{
				'my-a':myA
			},
			el:"#app",
			data:{
				msg:'我是父组件'
			}
		})
	</script>
</body>

在props中,子组件可以对父组件的传值进行类型校验,当传入的值不是我们想要的类型的时候,会进行报错,此时props需要写成对象的形式:

注意:null和undefined可以通过任意类型的校验

<body>
  <div id="app">
    <!-- 父组件传值给子组件 -->
    <!-- 1.在子组件标签上 写入传入的值 -->
    <!-- 静态传参 不使用v-bind进行数据绑定,那么传递的就是'msg'字符串本身-->
    <!-- <my-a msg1="msg"></my-a> -->
    <!-- 动态传参 使用v-bind进行数据绑定,就可以传递任意类型的值-->
    <my-a :msg2="msg" :age="18" :obj="{name:'zhangsan'}" :stu='[1,2,3]' :stu2="19"></my-a>
  </div>
  <script>
    let myA = {
      // 子组件内使用props接收父组件传递的值
      props: {
        age: {
          // 可以进行多个类型值的校验
          // 可以是Number,String,Boolean类型中的任意一个
          type: [Number, String, Boolean],
          // 自定义校验器规则  参数val表示传过来的值
          validator(val) {
            return val > 50
          }
        },
        msg2: String,
        obj: Object,
        stu2: String,
        stu: {
          type: Array,
          // 可以设置默认值,注意:需要写成函数的形式
          default () {
            return [4, 5, 6]
          },
          //要求必须传递
          required: true
        }
      },
      template: `
				<div>
					我是子组件<br>
					{
   
   {msg2}}---{
   
   {typeof msg2}}<br>
                    {
   
   {stu}}---{
   
   {typeof stu}}<br>
                    {
   
   {stu2}}---{
   
   {typeof stu2}}<br>
                    {
   
   {age}}---{
   
   {typeof age}}<br>
                    {
   
   {obj}}---{
   
   {typeof obj}}
				</div>
			`
    };
    new Vue({
      // 局部注册组件
      components: {
        'my-a': myA
      },
      el: "#app",
      data: {
        msg: '我是父组件'
      }
    })
  </script>
</body>


2、子组件给父组件传值

子组件给父组件传值的方式:
第一步:在子组件中使用 $emit('发射事件的名称',传递的参数) 给父组件发射自定义事件和传递值

第二步:在父组件中声明自定义事件来接收参数

<body>
  <div id="app">
    <!-- 自定义事件 -->
    <my-a @my-event="handler"></my-a>
  </div>
  <script>
    let myA = {
      template: `
        <div>我是子组件
          <button @click='toSend'>子传值给父</button>
        </div>
      `,
      data() {
        return {
          subMsg: "我是子组件A,我要给父组件传值"
        }
      },
      methods: {
        toSend() {
          // 发射事件 $emit('发射事件的名称',传递的参数)
          this.$emit('my-event', this.subMsg)
        }
      }
    }
    new Vue({
      components: {
        'my-a': myA
      },
      el: '#app',
      data: {
        msg: "我是父组件",
      },
      methods: {
        handler(a) {
          console.log(a, '这是子组件的值');
        }
      }
    })
  </script>
</body>


 

3、兄弟组件之间的传值

兄弟组件之间传值的方式:

使用事件总线:
第一步:声明一个事件总线xxx.js,即新建一个js文件,在js文件导出一个Vue实例

第二步:引入事件总线xxx.js,即在其中一个兄弟组件内导入xxx.js文件,并使用$emit()将数据发射出去

第三步:在另一个兄弟组件导入xxx.js文件,并使用$on()接收兄弟组件传递过来的数据

我们在vue脚手架中演示:
 

创建好脚手架后,我们在src下的components文件夹下建立两个.vue文件,分别是Header.vue和Footer.vue,然后在App.vue中引入这两个组件并使用,此时Header.vue和Footer.vue就是兄弟组件,然后在src下新建一个eventBus.js文件,它就是事件总线。

App.vue

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <Header/>
    <hr>
    <Footer/>
  </div>
</template>

<script>
import Header from './components/Header.vue'
import Footer from './components/Footer.vue'
export default {
  name: 'App',
  components: {
    Header,
    Footer,
  },
  data() {
    return {
      msg:'我是祖先组件'
    }
  },
  provide(){
    return {'msg':this.msg}
  }
}

</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

eventBus.js 

import Vue from 'vue';
export default new Vue();

Header.vue

<template>
  <div>
    {
   
   {msgH}}
    <button @click="handler">点击我传值给Footer</button>
  </div>
</template>

<script>
// 引入事件总线
import Bus from '../eventBus.js'
export default {
  data(){
    return {
      msgH:"头部组件",
      Footer:"这是兄弟组件Footer"
    }
  },
  methods:{
    handler(){
      // 兄弟组件传值 
	  // 1.兄弟组件使用$emit('发射事件',携带参数) 
      Bus.$emit('toFoot',this.Footer)
    }
  }
}
</script>

Footer.vue

<template>
  <div>
    {
   
   {msgF}}
  </div>
</template>

<script>
// 引入事件总线
import Bus from '../eventBus.js'
export default {
  data(){
    return {
      msgF:"底部组件",
    }
  },
  // 另一个兄弟组件使用 $on(自定义事件名称,(形参 用于接收兄弟组件传递过来的值)=>{}) 接收参数
  created(){
    Bus.$on('toFoot',(a)=>{
      console.log(a,"这是Footer传给我的值");
    })
  }
}
</script>

 

4、祖先组件和子孙组件之间的传值

祖先组件和子孙组件之间的传值方式:
第一步:祖先组件使用provide方法传递数据

第二步:子孙组件使用inject注入数据

我们同样在vue脚手架中演示:
在components文件夹下再新建一个FooterChild.vue文件,然后在Footer.vue组件中使用FooterChild.vue组件,App.vue中使用Footer.vue组件,那么App.vue就作为祖先组件,FooterChild.vue就作为子孙组件了。

App.vue

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <Header/>
    <hr>
    <Footer/>
    
  </div>
</template>

<script>
import Header from './components/Header.vue'
import Footer from './components/Footer.vue'
export default {
  name: 'App',
  components: {
    Header,
    Footer,
  },
  data(){
    return {
      msg: '我是祖先组件',
      a: 18
    }
  },
  // 祖先组件使用provide方法提供传递的数据
  provide(){
    return {
      "msg":this.msg,
      "a":this.a
    }
  }
}

</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

Footer.vue

<template>
  <div>
    {
   
   {msgF}}
    <FooterChild/>
  </div>
</template>

<script>
import FooterChild from './FooterChild.vue'
export default {
  components:{
    FooterChild
  },
  data(){
    return {
      msgF:"底部组件",
    }
  }
}
</script>

FooterChild.vue

<template>
  <div>
    {
   
   {msgC}}--{
   
   {msg}}--{
   
   {a}}
  </div>
</template>

<script>
export default {
  data(){
    return {
      msgC:"底部组件的子组件"
    }
  },
  // 注入数据
  inject:['msg','a']
}
</script>

5、关于单向数据流 

 单向数据流是指数据是由上层向下层流动的,也就是说父组件的数据发生改变后,子组件的数据也会发生改变;而子组件的数据发生改变,父组件的数据不会受到影响。

猜你喜欢

转载自blog.csdn.net/lq313131/article/details/127054416