父子组件通信
父传子
父组件传递给子组件:通过props属性;
- Props是你可以在组件上注册一些自定义的attribute;
- 父组件给这些attribute赋值,子组件通过attribute的名称获取到对应的值
props两种常见用法:
- 方式一:字符串数组,数组中的字符串就是attribute的名称;
props:{
title:String
}
多个可能类型的写法:
props:{
title:[String,Number]
}
- 方式二:对象类型,对象类型我们可以在指定attribute名称的同时,指定它需要传递的类型、是否是必须的、默认值等等
props:{
content:{
type:String,
required:true,
default:"lalalla"
}
}
对象类型的其他写法:
//带有默认值的对象(重要)
//对象或数组的默认值必须从一个工厂函数获取
propA:{
type:Object,
default(){
return {message:'hello'}
}
}
//自定义验证函数
propB:{
validator(value){
return ['success','warning','danger'].includes(value)
}
}
//具有默认值的函数
//与对象或数组默认值不同,这是一个用作默认值的函数而不是一个工厂函数
propC:{
type:Function,
default(){
return 'default Function'
}
}
type类型
- String
- Number
- Boolean
- Array
- Object
- Date
- Function
- Symbol
prop大小写命名 大小写不敏感,使用DOM模板时,驼峰命名法的prop名需要使用等价的短横线分隔命名
非prop的attribute
传递给一个组件某个属性,但是该属性并没有定义对应的props或者emits时,就称之为 非Prop的Attribute
常见包括class
、style
、id属性
Attribute继承
- 当组件有单个根节点时,非Prop的Attribute将自动添加到根节点的Attribute中
- 如果我们不希望组件的根元素继承attribute,可以在组件中设置
inheritAttrs: false:
- 禁用attribute继承的常见情况是需要将attribute应用于根元素之外的其他元素;
- 我们可以通过 $attrs来访问所有的 非props的attribute
- 多个根节点的attribute如果没有显示的绑定,那么会报警告,我们必须手动的指定要绑定到哪一个属性上,如
:class="$attrs.class"
子传父
子组件传递给父组件:通过$emit触发事件
子传父步骤
- 首先,需要在子组件中定义好在某些情况下触发的事件名称;
emits:["add","sub"],
methods:{
increment(){
console.log("+1")
this.$emit("add")
},
decrement(){
console.log("-1")
this.$emit("sub")
}
}
- 其次,在父组件中以v-on的方式传入要监听的事件名称,并且绑定到对应的方法中;
<counter-operation @add="addOne" @sub="subOne"></counter-operation>
methods:{
addOne(){
this.counter++
},
subOne(){
this.counter--
}
}
- 最后,在子组件中发生某个事件的时候,根据事件名称触发对应的事件
emits也可以写成数组或对象
对象写法的目的是为了进行参数的验证
- 传单个参数时:
emits:{
addN:payload=>{
console.log(payload)
}
}
- 传多个参数时
emits:{
addN(num,name,age)=>{
console.log(num,name,age);
if(num>10){
return ture
}
return false
}
}
此时的验证只会警告,但仍可以正常传递参数
父子组件案例
简单的页面切换
//父组件
<template>
<div>
<tab-control :titles="titles" @titleClick="titleClick"></tab-control>
<h2>{{content[currentIndex]}}</h2>
</div>
</template>
<script>
import tabControl from "./tabControl.vue";
export default {
components: {
tabControl,
},
data() {
return {
titles: ["衣服", "鞋子", "裤子"],
content:["衣服页面","鞋子页面","裤子页面"],
currentIndex:0
}
},
methods:{
titleClick(index){
this.currentIndex=index
}
}
};
</script>
<style scoped>
</style>
//子组件
<template>
<div class="tab-control">
<div v-for="(title,index) in titles"
:key="title"
:class="{active:currentIndex===index}"
@click="itemClick(index)"
class="tab-control-item"><span>{{title}}</span></div>
</div>
</template>
<script>
export default {
emits:["titleClick"],
data(){
return{
currentIndex:0
}
},
props:{
titles:{
type:Array,
default(){
return []
}
}
},
methods:{
itemClick(index){
this.currentIndex=index;
this.$emit("titleClick",index)
}
}
}
</script>
<style scoped>
.tab-control{
display: flex;
}
.tab-control-item{
flex: 1;
text-align: center;
font-weight: 700;
}
.tab-control-item.active{
color:red
}
.tab-control-item.active span{
border-bottom: 3px red solid;
}
</style>
非父子组件通信
Provide/Inject
兄弟之间不能用,是子孙之间使用的
- 无论层级结构有多深,父组件都可以作为其所有子组件的依赖提供者;
- 父组件有一个 provide 选项来提供数据;
- 子组件有一个 inject 选项来开始使用这些数据
可以将依赖注入看作是long range props
- 父组件不需要知道哪些子组件使用它 provide 的 property
- 子组件不需要知道 inject 的 property 来自哪里
provide
provide:{
name:"why",
age:18
}
inject
inject:["name","age"]
处理响应式数据
provide(){
return{
length:computed(()=>this.names.length)
}
}
computed返回的是一个ref对象
,需要取出其中的value来使用{{length.value}}
全局事件总线mitt库
Vue3从实例中移除了
o
n
、
on、
on、off 和 $once 方法
npm install mitt
封装一个工具eventbus.js
import mitt from 'mitt'
const emitter = mitt();
export default emitter;
监听事件
created(){
emitter.on("why",(info)={
console.log("why event:",info);
})
<!-- 没传递kobe,不会触发 -->
emitter.on("kobe",(info)={
console.log("kobe event:",info);
})
<!-- 监听所有数据 -->
emitter.on("*",(type,e)={
console.log("* event:",type,e);
})
}
触发事件
methods:{
methodsFunction(){
emitter.emit("why",{name:"why",age:18})
}
}
取消数据监听
-
取消所有监听
emitter.all.clear()
-
取消指定监听
function onFoo(){} //定义一个函数
emitter.on('foo',onFoo) //监听
emitter.off('foo',onFoo) //取消监听