Vue中的组件间通信(总结)

120 阅读3分钟

1、利用props实现父组件给子组件传递数据

在父组件中给子组件传递数据,然后再在子组件中用props接收,就可以实现父组件->子组件的数据传递

父组件:

  <div>
      <Student name='李四' sex='女' :age='18'/>
     <!-- 这样可以提高代码的复用率,就算数据是不相同的,你可以动态的指定数据 -->
      <Student name='张三' sex='男' :age='19'/>
  </div>
</template>

<script>
//引入School组件 
import Student from './components/Student.vue'
export default {
    name:"App",
  
    components:{
        Student
    },
}
</script>

子组件

  <div class="school"> 
      <h1>{{msg}}</h1>
      <h2>{{Name}}</h2>
      <h2>{{sex}}</h2>
      <h2>{{myAge+1}}</h2>
      <button @click='updataAge'>尝试修改收到的年龄</button>
  </div>
</template>

<script>
export default {
    name:"Student",
    data() {
        return {
            msg:'欢迎!',
            myAge:this.age
        }
    },
    methods:{
        updataAge(){
            this.myAge++
        }
    },
    // 在这里简单声明接收一下数据
    props:['Name','age','sex']
  
    // 在这里接收数据的同时限制了数据的类型
    // props:{
    //     name:'String',
    //     age:'Number',
    //     sex:'String'
    // }
  
    //接收的同时对数据: 进行类型限制+默认值的指定+必要性的限制
    // props:{
    //     name:{
    //         type:String,//name的类型
    //         required:true//name是必要的
    //     },
    //     age:{
    //         type:Number,
    //         default:99 //默认值
    //     },
    //     sex:{
    //         type:String,
    //         required:true
    //     }
    // }
}
</script>

<style>
    .school{
        background-color: gray;
    }
</style>

从上面可以看出,props有几种接受的形式,可以简单声明一下接收,也可以在接收数据的同时对类型进行限制,指定默认值,限制必要性

2、利用props实现子组件给父组件传递数据

在父组件中给子组件传递一个函数,函数的回调在父组件中;在子组件中定义一个事件,让他触发父组件中传递过来的函数,并且在触发的同时给函数传递数据,这样在父组件中就可以通过回调函数的到数据 父组件:

  <div class="app">
      <h1>{{msg}},学生姓名是:{{studentName}}</h1>
      <!-- 通过父组件给子组件传递函数类型的props实现:子给父传递数据 -->
      <School :getSchoolName='getSchoolName'/>
  </div>
</template>
import School from './components/School.vue'
export default {
    name:"App",
  
    components:{
        School
    },
    data(){
      return{
        msg:'你好啊!',
        studentName:''
      }
    },
    methods:{
      getSchoolName(name){
        console.log('App收到了学校名:',name)
        //在这里通过回调可以的到学校名
      }
    },

子组件(School)组件:

  <div class="school">
      <h2>学校名称:{{schoolName}}</h2>
      <h2>学校地址:{{adress}}</h2>
      <button @click="sendSchoolName">把学校名给App</button>
  </div>
</template>

<script>
export default {
    name:"School",
    props:['getSchoolName'],
    data() {
        return {
            schoolName:'shangguigu ',
            adress:'beijing'
        }
    },
   methods:{
       sendSchoolName(){
           this.getSchoolName(this.schoolName)
       }
   }
}
</script>

<style>
    .school{
        background-color:skyblue;
        padding: 5px;
        margin-top: 30px;
    }
</style>

3、通过绑定自定义事件来实现子组件给父组件传递数据

其实思路跟上面用props差不多,在父组件调用的子组件里绑定一个自定义事件,这个事件指向一个函数,函数的回调在父组件中。在子组件里定义一个事件,这个事件用来触发绑定在子组件上的自定义事件,并且在触发的同时传入数据,这样父组件中的回调就可以的到数据了。 父组件:

  <div class="app">
      <h1>{{msg}},学生姓名是:{{studentName}}</h1>
      <!-- 通过绑定自定义事件实现(第一种:使用v-on或者@) -->
      <Student v-on:hah='demo' @demo='m1'/>
      <!-- 通过绑定自定义事件实现(第二种:使用ref实现) -->
      <!-- <Student ref="student"/> -->

  </div>
</template>

<script>
//引入School组件 
import Student from './components/Student.vue'
import School from './components/School.vue'
export default {
    name:"App",
  
    components:{
        Student,
        School
    },
    data(){
      return{
        msg:'你好啊!',
        studentName:''
      }
    },
    methods:{
      getSchoolName(name){
        console.log('App收到了学校名:',name)
      },
      demo(name){
        console.log('数据传输了',name)
        this.studentName=name
      },
    },
    // 这样写可以更加的灵活
    //
    // mounted(){
    //   setTimeout(()=>{
    //      this.$refs.student.$on('hah',this.demo)
    //   },3000)
    // }
}
</script>
<style lang="css">
  .app{
    background-color: gray;
    padding: 5px;
  }
</style>

子组件(Student)组件:

  <div class="student">
      <h2>学生姓名:{{name}}</h2>
      <h2>学生性别:{{sex}}</h2>
      <button @click="sendStudentName">把学生姓名给App</button>
      <button @click="unbind">解绑hah事件</button>
  </div>
</template>

<script>

export default {
    name:"Student",
    data() {
        return {
            name:'张三',
            sex:'男'
        }
    },
    methods:{
        sendStudentName(){
            // 触发Student组件实例身上的hah事件
            this.$emit('hah',this.name)
        },
        unbind(){
            this.$off('hah')//解绑一个自定义事间
        }
    }
}
</script>

<style>
    .student{
        background-color: orange;
        padding: 5px;
    }
</style>

上面自定义事件有两种写法,一种是在父组件中调用的子组件中直接用v-on或者@来定义自定义事件;第二种就是先用ref标记一下这个子组件,然后在后面通过ref将这个子组件拿出来然后通过ref将这个子组件拿出来然后通过on('自定义事件名,自定义事件的回调函数')来定义自定义事件。

4、利用全局事件总线实现组件间通信

需要创建一个事件总线,它的特点有以下几点

1、可以被所有的组件访问到:这一点可以通过将他定义在Vue原型来实现,(因为在Vue中内置了:
VueComponent.prototype.__proto__指向Vue.prototype,
这样vue的实例和vm实例都可以通过原型链来访问到Vue原型对象)
2、要有$on$off$emit等方法,这些Vm实例身上都有   

为了实现从Student组件向School组件传递信息,可以通过¥on('xxx',callback)在School组件监听一个xxx事件,在Student组件里面通过¥emit('xxx',data)触发事件并传递参数,School组件中的回调callback接收参数。

main.js里面

 el:'#app',
 render:h=>h(app),
 beforeCreate() {
   Vue.prototype.$bus=this //安装全局事件总线
 },
})

School组件:

 <div class="school">
     <h2>学校名称:{{schoolName}}</h2>
     <h2>学校地址:{{adress}}</h2>
 </div>
</template>

<script>
export default {
   name:"School",
   props:['getSchoolName'],
   data() {
       return {
           schoolName:'shangguigu ',
           adress:'beijing'
       }
   },
 
   mounted(){
       this.$bus.$on('hello',(name)=>{
           console.log('success',name)
       })
   },
   beforeDestroy(){
       this.$bus.$off('hello')
   }
}
</script>

<style>
   .school{
       background-color:skyblue;
       padding: 5px;
       margin-top: 30px;
   }
</style>

Student组件:

  <div class="student">
      <h2>学生姓名:{{name}}</h2>
      <h2>学生性别:{{sex}}</h2>
      <button @click="sendToSchool">把数据传给school</button>
  </div>
</template>

<script>

export default {
    name:"Student",
    data() {
        return {
            name:'张三',
            sex:'男'
        }
    },
    methods:{
        sendToSchool(){
            this.$bus.$emit('hello',this.name)
        }
    },
    // mounted(){
    //     console.log('Student',this.x)
    // }
}
</script>

<style>
    .student{
        background-color: orange;
        padding: 5px;
    }
</style>

5、消息订阅与发布

这是利用消息订阅发布的插件实现的,首先先导入一个插件 import pubsub from 'pubsub-js'

School组件:

  <div class="school">
      <h2>学校名称:{{schoolName}}</h2>
      <h2>学校地址:{{adress}}</h2>
  </div>
</template>

<script>
import pubsub from 'pubsub-js'
export default {
    name:"School",
    props:['getSchoolName'],
    data() {
        return {
            schoolName:'shangguigu ',
            adress:'beijing'
        }
    },
  
    mounted(){
      
        pubsub.subscribe('hello',(msgName,data)=>{
            this.pubId =console.log('有人发布了消息,hello的回调被执行了',msgName,data)
        })
        
    },
    beforeDestroy(){
        pubsub.unsubscribe(this.pubId)
    }
}
</script>

<style>
    .school{
        background-color:skyblue;
        padding: 5px;
        margin-top: 30px;
    }
</style>

在Student组件里面订阅消息(类似于订报纸,订的是hello这个报纸,后面的回调函数用来接收数据), 这里回调函数会犯一个值(标识符),将来用来unsubscribe(取消订阅)。

Student组件:

  <div class="student">
      <h2>学生姓名:{{name}}</h2>
      <h2>学生性别:{{sex}}</h2>
      <button @click="sendToSchool">把数据传给school</button>
  </div>
</template>

<script>
import pubsub from 'pubsub-js'
export default {
    name:"Student",
    data() {
        return {
            name:'张三',
            sex:'男'
        }
    },
    methods:{
        sendToSchool(){
            pubsub.publish('hello',666)
        }
    },
   
}
</script>

<style>
    .student{
        background-color: orange;
        padding: 5px;
    }
</style>

在Student组件中用来发布消息,publish('消息名称',数据),消息名称对应于上面提到的‘报纸名称’,只用名称对应了(确定报纸是你订的才会接收)才会接收。