Vue-组件间通信方式

组件的自定义事件

1.一种组件间通信方式,适用于:子组件=>父组件
2.使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中
3.绑定自定义事件:

  • 第一种方式在父组件中:<student @xiaomi="demo"/>或者<student v-on:xiaomi="demo"/>
  • 第二种方式在父组件中:
<student ref="demo"/>
.....
mounted(){
	this.$ref.xxx.$on('xiaomi',this.name
	}
  • 若想让自定义事件只能触发一次,可以使用once修饰符,或$once方法
    4.触发自定义事件:this.$emit('xiaomi',数据)
    5.解绑自定义事件:this.$off('xiaomi')
    6.组件上也可以绑定原生DOM事件,需要使用native修饰符
    7.注意:通过this.$ref.xxx.$on('xiaomi',回调}绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题

一.props实现传递数据

通过父组件给子组件传递函数类型的props实现:子给父传递数据
实现:点击按钮将学校名交给App,实现子组件给父组件传递数据
分析
1.App组件想要得到school组件的学校名就需要在自己的组件里表达出想要的意思(定义得到学校名字的方法)
2.表达出想要的意思还不行,还要告诉他我已经定义了方法你接受下(将方法给到school)
3.之后就用props声明接收,整个getSchoolName我们定义完,就可以直接定义按钮来用它
App.vue

  • 定义方法(首先在app.vue里面定义得到学校名字的方法)
script>
// 引入组件
import School from './components/School.vue'
import Student from './components/Student.vue'


export default {
    name:'App',
    components:{School,Student},
    data() {
        return {
            msg:'你好啊'
        }
    },
    // 首先先定义方法
    methods: {
        getSchoolName(name){
            console.log('App收到了学校名',name);
        }
    },
}
  • 之后在App.vue里面将方法给到school组件
<template>
  <div class="app">
      <h1>{{msg}}</h1>
      <!-- 将这个方法给到school -->
      <School :getSchoolName = "getSchoolName"/>
      <Student/>
  </div>
</template>

School.vue

  • School声明接收
export default{//直接暴露组件的配置对象
        name:'School',//需要和文件名保持一致
        // 之后school声明接收
        props:['getSchoolName'],
        data() {
            return {
                name: '双语幼儿园',
                address: '北京'
            }
        },

getSchoolName函数已经定义完了

  • 写按钮做交互
<template>
    <div class="school">
        <h2>学校名称:{{name}}</h2>
        <h2>学校地址:{{address}}</h2>
        <!-- 接收完了之后写一个按钮 -->
        <button @click="sendSchoolName">把学校名给APP</button>
    </div>
</template>
<script>
   export default{//直接暴露组件的配置对象
        name:'School',//需要和文件名保持一致
        // 之后school声明接收
        props:['getSchoolName'],
        data() {
            return {
                name: '双语幼儿园',
                address: '北京'
            }
        },
        methods: {
            sendSchoolName(){
                this.getSchoolName(this.name)
            }
        },
    }
</script>

二.自定义事件实现传递数据

通过父组件给子组件绑定一个自定义事件实现:子给父传递数据

//写法一:使用@或者v-on
<Student v-on:xiaomi = "demo"/>由于v-on:在student组件标签上,所以说是给student这个组件的实例对象vc身上绑定了一个事件,事件名字叫xiaomi,如果以后有人触发了这个事件那么demo函数就会被调用

<template>
  <div class="app">
      <h1>{{msg}}</h1>
      <!-- 将这个方法给到school -->
      <School :getSchoolName = "getSchoolName"/>
      //方式一:
      <Student v-on:xiaomi = "demo"/>
  </div>
</template>

写demo方法

export default {
    name:'App',
    components:{School,Student},
    data() {
        return {
            msg:'你好啊'
        }
    },
    // 首先先定义方法
    methods: {
        getSchoolName(name){
            console.log('App收到了学校名',name);
        },
        demo(){
            console.log('demo被调用了');
        }
    },
}

xiaomi事件是给student组件的实例对象绑定的,想要触发xiaomi事件就需要找student组件的实例对象,所以接下来我们要操作student.vue
因为我们在student组件的实例对象上绑定的xiaomi事件,所以现在触发我们需要找student上的vc
this.$emit('hello',this.name)this是拿到school身上的vc,$emit的意思是触发

<template>
  <div class="student">
    <h2>学生姓名:{{ name }}</h2>
    <h2>学生年龄:{{ age }}</h2>
    <button @click="sendStudentName">把学生名给school组件</button>
  </div>
</template>

<script>
export default {
  //直接暴露组件的配置对象
  name: "Student", //需要和文件名保持一致
  data() {
            return {
                name: '张三',
                age: '18'
            }
        },
        methods: {
          sendStudentName(){
            // 触发student组件实例身上的xiaomi事件
            this.$emit('hello',this.name)//拿到vc后触发
          }
        },
};

//写法二:使用ref
1.在app里面写<Student ref="student"/>
2.然后通过app的实例对象vc(this拿到)this.$refs.student能获取到student组件的实例对象
3.当app挂载完毕就用this.$refs.student拿student组件的实例对象,然后就可以绑定事件,调$on(当…的时候)当‘xiaomi’这个事件被触发的时候执行一个回调getSchoolName,但是这个回调在methods方法中要想拿到需要通过this

mounted(){
   this.$refs.student.$on('xiaomi',this.getSchoolName)
    }

注:mounted(){}写在哪个组件里面就是哪个组件挂载完毕

  • 想要自定义事件触发一次就不能再触发了
mounted(){
        this.$refs.student.$once('xiaomi',this.getSchoolName)
    }

如果写的是上面两种方法直接在<Student @xiaomi.once = "demo"/>

  • 传递的参数很多的话可以采用这种方法,第一个参数作为name形参接收,其他的参数全都整理到params(参数)这个数组上
 getSchoolName(name,...params){
            console.log('App收到了学校名',name,params);
        },

三.两者之间的比较

共同点:必须配置回调
在这里插入图片描述
不同点:1.自定义事件的话父组件什么都没给子组件传,只是将事件绑定在子组件身上,将事件方法一直作为回调在使用2.但是另一个却是用props来接收数据

这样看来自定义事件更简单,不用传数据

四.解绑自定义事件

为什么要解绑自定义事件:遵循原则不用就解绑

解绑一个自定义事件:在给哪个组件绑定的事件,就在哪个组件解绑事件,在student.vue的methods方法里定义unbind函数

 unbind(){
            this.$off('xiaomi')//解绑一个自定义事件
          }

解绑多个自定义事件:需要写在数组里

unbind(){
            this.$off(['xiaomi','demo'])
          }

解绑所有的自定义事件:

 unbind(){
            this.$off()//解绑所有的自定义事件
          }

销毁了当前student组件的实例对象:

 death(){
            this.$destory()//销毁了当前student组件的实例对象,销毁后所有student实例的自定义事件
          }

在这里插入图片描述
在这里插入图片描述
而在App组件里差值语法里面的来源有三个:1.data(来自于data自己亲自写好)2.props(外部传入)3.computed(计算属性计算出来的)想要用这个name需要把name放在这三个地方
后两个办法都不可用,唯一的办法是将student的子组件交给app的name并且将它放在data里

注意:组件可以用原生事件,想用原生dom事件,要用.native

 <Student ref="student" @click.native="show"/>

在这里插入图片描述

全局事件总线

全局事件总线可以实现任意组件通信
在这里插入图片描述
A组件想收到别人给它的数据 ,在A组件里面就需要写点代码给X绑定自定义事件demo,由于是在A组件里面绑定的自定义事件,所以demo自定义事件的回调就留在了A组件里面。
下面的D组件想给A组件传点数据,在D组件写一段代码去触发x身上的demo自定义事件,并且在触发事件的同时再带点数据666过去,这样的话x身上的demo事件就被触发了,demo事件所对应的回调就会被执行,回调一执行传入的666就以参数的形式到了A组件里面,所以这样就实现了任意组件之间的通信、
其实X就是一个中间商,

步骤:
1.抛出X让所有组件都能看的到,所以我们需要写在main.js里面
main.js为啥要在main.js里写,在哪引入的vue就要在哪操作

/*该文件是整个项目的入口文件*/
//引入vue
import Vue from 'vue'
// 引入APP组件 它是所有组件的父组件
import App from './App.vue'
// 关闭vue的生产提示
Vue.config.productionTip = false
// 创建vue的实例对象 vm
new Vue({ 
  el:'#app',
  // 将APP组件放入容器中
  render: h => h(App),
  //安装全局事件总线
  brforeCreate(){
    Vue.prototype.$bus = this.name//$bus就是总线x,this指向的是vm
  }
})

将x放在vuecomponent原型上放不合适,因为每一次写标签将会生成一个新的vuecomponent,并不好控制。必须将x放在vue的原型对象上这样所有属性和方法都能访问到
$on $off $emit都在vue的原型对象上

student.vue
绑定按钮,点击事件。将事件写在方法里,拿到全局总线触发事件

<template>
  <div class="student">
    <h2>学生姓名:{{ name }}</h2>
    <h2>学生年龄:{{ age }}</h2>
    <button @click="sendStudentName">把学生名给school组件</button>
  </div>
</template>

<script>
export default {
  //直接暴露组件的配置对象
  name: "Student", //需要和文件名保持一致
  data() {
    return {
      name: "张三",
      age: "18",
    }
  },
  mounted() {},
  methods: {
    sendStudentName(){
      this.$bus.$emit("hello", this.name);
      //通过事件总线,触发hello事件,拿到学生名字
    }
  },
};
</script>
<style lang="less" scoped>
.student {
  background-color: pink;
}
</style>

school.vue
通过按钮的点击事件,然后this.$emit传递事件,然后this.$on捕获本页面的事件

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

<script>
export default {
  //直接暴露组件的配置对象
  name: "School", //需要和文件名保持一致
  data() {
    return {
      name: "双语幼儿园",
      address: "北京",
    };
  },
  mounted() {
    // console.log('school',this);
    this.$bus.$on("hello", (data) => {
      console.log("我是school组件,我收到了数据", data);
      //接收hello事件将数据传过来
    });
  },
};
</script>

<style scoped>
.school {
  background: orange;
}
</style>

在这里插入图片描述
注意:
在school组件里给傀儡绑定事件,为什么绑定事件是想借助傀儡得到数据,在组件销毁之前最好把傀儡身上的hello事件解绑

只要school组件一挂载就找到总线收数据
 mounted() {
    // console.log('school',this);
    this.$bus.$on("hello", (data) => {
      console.log("我是school组件,我收到了数据", data);
    });
  },
  beforeDestroy() {
      this.$bus.$off('hello')//拿到总线销毁hello事件
  },
};

消息订阅与发布

一种组件间通信的方式,适用于任意组件间通信
需要引入import pubsub from "pubsub-js";
步骤:
1.订阅消息:消息名
2.发布消息:消息内容

C组件里面的东西A组件想用,这样A是需要数据的人,C是数据的提供者,A就相当于我们,C就相当于邮局。
在A组件里面订阅,名叫demo的消息,demo消息带一个text回调函数,如果有人发布了demo消息那么text函数将会被调用。发布的消息名也叫demo,随后携带着数据666。只要C一发布,A这边由于订阅了demo这个消息,text函数就会触发调用,然后666以参数的形式传到text回调里
注意:订阅的时候是什么名字,发布的时候就得是什么名。
需要数据的人订阅消息,提供数据的人发布(发送消息)

原生js里面没有办法实现订阅与发布,我们需要借助第三方库==>pubsub.js
在这里插入图片描述

  • 先从收数据的人school组件入手,school说我要学生名,快给我
    school.vue
    需要现在school组件里面引入这段代码
<script>
import pubsub from "pubsub-js";

school组件只要挂载完毕,立刻马上就去订阅一个消息
subscribe是pubsub里面的一个API,第一个参数消息的名字叫hello,第二个参数是消息的回调,msgName是消息名,data是参数

mounted() {
    pubsub.subscribe("hello", function (msgName,data) {
      console.log("有人发布了hello消息,hello消息的回调执行了",msgName,data);
    });
  },
  • 然后student组件说我已经发布了,你快订阅!
    pubsub.publish('hello',666) publish发布hello事件,传递参数666
<template>
  <div class="student">
    <h2>学生姓名:{{ name }}</h2>
    <h2>学生年龄:{{ age }}</h2>
    <button @click="sendStudentName">把学生名给school组件</button>
  </div>
</template>

<script>
import pubsub from "pubsub-js";
export default {
  //直接暴露组件的配置对象
  name: "Student", //需要和文件名保持一致
  data() {
    return {
      name: "张三",
      age: "18",
    }
  },
  mounted() {},
  methods: {
    sendStudentName(){
     pubsub.publish('hello',666)
    }
  },
};
</script>

在这里插入图片描述

  • 每一次订阅的消息都会有一个订阅的ID,当你想取消的时候需要通过ID去取消订阅
 mounted() {
   this.pubId= pubsub.subscribe("hello", (msgName,data)=> {//改成箭头函数指向正常
      console.log("有人发布了hello消息,hello消息的回调执行了",msgName,data);
    });
  },
  beforeDestroy() {
    pubsub.unsubscribe(this.pubId)
  },
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值