组件的自定义事件
自定义事件就是区别于JS
里面内置事件而存在的:
- 比如点击事件
click
- 键盘事件
keyup
…
内置事件是给html元素用的;而自定义事件是给组件用的
准备俩个组件
School.vue
<template>
<div class="schoolBack">
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
</div>
</template>
<script>
export default{
name: 'School',
components:{},
data(){
return{
name: 'bilibili',
address: '魔都'
}
},
}
</script>
<style scoped>
.schoolBack{
background-color: skyblue;
}
</style>
Student.vue
<template>
<div class="studentBack">
<h2>学生姓名:{{name}}</h2>
<h2>学生性别:{{sex}}</h2>
</div>
</template>
<script>
export default{
name: 'Student',
components:{},
data() {
return {
name: '张三',
sex: '男'
}
},
}
</script>
<style scoped>
.studentBack{
background-color: pink;
}
</style>
引入App.vue
<template>
<div class="appBack">
<h1>{{msg}}</h1>
<School />
<hr />
<Student />
</div>
</template>
<script>
import School from './components/School.vue'
import Student from './components/Student.vue'
export default{
name: 'App',
components:{School,Student},
data() {
return {
msg: '你好啊!'
}
},
}
</script>
<style>
.appBack{
background-color: gray;
}
</style>
接下来提出需求
就是School组件在最下面设计一个按钮,这个按钮功能是点击这个按钮把这个学校名就交给App组件
子组件给父组件传值,可以用props
但是有一个前提就是父组件提前给字组件一个函数,子组件在合适的时候调用该函数:
App.vue
<template>
<div class="appBack">
<h1>{{msg}}</h1>
<School :getSchoolName="getSchoolName"/>
<hr />
<Student />
</div>
</template>
<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)
}
},
}
</script>
给完之后School.vue
得声明函数:
School.vue
<template>
<div class="schoolBack">
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
<button @click="sendSchoolName">把学校名给自己的父组件App</button>
</div>
</template>
<script>
export default{
name: 'School',
components:{},
props:['getSchoolName'],
data(){
return{
name: 'bilibili',
address: '魔都'
}
},
methods: {
sendSchoolName(){
this.getSchoolName(this.name)
}
},
}
</script>
同样的功能,也想给Student.vue
一份,把学生名给App
但是
用自定义事件去写
App.vue
<Student v-on:bilibili="demo"/>
首先我们必须认可一件事v-on
在谁身上就是给谁绑定事件
由于v-on在Student这个组件标签上,所以说是给Student这个组件的实例对象(VueComponent)上绑定了一个事件,事件名称叫bilibili
,如果以后有人触发了这个事件那么以后demo
函数就会被调用
demo(){
console.log('demo被调用了')
}
那么bilibili
这个事件得怎么触发呢?
里面有一个原则:你给谁绑的事件,你就找谁触发事件去
比如我按下click
就给我调用demo()函数
这个给Student
组件的实例对象绑定的bilibili
事件。想要触发就直接找Student
这个组件的实例对象
Student.vue
<template>
<div class="studentBack">
<h2>学生姓名:{{name}}</h2>
<h2>学生性别:{{sex}}</h2>
<button @click="sendStudentName">把姓名给自己的父组件App</button>
</div>
</template>
<script>
export default{
name: 'Student',
components:{},
data() {
return {
name: '张三',
sex: '男'
}
},
methods: {
sendStudentName(){
}
},
}
</script>
在这个sendStudentName()
函数里面我就想触发bilibili
事件
之前说是吧bilibili
给了Student
实例对象上,所以要找也是去Student的组件实例对象身上(VueComponent)
在Student.vue
里可以轻而易举的拿到这个实例对象(VueComponent),用this
;但接下来的问题是,你怎么触发:
借助一个特殊的方法,这个方法名字叫做$emit
(没有触发的意思,它的本意是爆发、发射),虽然没有触发的含义,但是我们可以想成是触发;它是个函数$emit()
里面的实参就是你想要触发哪个事件(这里是this.$emit('bilibili')
),要传数据this.$emit('bilibili',this.name)
,整体:
<template>
<div class="studentBack">
<h2>学生姓名:{{name}}</h2>
<h2>学生性别:{{sex}}</h2>
<button @click="sendStudentName">把姓名给自己的父组件App</button>
</div>
</template>
<script>
export default{
name: 'Student',
components:{},
data() {
return {
name: '张三',
sex: '男'
}
},
methods: {
sendStudentName(){
//触发Student组件实例身上的bilibili事件
this.$emit('bilibili',this.name)
}
},
}
</script>
App.vue
demo(name){
console.log('demo被调用了',name)
}
这俩个都是子组件给父组件传值
这俩个的共同点就是:都要在父组件配置一个回调函数
自定义的优点就是你不用在这里用props
自己去收,收完在用
另一种写法:
<Student ref="student"/>
一写这个你就要知道你能用this.$refs.student
我就可以获取到Student这个组件的实例对象
App.vue
mounted(){//只要在哪个组件里面就意味着哪个组件挂载完毕
this.$refs.student
}
this.$refs.student
这就是Student的组件实例对象,接下来就可以绑定事件了,随后调一个方法$on
(当什么什么时候)
$on()里的参数:
- 第一个参数:什么事件被触发的时候,写成字符形式
- 第二个参数:当触发的时候我要执行一个回调:
methods: {
getSchoolName(name){
console.log('App收到了学校名:',name)
},
demo(name){
console.log('demo被调用了',name)
}
},
mounted() {
this.$refs.student.$on('bilibili',this.demo)
},
这样你可以实现同样的效果
这种方法虽然麻烦,但灵活性很强
第一种@
或者v-on
的写法,只要模板一解析瞬间就绑完了
如果的需求是等三秒ajax请求发送完回来我再给你绑定自定义事件。第二种就可以
mounted() {
setTimeout(()=>{
this.$refs.student.$on('bilibili',this.demo)
},3000)
},
如果没有这种需求可以选择第一种方法
这里面还涉及到另外一个事
就是有些时候,我想让我这个自定义事件触发一次之后就不能再触发了,那怎么写:
如果是以第二种方式去写,你可以考虑换一个API($once
)
this.$refs.student.$once('bilibili',this.demo)
如果你用的是第二种方式
<Student v-on:bilibili.once="demo"/>
这里还是涉及到一个问题(传多数据)
当我去触发这个事件的时候,我想传很多参数
Student.vue
sendStudentName(){
//触发Student组件实例身上的bilibili事件
this.$emit('bilibili',this.name,666,888,900)
}
App.vue
demo(name,x,y,z){
console.log('demo被调用了',name,x,y,z)
}
但一般中我们不会给这么多形参去接,如果传递的之很多,有俩种做法:
-
把传递的参数(比如Student.vue里的666,888,900)包装成一个对象
-
在接收的地方(比如App.vue里的demo())无论传了多少值以
...随便去一个名字
(比如...a
)也就是剩余的全都存到a这个数组身上(一般用params
(参数))demo(name,...a){ console.log('demo被调用了',name,a) }