页面组件的关系结构,是一个由许多组件构成的树状结构,组件间存在着两种关系:父子关系、非父子关系 。几乎任意类型的应用界面都可以抽象为一个组件树。

组件间的父子关系指的组件树中由线直接相连的两个组件间的关系,其余关系一律归为非父子关系。

一、父子组件间数据传递

1.父向子传递数据

  • 父组件调用子组件时,以属性绑定的方式将要传递的数据绑定在子组件标签上。
  • 在子组件对象中,使用props选项声明获取的数据,进行绑定属性的拦截,即接收来自父组件的数据 。

方式:属性绑定+数据拦截

首先,定义父组件hello和子组件world,父组件中数据变量名是msg、name、age,子组件中变量名是message、name、age。在父组件hello中调用子组件时,以“:子组件数据=”父组件数据””的方式进行属性绑定。

<template id="hello">
 <div>
 <h3>我是hello父组件</h3> 
 <h3>访问自己的数据:{{msg}},{{name}},{{age}}</h3> 
 <hr>
 <!-- 属性绑定方式 -->
 <my-world :message="msg" :name="name" :age="age"></my-world>
 </div>
 </template>

然后,在子组件对象中的props选项中声明获取的数据,进行属性拦截。

components:{
 'my-hello':{
        template:'#hello',
        data(){
           return {
                msg:xx,
                name:xx,
                age:xx,
            }
         },
       components:{
          'my-world':{
              template:'#world',
           // props: ['message','name','age'] // 简单的字符串数组
              props:{
                 message:{
                    type:String
                 },
                 name:{
                     type:String,
                     required:true,
                 },
                 age:{
                      type:Number,
                      default:18,
                      validator:function(value){ // 参数value为传递的数据
                          if(value<0 || value>100){
                              alert('年龄无效');
                       }
                         return true;
                      }
                     }
                   }
                 }
             }
        }
 }

2.子向父传递数据

父组件在调用子组件时,监听子组件触发的自定义事件,也就是父组件时刻观察子组件,看它有没有数据要传递,并且在父组件对象中定义回调方法,用来接收数据。

方式:事件监听+事件触发

在子组件对象中使用$emit(事件名,数据)的形式触发自定义事件,向父组件传递数据。

<template id="hello">
 <div>
 <h3>我是hello父组件</h3> 
 <h3>访问自己的数据:{{msg}},{{name}},{{age}}</h3> 
 <hr>
 
 <!-- 监听子组件触发的自定义事件 -->
 <my-world @e-world="get" @update-sex="updateSex"></my-world>
 </div>
 </template>

上述父组件hello调用子组件时,触发自定义事件e-world和update-sex(名字自定义)。在子组件中以this.$emit(‘e-world’,this.sex,this.height)的方式传递数据,父组件中定义方法get(sex,height)接收数据。

 

new Vue({
       el:'#app',
       // 提供要向后代组件传递的数据
       provide:{
          hobby:'game',
          weight:150
       },
      components:{
         'my-hello':{ // 父组件
         template:'#hello',
         data(){
            return {
               sex:null,
               height:null
            }
         },
        methods: {
           get(sex,height){
          // console.log(sex,height);
           this.sex = sex;
           this.height = height;
        },
        updateSex(sex){
           this.sex = sex;
        }
       },
       components:{
          'my-world':{ // 子组件
              template:'#world',
              data(){
              return {
                 sex:'male',
                 height:180.5
               }
              },
             methods: {
                send(){
                // 使用$emit()触发自定义事件
                   this.$emit('e-world',this.sex,this.height);
                }
             },
             mounted() {
            // 当组件挂载完成后,主动将数据传递给父组件
                this.$emit('e-world',this.sex,this.height);
            },
             watch: { // 监视子组件数据的变化,当数据发生变化时触发$emit更新父组件中的数 据
               sex:function(newValue){
                   this.$emit('update-sex',newValue);
                 }
             },
           }
        }
     }
 });

二、非父子组件传递数据

1.祖先向后代传递数据

祖先向后代传递数据使用注入依赖(依赖注入)的方式:

  • 使用provide/inject实现
  • 在祖先组件中使用provide选项提供一个可注入到其后代的数据对象
  • 在后代组件中使用inject选项注入一个要接收数据的字符串数组
new Vue({
     // 祖先组件使用provide
     provide:{
     hobby:'game',
     weight:150
    },
     components:{
       components:{
        // 后代组件使用inject接收祖先组件传递的数据
       inject:['hobby']
      }
     }
 
});

2.相邻组件间传递数据

非父子组件间的通信,均可以通过中央事件总线 Event Bus 来实现,也称为事件中心。其实就是使用一个可以在所有组件中访问的Vue实例,用它来监听事件和触发事件。上面的祖父向后代传递数据也可以使用中央事件总线来实现。

方式:事件监听+事件触发

与子组件向父组件传递数据不同,使用中央事件总线一般借助根组件root进行事件监听和触发。

定义组件A,向组件C传递数据name,使用this.$root.$emit(‘data-a’,this.name)触发自定义事件,发送数据。

Vue.component('CompA',{
     template:'#a',
         data(){
            return {
              name:'tom'
            }
         },
     beforeMount() {
         console.log('组件A。。。。。beforeMount');
     },
     mounted() {
         console.log('组件A。。。。。mounted');
      // console.log(this.$root); // 获取根实例Root
         this.$root.$emit('data-a',this.name);
     },
     methods: {
       send(){
       // 触发根实例上的自定义事件,发送数据
       this.$root.$emit('data-a',this.name);
       }
     },
 });

在组件C中,使用this.$root.$on(‘data-a’,name =>{  this.name = name})监听自定义事件,接收数据。注意,此处接收name必须使用箭头函数,如果不使用箭头函数,this.name的this将表示root实例,即事件源。使用箭头函数后表示此组件C。

 

Vue.component('CompC',{
   template:'#c',
   data(){
     return {
       name:null,
       age:null
     }
   },
   beforeMount() {
      console.log('组件C。。。。。beforeMount');
      // 监听根实例上的自定义事件,接收数据
      this.$root.$on('data-a',name => {
      // console.log(name);
      // this.name = name;
      // console.log(this); // 如果不使用箭头函数,则此处的this表示Root实例,表示事件源
     this.name = name;
   });
   this.$root.$on('data-b',age => {
   this.age = age;
   });
   },
 });

中央事件总线Event Bus的方式实现数据传递不仅适用于非父子组件,也可用于父子组件间。但我们一般不这么做,使用Event Bus时,事件绑定在根组件,这样其他组件也可以获取数据。

 

 

说点什么
欢迎骚扰,有缘人互加友链
支持Markdown语法
好耶,沙发还空着ヾ(≧▽≦*)o
Loading...