无标题.png我们知道,向子组件传递数据,是通过 v-bind 子类组件定义的 props 属性完成的,这只适用于单向、两层组件之间。同样地,事件传递也是在父组件中用 v-on 给子组件绑定事件,然后在子组件中通过
this.$emit
触发的、以达到修改父组件数据的目的。
那么,在多层嵌套组件中,顶层组件和最底层组件之间如何进行数据传递和事件触发呢?比如,A 组件引用了 B 组件,而 B 组件又引用了 C 组件,怎么在 A 中将数据传给 C,在 C 中,怎么触发 A 中的方法呢?这就是$attrs
和$listeners
的作用了。
Vue2 中的食用
父子之间的通讯
从上图可以看出A组件-爷爷,B是爸爸,C 是孙子
A to B 通过props的方式向子组件传递,B to A 通过在 B 组件中 $emit, A 组件中 v-on 的方式实现
// A 组件
<template>
<div class="attrsA" title="自带属性">
<child-b v-on:handleClick="handleClick"></child-b>
</div>
</template>
<template>
// B组件
<div class="attrsB">
<button @click="handleClick">点击</button>
</div>
</template>
handleClick() {
this.$emit("handleClick");
},
爷孙之间的通讯
借助 B 组件的中转,从上到下props依次传递,从下至上,emit的方式,使得组件之间的业务逻辑臃肿不堪,B组件在其中仅仅充当的是一个中转站的作用。
listeners的出现使得B组件在其中传递props以及事件的过程中,不必在写多余的代码,仅仅是将listeners向上或者向下传递即可
// A 组件
<template>
<div class="attrsA" title="自带属性">
<child-b
:color="'red 未接收的属性'"
title="父组件传入"
title2="父组件传入2"
test="test"
@handleClick="handleClick"
@handleClickName="handleClickName"
/>
</div>
</template>
<template>
// B组件
<div class="attrsB">
<child-c v-on:handleClick="handleClick" v-bind="$attrs" v-on="$listeners"></child-c>
</div>
</template>
<template>
// C组件
<div >
{{$attrs}}
<button @click="handleClick">点击</button>
<button @click="handleClickName">handleClickName</button>
</div>
</template>
props: {
},
methods: {
handleClick() {
this.$emit("handleClick");
},
handleClickName() {
this.$emit("handleClickName");
},
}
屏幕截图 2023-04-07 234533.png
$attrs
接收除了props声明外的所有绑定属性(class、style除外)
接收除了带有.native事件修饰符的所有事件监听器
inheritAttrs
如果你不希望组件的根元素继承特性,你可以在组件的选项中设置 inheritAttrs: false。(.不管inheritAttrs为true或者false,子组件中都能通过$attrs属性获取到父组件中传递过来的属性。)
Vue3 中使用
在vue3中的$attrs的变化
attrs中。
$attrs现在包括class和style属性。
爷爷组件-A
<template>
<ChildB data="data" style="color:red" @handleClick="handleClick" />
</template>
<script setup>
import ChildB from './ChildB.vue'
const handleClick = () => {
console.log("爷爷组件的点击");
}
</script>
父组件 - B
<template>
<div>{{ title }}</div>
<ChildC v-bind="$attrs" />
</template>
<script>
// 普通 <script>, 在模块作用域下执行 (仅一次)
// 声明额外的选项
export default {
inheritAttrs: false,
customOptions: {}
}
</script>
<script setup>
import ChildC from './ChildC.vue'
import { useAttrs } from "vue";
defineProps({
title: {
type: String,
default: "父组件",
},
});
const attrs = useAttrs()
console.log(attrs, 'attrs-中转组件-父组件-');
</script>
孙组件 -C
<template>
<div @click="handleClick">
孙组件
</div>
</template>
<script setup>
import {useAttrs} from 'vue'
const attrs = useAttrs()
let emit = defineEmits('handleClick')
console.log(attrs,'attrs-孙组件')
const handleClick = () => {
emit('handleClick','孙组件');
}
</script>
inheritAttrs结果
image.png image.png
配置inheritAttrs
参考vue3官方文档:与普通的<script> 一起使用
<script>
// 普通 <script>, 在模块作用域下执行 (仅一次)
// 声明额外的选项
export default {
inheritAttrs: false,
customOptions: {}
}
</script>
<script setup>
</script>
或
export default defineComponent({
inheritAttrs: false,
})
结语: listener 在我们二次封装组件,开发组件,还有数据跨级传递等让开发更灵活,方便
网友评论