p80 组件自定义事件: 子组件 传参 给父组件
子组件传参给父组件有个前提,就是“父得提前给子 一个函数
”,子 在合适的时候调用那个函数。
(笔记都写在了代码注释中)
App.vue
<template>
<div class="app">
<h1>{{ msg }},学生姓名是:{{ studentName }}</h1>
<!-- 通过父组件给子组件传递函数类型的props实现:子给父传递数据 -->
<!-- 还可以绑定【函数】,函数名 和 变量名都是地址指针 -->
<School :getSchoolName="getSchoolName" />
<!-- 1、通过父组件给子组件绑定一个自定义事件实现:
【子给父传递数据】(第一种写法,使用@或v-on)
子组件中通过 $emit 触发事件,(父传子 只需要子组件中 props接收就好了)
【父组件中绑定,子组件中触发】
2、模板里写什么都不需要this
-->
<!-- <Student @atguigu="getStudentName" /> -->
<!-- <Student @atguigu.once="getStudentName" /> -->
<!-- <Student @atguigu="getStudentName" @demo="m1" /> -->
<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种写法,使用ref) -->
<!-- <Student ref="student"/> -->
<!-- @click="show" 会被认为是自定义事件, @click.native才会被认为原生DOM事件-->
<!-- Student中不让写两个根元素(最外层的div) @click.native事件就把对象给到最外层的根元素了-->
<Student ref="student" @click.native="show" />
</div>
</template>
<script>
import Student from './components/Student'
import School from './components/School'
export default {
name: 'App',
components: { School, Student },
data() {
return {
msg: '你好啊!',
studentName: ''
}
},
methods: {
getSchoolName(name) {
// 因为 函数名传递给了子组件,所以子组件中能够访问该函数(函数具有传参的功能)
console.log('App收到了学校名:', name)
},
// 只要是methods里面的this,就一定指向App的vc
getStudentName(name, ...params) { // 接收后面的内容
console.log('App收到了学生名:', name, params)
this.studentName = name
},
m1() {
console.log('demo事件被触发了!')
},
show() {
alert(123)
}
},
// APP只要挂载完毕,就【自动加载】
// 之所以需要【挂载】是因为没有事件触发,所以需要挂载
mounted() {
// $on :【监听】当……时候,当atguigu事件被 (子组件)【触发$emit】的时候,(父组件)执行【回调】 this.getStudentName
// this.$refs.student.$once('atguigu',this.getStudentName) //绑定自定义事件(监听一次)
// 1-1、这里调用了一次函数:(推荐第一种写法)
// this是指向Student的vc,但是调用的函数里面的this以App的vc为主!
this.$refs.student.$on('atguigu', this.getStudentName) //绑定自定义事件,此方法更加灵活,可以等ajax发回来一个请求后再执行
// 1-2、要是写成以下:有坑 this指向问题
/* this.$refs.student.$on('atguigu', function(name, ...params){
console.log('App收到了学生名:', name, params)
console.log(this); //this:Student 的 VueComponent组件,不是App的,因为是Student组件触发的
// this.studentName = name // 不起作用
}) */
// 1-3、箭头函数:箭头函数没有自己的this,就往外找,找到mounted的this ,即App的vc
/* this.$refs.student.$on('atguigu', (name, ...params) => {
console.log('App收到了学生名:', name, params)
console.log(this); //this:Student 的 VueComponent组件,不是App的,因为是Student组件触发的
this.studentName = name //正确
}) */
},
/* mounted() {
setTimeout(()=>{
this.$refs.student.$on('atguigu', this.getStudentName)
}, 3000)
// 子组件中就算【触发】了事件,也得等到3s才反应。
}, */
}
</script>
<style scoped>
.app {
background-color: gray;
padding: 5px;
}
</style>
-{{name}} 的来源:data、props、computed 计算属性
main.js
//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//关闭Vue的生产提示
Vue.config.productionTip = false
//创建vm
new Vue({
el: '#app',
render: h => h(App),
/* mounted() {
setTimeout(() => {
this.$destroy()
}, 3000)
}, */
})
components/School.vue
<template>
<div class="school">
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
<button @click="sendSchoolName">把学校名给App</button>
</div>
</template>
<script>
export default {
name:'School',
// 接收父组件传下来的,把getSchoolName函数放在 VueComponent(this) 上
props:['getSchoolName'],
data() {
return {
name:'尚硅谷',
address:'北京',
}
},
methods: {
sendSchoolName(){
console.log(this); //VueComponent
// 把子组件的参数 通过函数传递上父组件
//这里的this.getSchoolName,和父组件getSchoolName 都指向同一个 函数地址,父组件和子组件都可以调用这个函数
this.getSchoolName(this.name)
}
},
}
</script>
<style scoped>
.school{
background-color: skyblue;
padding: 5px;
}
</style>
components/Student.vue
<template>
<div class="student">
<h2>学生姓名:{{ name }}</h2>
<h2>学生性别:{{ sex }}</h2>
<h2>当前求和为:{{ number }}</h2>
<button @click="add">点我number++</button>
<button @click="sendStudentlName">把学生名给App</button>
<button @click="unbind">解绑atguigu事件</button>
<button @click="death">销毁当前Student组件的实例(vc)</button>
</div>
</template>
<script>
export default {
name: 'Student',
data() {
return {
name: '张三',
sex: '男',
number: 0
}
},
methods: {
add() {
console.log('add回调被调用了')
this.number++
},
sendStudentlName() {
//【触发】Student组件实例身上的atguigu事件,即 @atguigu = xxx事件
this.$emit('atguigu', this.name, 666, 888, 900)
// this.$emit('demo')
// this.$emit('click')
},
unbind() {
this.$off('atguigu') //解绑一个自定义事件
// this.$off(['atguigu','demo']) //解绑多个自定义事件
// this.$off() //解绑所有的自定义事件
},
death() {
this.$destroy() //销毁了当前Student组件的实例,销毁后所有Student实例的自定义事件全都不能用了,但是原生的js可以使用
}
},
}
</script>
<style lang="less" scoped>
.student {
background-color: pink;
padding: 5px;
margin-top: 30px;
}
</style>