父传子(props、插槽、ref)
一、props
1.代码实现:
父组件
<template>
<!-- 通过:addTodo=""给子组件传值 -->
<div class="todo-wrap"><MyHeader :addTodo="addTodo"/>父组件</div>
</template>
<script>
export default {
data() {};
components:{MyHeader},
methods: {
addTodo(todoObj){
this.todos.unshift(todoObj)
},;//给子组件传的值
}
</script>
子组件
<template>
<!-- 通过props接受值后可直接使用 -->
<div>子组件{{addTodo}}</div>
</template>
<script>
export default {
name:'MyHeader',
//通过props接收父组件传来的值
props: {
addTodo: {
// 定义接收的类型[String, Undefined, Number]
type: String,
// 定义是否必须传
required: true,
// 定义默认值
default: ''
},
},
data() {},
};
</script>
props三种写法:
1.(只接收)props:['name(父组件传的值)']
2.(限制类型)props:{name(父组件传的值):String( 定义接收的类型)}
3.(限制类型、限制必要性、指定默认值)
props: {
name(父组件传的值)父组件传的值: {
// 定义接收的类型[String, Undefined, Number]
type: String,
// 定义是否必须传
required: true,
// 定义默认值
default: ''
注意:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。
二、插槽
定义:所谓的插槽就是⼀个占位符,将⾃定义组件的内容展示出来
- 作用:让父组件可以向子组件指定位置插入html结构。
- 分类:默认插槽、具名插槽、作用域插槽
- 默认插槽
使用场景:使用者没有填充内容,插槽指定默认数据。
代码实现:
父组件中:
<Category>
<div>html结构1</div>
</Category>
子组件中:
<template>
<div>
<!-- 定义插槽 -->
<slot>插槽默认内容...</slot>
</div>
</template>
4.具名插槽
使用场景:给特定的slot添加内容。
代码实现:
父组件中:
<Category>
<template slot="center">
<div>html结构1</div>
</template>
<template v-slot:footer>
<div>html结构2</div>
</template>
</Category>
子组件中:
<template>
<div>
<!-- 定义插槽 -->
<slot name="center">插槽默认内容...</slot>
<slot name="footer">插槽默认内容...</slot>
</div>
</template>
5.作用域插槽
使用场景:子组件提供数据,父组件决定如何渲染。
定义:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。
代码实现:
父组件中:
<Category>
<template scope="scopeData">
<!-- 生成的是ul列表 -->
<ul>
<li v-for="g in scopeData.games" :key="g">{{g}}</li>
</ul>
</template>
</Category>
<Category>
<template slot-scope="scopeData">
<!-- 生成的是h4标题 -->
<h4 v-for="g in scopeData.games" :key="g">{{g}}</h4>
</template>
</Category>
子组件中:
<template>
<div>
<!--通过v-bind来暴露数据 :数据名=“要暴露的数据”-->
<slot :games="games"></slot>
</div>
</template>
<script>
export default {
name:'Category',
props:['title'],
//数据在子组件自身
data() {
return {
games:['红色警戒','穿越火线','劲舞团','超级玛丽']
}
},
}
</script>
三、ref
- 被用来给元素或子组件注册引用信息(id的替代者)
- 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)。
- 使用方式:
父组件
<template>
<!--1. 打标识-->
<h1 ref="xxx">.....</h1>或`<School ref="xxx"></School>
</template>
<script>
//引入子组件
import School from './components/School'
// 获取:
export default {
name:'',
components:{School},
data() {
return {}},
methods: {
showDOM(){
console.log(this.$refs.title) //真实DOM元素
}
```this.$refs.xxx```
</script>
适用于,后面动态给子组件传值,这样会比较快速,但是操作的时候记得备注,方便后续追踪及维护。
子传父(组件的自定义事件)
原理:通过父组件给子组件绑定一个自定义事件实现:子给父传递数据。
- 使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件。
- 作用:在封装组件时,为了让组件的使用者可以监听到组件内状态的变化。
- 写法:
父组件:
第一种写法,使用@或v-on
<template>
<Student ref="student" @click.native="show"/>
</template>
第二种写法,使用ref:
<template>
<Demo ref="demo"/>
</template>
......
<script>
import Student from './components/Student'
mounted(){
this.$refs.student .$on('atguigu',this.test)
}
</script>
若想让自定义事件只能触发一次(父组件),可以使用
once
修饰符,或$once
方法。触发自定义事件(子组件):
this.$emit('自定义事件名',数据)
解绑自定义事件(子组件)
this.$off('自定义事件名')
this.$off() //解绑所有的自定义事件销毁了当前t组件的实例(子组件)
this.$destroy()
组件上也可以绑定原生DOM事件(父组件),需要使用
native
修饰符。