组件的自定义事件-绑定

80 阅读2分钟

Js的内置事件

Js的内置事件有click、keyup、mouseleave、mouseenter....,这些我们是要给html使用,比如给h1一个click事件,给input一个keyup事件。

那么现在我们就要打造一个自定义的事件,比如:aa、bb、cc(自己定义的),这些我们是要给组件使用的

准备

把之前我写过的《scoped样式》里的components和App.vue复制下来


image.png

把里面代码弄简单点,写的更便于观察一些

image.png image.png image.png

下面就是改完后的网页效果图
image.png

为了好看一点,我又加了一些样式
image.png image.png image.png

最后效果是这样的
image.png

实现将子组件的数据传到父组件

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

点击school部分的一个按钮,将学校名和地址传到App上

用props实现,父组件传递一个方法给子组件,子组件用props接收,子组件通过接收到的方法将数据传给父组件
image.png image.png

在网页点击按钮后,App就收到学校名了
image.png

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

第一种写法,使用@或v-on

点击student部分的一个按钮,将学生名传到App上

通过v-on绑定一个方法,v-on在Student组件上就是给Student组件的实例对象vc绑定一个名叫xuesheng的事件,如果有人触发了这个xuesheng事件,那么demo函数就会被调用。
image.png

先配置一下demo,只要demo被调用了,就会提示我们
image.png

那么现在只要我们触发Student里的xuesheng事件,就可以调用demo了,我们先给Mystudent一个点击事件,
image.png

xuesheng事件在MyStudent的vc里,我们直接就可以获取到,但是如果要触发该事件,就要通过$emit(emit:散发;发出)来触发
image.png

点击按钮,demo就被调用了
image.png

如果要上传学生名,就要传参数,直接在后面加一个参数就可以
image.png

在App也就收到了参数
image.png

在网页上点击按钮,就可以将学生名上传到App上了
image.png

为了看起来更整齐一点,我将demo改成getStudentname
image.png

将上面MySchool里的upload也改成sendSchoolname
image.png

对了,v-on可以简写,如下
image.png

第二种写法,使用ref(灵活性强)

在App使用ref,然后只要我通过this.$refs.student就可以在App上拿到Student组件的实例对象vc
image.png

然后我再App方法上写一个钩子mounted,只要App挂载完毕就拿student的实例对象
image.png

然后在后面写一个$on('xuesheng',this.getStudentname),表示的是当触发这个xuesheng事件就调用getStudentname函数
image.png

我的mounted放错位置了,我放method里边去了,应该放在外面
image.png

修改过来后,在网页点击按钮后,就可以得到学生名了
image.png

为什么说第二种写法比第一种写法的灵活性强,因为如果我想等个3秒后再绑定,那么第一种写法就没法操作,而第二种写法就可以
image.png

然后再网页上如果你刷新后前3秒还没绑定,所以我们点击按钮后得不到学生名,3秒后再点击按钮,就可以得到学生名了
image.png

获取一次学生名

第二种写法

我们无数次点击按钮,就可以无数次获得学生名
image.png

如果我希望只能获取一次学生名,那么就需要换一个api,将on改为on改为once
image.png

这样网页你再点击多少次它都只获取一次学生名
image.png

第一种写法

那么如果我要第一种写法,只获取一次学生名,那么就在xuesheng后面加上once
image.png

网页上点击按钮,得到的也一样的效果
image.png

接收多个参数

如果我想传递多个参数也是可以的,在第一种写法的基础上,直接在this.name的后面直接加上其它的参数
image.png

然后在App上接收
image.png

在网页上点击按钮后,你就可以看到其它传递出来的参数
image.png

一般来说,我们不会传递那么多的参数,如果需要传递那么多的参数,我们一般会包在一个对象里面,再传递;对ES6很熟的同学,知道我们可以通过...a来将多个参数包裹在一个a数组里输出,前面参数正常传
image.png

把参数包裹在a里,再将a数组输出
image.png

网页上点击按钮后,就可以输出包裹着后面参数的数组
image.png

但一般不用a用的是params
image.png

因为后面章节要用这些代码,所以我先把once删掉
image.png

平时用两种写法都可以,只是我下个文章用的是第一种写法,所以我把第二种写法先注释掉

本结用的主要代码如下:
MySchool.vue

<template>
  <div class="school">
    <h1>学校名:{{ name }}</h1>
    <h1>学校地址:{{ address }}</h1>
    <button @click="sendSchoolname">上传学校名给App</button>
  </div>
</template>

<script>
// 组件交互相关的代码(数据、方法等等)
export default {
  name: "MySchool",
  props: ["getSchoolname"],
  data() {
    return {
      name: "南大",
      address: "南京",
    };
  },
  methods:{
    sendSchoolname(){
      this.getSchoolname(this.name)
    }
  }
};
</script>

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

MyStudent.vue

<template>
  <div class="student">
    <h1>学校姓名:{{ name }}</h1>
    <h1>学生年龄:{{ age }}</h1>
    <button @click="sendStudentname">上传学生名给App</button>
  </div>
</template>

<script>
// 组件交互相关的代码(数据、方法等等)
export default {
  name: "MyStudent",
  data() {
    return {
      name: "小蒲",
      age: 18,
    };
  },
  methods: {
    sendStudentname() {
      // 触发Student组件实例对象上的xuesheng事件
      this.$emit("xuesheng", this.name, 111, 222, 333);
    },
  },
};
</script>

<style lang="less">
.student {
  background-color: pink;
  padding: 5px;
  margin-top: 30px;
}
</style>

App.vue

<template>
  <div class="App">
    <h1>{{ msg }}</h1>
    <!-- <h2>{{ Schoolname }}</h2> -->
    <!-- 通过父组件给子组件传递函数类型的props实现:子给父传递数据 -->
    <School :getSchoolname="getSchoolname" />
    <!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第一种写法,使用@或v-on)-->
    <!-- <Student v-on:xuesheng="getStudentname" /> -->
    <Student @xuesheng="getStudentname" />
    <!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种写法,使用ref)-->
    <!-- <Student ref="student" /> -->
  </div>
</template>

<script>
// 引入组件
import School from "./components/MySchool.vue";
import Student from "./components/MyStudent.vue";

export default {
  name: "App",
  components: { School, Student },
  data() {
    return {
      msg: "你好啊",
      Schoolname: "",
    };
  },
  methods: {
    getSchoolname(name) {
      console.log("App收到了学校名", name);
      // this.Schoolname = name;
    },
    getStudentname(name, ...params) {
      console.log("App收到了学生名", name, params);
    },
  },
  // mounted() {
  //   setTimeout(() => {
  //     // this.$refs.student.$on("xuesheng", this.getStudentname);
  //     this.$refs.student.$once("xuesheng", this.getStudentname)(一次性);
  //   }, 3000);
  // },
};
</script>

<style>
.App {
  background-color: gray;
  padding: 5px;
}
</style>