Vue组件之间的数据通信(子组件传父组件,兄弟组件)

1 Vue子组件向父组件传递数据

1.1 知识点: 组件的自定义事件

  1. 一种组件间通信的方式,适用于:子组件 ===> 父组件

  2. 使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。

  3. 绑定自定义事件:

    1. 第一种方式,在父组件中:<Demo @atguigu="test"/><Demo v-on:atguigu="test"/>

    2. 第二种方式,在父组件中:

      <Demo ref="demo"/>
      ......
      mounted(){
         this.$refs.xxx.$on('atguigu',this.test)
      }
      
    3. 若想让自定义事件只能触发一次,可以使用once修饰符,或$once方法。

  4. 触发自定义事件:this.$emit('atguigu',数据)

  5. 解绑自定义事件this.$off('atguigu')

  6. 组件上也可以绑定原生DOM事件,需要使用native修饰符。

  7. 注意:通过this.$refs.xxx.$on('atguigu',回调)绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!

1.2 方式一: 通过父组件给子组件传递函数类型的props实现

App.vue 父组件

<template>
  <div>
    <h1 class="title">{{ title + '   ' }}学校名称: {{ schoolName }} </h1>
    <!-- 子组件给父组件传递数据,通过父组件给子组件传递函数类型的props实现-->
    <School :getSchoolName="getSchoolName"/>
  </div>
</template>

<script>
import School from '@/components/School.vue'

export default {
  name: 'App',
  components: {School},
  data() {
    return {
      title: '你好',
      schoolName: ''
    }
  },
  methods: {
    getSchoolName(name) {
      this.schoolName = name
    }
  }
}
</script>

School .vue 子组件

<template>
  <div class="demo">
    <h2>学校名称:{{ name }}</h2>
    <h2>学校地址:{{ address }}</h2>
    <!-- 点击,子组件向父组件传值 -->
    <button @click="sendSchoolName">给APP父组件传递学校名称</button>
  </div>
</template>

<script>
export default {
  name: 'School',
  data() {
    return {
      name: '尚硅谷atguigu',
      address: '北京'
    }
  },
  props: ['getSchoolName'],
  methods: {
    sendSchoolName() {
      this.getSchoolName(this.name)
    }
  }
}
</script>

<style scoped>
.demo {
  background-color: skyblue;
  margin-bottom: 30px;
  padding: 10px;
}
</style>

1.3 方式二:通过父组件给子组件绑定一个自定义事件实现

App.vue 父组件

<template>
  <div>
    <h1 class="title">{{ title + '   ' } 学生姓名:{{ studentName }}</h1>
    <!--  通过父组件给子组件绑定一个自定义事件实现,(第一种写法,使用@或v-on)-->
    <!-- v-on在谁身上就是再给谁绑定事件, 事件名叫atguigu,getStudentName函数就会被调用 -->
    <!--<Student v-on:atguigu="getStudentName"/>-->
    <!-- 只触发一次  -->
    <!--    <Student @atguigu.once="getStudentName"/>-->
    <!--  通过父组件给子组件绑定一个自定义事件实现,(第二种写法,使用ref)-->
    <Student ref="student"/>
  </div>
</template>

<script>
import Student from '@/components/Student.vue'

export default {
  name: 'App',
  components: { Student},
  data() {
    return {
      title: '你好',
      studentName: ''
    }
  },
  mounted() {
    // this.$refs.student.$on('atguigu', this.getStudentName) // 绑定自定义事件
    this.$refs.student.$once('atguigu', this.getStudentName) // 绑定自定义事件(只触发一次)
  },
  methods: {
    getStudentName(name) {
      this.studentName = name
    },
    // 传递多个参数时
    //getStudentNames(name, ...params) {
    //  this.studentName = name
    //}
    ,
    add(){
      this.number++
    },
    unbind(){
      // 解绑一个
      this.$off('atguigu')
      // 解绑多个
      this.$off(['atguigu', 'demo'])
      // 解绑所有的自定义事件
      this.$off()
    },
    death(){
      this.$destroy() // 销毁当前student组件的实例,销毁后所有实例的自定义事件全部不奏效。
    }
  }
}
</script>
<style scoped>

</style>

School .vue 子组件

<template>
  <div class="demo">
    <h2>学生姓名:{{ name }}</h2>
    <h2>学生性别:{{ sex }}</h2>
        <h2>当前求和:{{ number }}</h2>
    <button @click="sendStudentName">发送学生姓名</button>
    <button @click="add">点我number++</button>
    <button @click="unbind">解绑aiguigu事件</button>
    <button @click="death">销毁当前student组件的实例Vc</button>
  </div>
</template>

<script>
export default {
  name: 'Student',
  data() {
    return {
      name: '张三',
      sex: '男',
      number: 0
    }
  },
  methods: {
    sendStudentName() {
    // 触发事件,传递参数
      this.$emit('atguigu', this.name)
      //this.$emit('atguigu', this.name, 44, 23, 21)
    }
  }
}
</script>

<style lang="less" scoped>
.demo {
  background-color: pink;
  padding: 10px;

}
</style>

2 利用全局事件总线

配置全局事件总线,来达到组件之间的数据通信。例如:父传子,子传父、兄弟之间、子孙之间等等,任意之间的组件通信。

2.1 知识点: 全局事件总线(GlobalEventBus)

  1. 一种组件间通信的方式,适用于任意组件间通信。

  2. 安装全局事件总线:

    new Vue({
    	......
    	beforeCreate() {
    		Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
    	},
        ......
    }) 
    
  3. 使用事件总线:

    1. 接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。

      methods(){
        demo(data){......}
      }
      ......
      mounted() {
        this.$bus.$on('xxxx',this.demo)
      }
      
    2. 提供数据:this.$bus.$emit('xxxx',数据)

  4. 最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件。

2.2 案例:兄弟之间,Student组件给School组件传递数据

第一步:安装全局事件总线
在main.js中安装全局数据总线(此处的$bus可任意起名,也可以是Vue.prototype.x = this)

//创建vm
new Vue({
	el:'#app',
	render: h => h(App),
	beforeCreate() {
		// 安装全局事件总线,$bus就是当前应用的vm
		Vue.prototype.$bus = this
	}
})

第二步: 在全局事件总线上绑定事件
谁收数据,就谁就绑定事件总线上的事件
在School组件上创建事件hello

<template>
  <div class="demo">
    <h2>学校名称:{{ name }}</h2>
    <h2>学校地址:{{ address }}</h2>
    <h2>学生姓名:{{ studentName }}</h2>
  </div>
</template>

<script>
export default {
  name: 'School',
  data() {
    return {
      name: '尚硅谷atguigu',
      address: '北京',
      studentName: ''
    }
  },
  mounted() {
    // 在$bus全局事件总线上面绑定hello自定义事件
    this.$bus.$on('hello', this.demo)
  },
  beforeDestroy() {
    // 在$bus全局事件总线上面销毁hello自定义事件
    this.$bus.$off('hello')
  },
  methods:{
    demo(data){
      this.studentName = data
    }
  }
}
</script>

<style scoped>
.demo {
  background-color: skyblue;
  margin-bottom: 30px;
  padding: 10px;
}
</style>

第三步:触发事件
Student组件触发事件

<template>
  <div class="demo">
    <h2>学生姓名:{{ name }}</h2>
    <h2>学生性别:{{ sex }}</h2>
    <button @click="sendNameToSchool">发送数据给school</button>
  </div>
</template>

<script>
export default {
  name: 'Student',
  data() {
    return {
      name: '张三',
      sex: '男'
    }
  },
  methods:{
    sendNameToSchool(){
      // 触发自定义事件hello
      this.$bus.$emit('hello', this.name)
    }
  }
}
</script>

<style lang="less" scoped>
.demo {
  background-color: pink;
  padding: 10px;

}
</style>

3 利用消息订阅与发布(不推荐)

3.1 知识点:消息订阅与发布

3.2 案例:兄弟之间,Student组件给School组件传递数据

需要数据的人订阅信息

第一步: 安装pubsub.js

npm i pubsub-js

第二步: School组件订阅

<template>
  <div class="demo">
    <h2>学校名称:{{ name }}</h2>
    <h2>学校地址:{{ address }}</h2>
    <h2>学生姓名:{{ studentName }}</h2>
  </div>
</template>

<script>
import pubsub from 'pubsub-js'
export default {
  name: 'School',
  data() {
    return {
      name: '尚硅谷atguigu',
      address: '北京',
      studentName: ''
    }
  },
  mounted() {
    // 订阅
    // 方式一写成箭头函数的形式,注意只能是箭头函数this的指向才是Vm
    // this.pubId = pubsub.subscribe('hello', (message, name) => {
    //   console.log('有人发布了hello消息,hello消息的回调执行了', message, name, this)
    // })
    // 方式二
    this.pubId = pubsub.subscribe('hello', this.demo)
  },
  beforeDestroy() {
    // 取消订阅,需要通过this.pubId
    pubsub.unsubscribe(this.pubId)
  },
  methods:{
    demo(message, name){
      console.log('有人发布了hello消息,hello消息的回调执行了', message, name, this)
      this.studentName = name
    }
  }
}
</script>

<style scoped>
.demo {
  background-color: skyblue;
  margin-bottom: 30px;
  padding: 10px;
}
</style>

第三步: Student组件发布

<template>
  <div class="demo">
    <h2>学生姓名:{{ name }}</h2>
    <h2 class="atguigu">学生性别:{{ sex }}</h2>
    <button @click="sendNameToSchool">发送数据给school</button>
  </div>
</template>

<script>
import pubsub from 'pubsub-js'

export default {
  name: 'Student',
  data() {
    return {
      name: '张三',
      sex: '男'
    }
  },
  methods: {
    sendNameToSchool() {
      // 发布
      this.pubId = pubsub.publish('hello', this.name)
    }
  }
}
</script>

<style lang="less" scoped>
.demo {
  background-color: pink;
  padding: 10px;

}
</style>

  • 15
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr.史

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值