组件 A 在它的模板中使用了组件 B。它们之间必然需要相互通信:父组件可能要给子组件下发数据,子组件则可能要将它内部发生的事情告知父组件。在 Vue 中,父子组件的关系可以总结为 prop 向下传递,事件向上传递。父组件通过 prop 给子组件下发数据,子组件通过事件给父组件发送消息。
<my-com title='' :msg='msg' attr-a=''>
- {
-
- props:['title','msg','attrA],
-
- template:``
-
- }
- <template>
- <div id="app">
- <Shcool />
- <Student name="科大" :age="19" />
- </div>
- </template>
-
- <script>
- import Shcool from "./components/Shcool.vue";
- import Student from "./components/Student.vue";
- export default {
- name: "app",
- components: { Shcool, Student },
- };
- </script>
-
- <style>
- #app {
- background-color: orange;
- padding: 15px;
- }
- </style>
- <template>
- <div id="student">
- <h1>学生姓名:{{ name }}</h1>
- <h1>学生年龄:{{ age + 1 }}</h1>
- </div>
- </template>
-
- <script>
- export default {
- data() {
- return {
- // studentName: "好学生",
- // age: "18",
- };
- },
- props: ["name", "age"],
- };
- </script>
-
- <style>
- #student {
- background-color: skyblue;
- }
- </style>
- 事件发射 自定义事件
-
- 在子组件内发射 在父组件内接受
子组件发射时机
- 1.手动按钮发送
-
- 2.监听子组件内数据变化,然后发射
- props传参同props父传子参数类似,具体实现原理是父组件定义函数,并将函数传递给子组件,在子组件中调用,并将自己的数据作为参数传递给父组件的函数。大体可分为四步。
-
- 第一步,在子组件 标签上 上使用v-bind(简写为 :)绑定传递的参数名以及传递的处理函数;
-
- 第二步,在子组件的 script 中 添加 props 属性 ,并将 参数名 接收;
-
- 第三步,在子组件中调用其他函数来触发用 props接收的参数(也就是那个函数)
-
- 第四步,子组件的参数被传递出去
- <template>
- <div id="app">
- <Shcool :getSchoolName="getSchoolName" />
-
- <!-- <Student name="科大" :age="19" /> -->
- <Student />
- </div>
- </template>
-
- <script>
- import Shcool from "./components/Shcool.vue";
- import Student from "./components/Student.vue";
- export default {
- name: "app",
- components: { Shcool, Student },
- methods: {
- getSchoolName(name) {
- console.log("App收到了学校名:", name);
- },
-
- },
- };
- </script>
-
- <style>
- #app {
- background-color: orange;
- padding: 15px;
- }
- </style>
- <template>
- <div id="school">
- <h1>学校名称:{{ name }}</h1>
- <h1>学校地址:{{ addddress }}</h1>
- <button @click="sendSchoolName">把学校名给App</button>
- </div>
- </template>
-
- <script>
- export default {
- //在子组件的 script 中 添加 props 属性 ,并将 参数名 接收;
- props: ["getSchoolName"],
- data() {
- return {
- name: "科大",
- addddress: "上海",
- };
- },
- methods: {
- sendSchoolName() {
- this.getSchoolName(this.name);
- },
- },
- };
- </script>
-
- <style>
- #school {
- background-color: skyblue;
- }
- </style>
- 靠函数参数传递的方法将数据带给父组件,具体分三步:
- 第一步,在子组件 标签上 上使用v-on(简写为 @)绑定自定义的 事件名 以及对应的处理函数,可以类比原生事件 @click=“handle(e)”;
-
- 第二步,在子组件中调用其他函数,使用 this.$emit(‘事件名’,参数) 的方法触发事件;
-
- 第三步,子组件的参数被传递出去
- <template>
- <div id="app">
- <Shcool :getSchoolName="getSchoolName" />
-
- <!-- <Student name="科大" :age="19" /> -->
- <Student v-on:lili="getStudentName" />
- </div>
- </template>
-
- <script>
- import Shcool from "./components/Shcool.vue";
- import Student from "./components/Student.vue";
- export default {
- name: "app",
- components: { Shcool, Student },
- methods: {
- getSchoolName(name) {
- console.log("App收到了学校名:", name);
- },
- getStudentName(name) {
- console.log("App收到学生名:", name);
- },
- },
- };
- </script>
-
- <style>
- #app {
- background-color: orange;
- padding: 15px;
- }
- </style>
- <template>
- <div id="student">
- <h1>学生姓名:{{ name }}</h1>
- <h1>学生年龄:{{ age }}</h1>
- <button @click="sendStudentName">把学生名给App</button>
- </div>
- </template>
-
- <script>
- export default {
- data() {
- return {
- name: "好学生",
- age: "18",
- };
- },
- // props: ["name", "age"],
-
- methods: {
- sendStudentName() {
- this.$emit("lili", this.name);
- },
- },
- };
- </script>
-
- <style>
- #student {
- background-color: skyblue;
- }
- </style>
- Student组件不需要任何变化
- 主要变动有两处,第一处 是子组件标签中 使用ref属性;第二处 是不在methods或者watch中 定义处理函数,而是在生命周期函数中处理。
- 这样的好处是更加灵活,自定义事件可以添加其他异步操作,且对子组件绑定多个自定义事件时,也无需考虑太多的逻辑,不断地在 生命周期函数中 使用 $on 来处理即可。
-
- $on 接收两个参数,$on(自定义事件名,函数) 而函数可以用箭头函数来简写操作
-
- 注意:通过this.$refs.xxx.$on('atguigu',回调)绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!
- <template>
- <div class="app">
- <h1>{{ msg }}h1>
-
- <School :getSchoolName="getSchoolName" />
- <hr />
-
-
- <Student @lili="getStudentName" />
-
-
- <Student ref="student" />
- div>
- template>
-
- <script>
- import Student from "./components/Student.vue";
- import School from "./components/School.vue";
-
- export default {
- name: "App",
- components: { Student, School },
- data() {
- return {
- msg: "你好啊",
- };
- },
- methods: {
- getSchoolName(name) {
- console.log("App收到了学校名:", name);
- },
- getStudentName(name) {
- console.log("App收到了学生名:", name);
- },
- },
- mounted() {
- this.$refs.student.$on("lili", this.getStudentName);
- },
- };
- script>
- <style scoped>
- .app {
- background-color: gold;
- padding: 10px;
- }
- style>
全局事件总线是一种可以在任意组件间通信的方式,本质上就是一个对象。它必须满足以下条件:
$on、$emit和$off方法去绑定、触发和解绑事件- import Vue from 'vue'
- import App from './App.vue'
-
- Vue.config.productionTip = false
-
- new Vue({
- el:'#app',
- render: h => h(App),
- beforeCreate() {
- Vue.prototype.$bus = this //安装全局事件总线
- }
- })
- <template>
- <div class="app">
- <School />
- <Student />
- </div>
- </template>
-
- <script>
- import Student from "./components/Student.vue";
- import School from "./components/School.vue";
-
- export default {
- name: "App",
- components: { Student, School },
- data() {
- return {};
- },
- };
- </script>
- <style scoped>
- .app {
- background-color: rgb(241, 207, 11);
- padding: 10px;
- }
- </style>
- <template>
- <div class="student">
- <h2>学生姓名:{{ name }}</h2>
- <h2>学生性别:{{ sex }}</h2>
- <button @click="sendStudentName">把学生名给School组件</button>
- </div>
- </template>
-
- <script>
- export default {
- name: "Student",
- data() {
- return {
- name: "好学生",
- sex: "男",
- };
- },
- methods: {
- sendStudentName() {
- this.$bus.$emit("demo", this.name);
- },
- },
- };
- </script>
- <style scoped>
- .student {
- background-color: red;
- }
- </style>
- <template>
- <div class="dome">
- <h2>学校姓名:{{ name }}</h2>
- <h2>学校地址:{{ address }}</h2>
- </div>
- </template>
-
- <script>
- export default {
- name: "School",
-
- data() {
- return {
- name: "科大",
- address: "北京",
- };
- },
- methods: {
- demo(data) {
- console.log("我是School组件,收到了数据:", data);
- },
- },
- mounted() {
- this.$bus.$on("demo", this.demo);
- },
- beforeDestroy() {
- this.$bus.$off("demo");
- },
- };
- </script>
- <style >
- .dome {
- background-color: skyblue;
- }
- </style>
- new Vue({
- ...
- beforeCreate() {
- Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
- },
- ...
- })
$bus绑定自定义事件,事件的回调留在A组件自身- export default {
- methods(){
- demo(data){...}
- }
- ...
- mounted() {
- this.$bus.$on('xxx',this.demo)
- }
- }
2.提供数据:`this.$bus.$emit('xxx',data)`
最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件
- <template>
- <div class="dome">
- <h2>学校姓名:{{ name }}</h2>
- <h2>学校地址:{{ address }}</h2>
- </div>
- </template>
-
- <script>
- import pubsub from "pubsub-js";
- export default {
- name: "School",
-
- data() {
- return {
- name: "科大",
- address: "北京",
- };
- },
- methods: {
- demo(msgName, data) {
- console.log("我是School组件,收到了数据:", data);
- },
- },
- mounted() {
- this.pubId = pubsub.subscribe("demo", this.demo); //订阅消息
- },
- beforeDestroy() {
- pubsub.unsubscribe(this.pubId); //取消订阅
- },
- };
- </script>
- <style >
- .dome {
- background-color: skyblue;
- }
- </style>
- <template>
- <div class="student">
- <h2>学生姓名:{{ name }}</h2>
- <h2>学生性别:{{ sex }}</h2>
- <button @click="sendStudentName">把学生名给School组件</button>
- </div>
- </template>
-
- <script>
- import pubsub from "pubsub-js";
- export default {
- name: "Student",
- data() {
- return {
- name: "好学生",
- sex: "男",
- };
- },
- methods: {
- sendStudentName() {
- // this.$bus.$emit("demo", this.name);
- pubsub.publish("demo", this.name); //发布消息
- },
- },
- };
- </script>
- <style scoped>
- .student {
- background-color: red;
- }
- </style>
- 消息订阅与发布(pubsub):
-
- 消息订阅与发布是一种组件间通信的方式,适用于任意组件间通信
-
- 使用步骤:
-
- 安装pubsub:npm i pubsub-js
-
- 引入:import pubsub from 'pubsub-js'
接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身
- export default {
- methods(){
- demo(data){...}
- }
- ...
- mounted() {
- this.pid = pubsub.subscribe('xxx',this.demo)
- }
- }
提供数据:pubsub.publish('xxx',data)
最好在beforeDestroy钩子中,使用pubsub.unsubscribe(pid)取消订阅