父子组件中的attrs props 理解/继承
首先,父组件可以给子组件传入属性、监听函数(类似onClick),class,style,id,总结起来就是大三类-属性,监听函数,样式!
爷爷组件 -- 有两个监听函数
import { computed, defineComponent, reactive, ref } from "vue";
import { css } from "@emotion/css";
import Child from "./test/Child";
export default defineComponent({
props: {},
setup: (props, { emit }) => {
return () => {
return (
<>
<Child
onHei={(val) => {
console.log("祖父组件", val);
}}
onTest={() => {
console.log("祖父Test");
}}
/>
</>
);
};
},
});
父组件 -给子组件传入了name,age以及onTest,style等属性,函数或者样式等。
import { defineComponent, reactive, ref } from "vue";
import Sun from "./Sun";
export default defineComponent({
// emits: ["hei"],
props: {},
setup: (props, { emit, attrs }) => {
const a = ref("test");
console.log("父组件中props", props);
console.log("父组件中attrs", attrs);
return () => {
return (
<Sun
name={a.value}
age="18"
onTest={() => {
console.log("父级test监听执行");
}}
// {...attrs}
onHei={(val) => {
console.log("父级hei组件", val);
}}
style={{
color: "red",
}}
class="test"
/>
);
};
},
});
子组件-可通过props和attrs看出父组件中的属性或者函数都能拿到。
import { defineComponent, reactive, ref } from "vue";
export default defineComponent({
props: {
name: String,
},
setup: (props, { emit, attrs }) => {
console.log("props", props); // {name: 'test'}
console.log("attrs", attrs); // {age: "18",onHei:()=>{}, onTest:()=>{},style:{color:'red'}}
return () => {
return (
<div
onClick={() => {
emit("hei");
}}
>
点击最底层
</div>
);
};
},
});
通过这种层层嵌套的组件关系,我们可以观察出以下结论
- 我们可以看到,父组件传入的属性或者监听函数都能被props和attrs、emits,具体可以用如下表达式来体现
**父组件传入的所有内容 = 子组件中props + 子组件声明的emits + 子组件中attrs ** - 如果不声明props、emits,则所有内容都可以用attrs拿到,包括style属性等。声明一个props,或者声明一个emits,attrs就少一个内容。
- 一般我们子组件中不直接用on监听的事件,只是用到传递过来的属性值,父组件中的事件监听,可以靠emit主动派发出去。
- 如果子组件中不声明props,emits,attrs可以拿到所有的内容,而attrs的内容,又默认都给了子组件继承下去了!!!
- 基于第4点,子组件中声明的props或者emits无非不就是截胡的意思(也就是props和emits是你的肉,attrs是子孙的汤,你吃肉,别人喝汤),也就是把父辈的东西截胡了,props声明的属性只有到了我这一辈能用,子孙别想用;emits声明的事件,只有我触发了,父辈能监听到,你子孙触发这些事件,父辈是监听不到的。
我们通过以上案例发现,父组件中的内容会默认通过attrs继承给子组件(或者是根元素),那么我们如果不想这么默认,该怎么操作?因为实际情况下,确实我们子组件中正常能通过props拿到属性,emit可以正常派发事件,其他的我不想这么默认继承下去。
以下,我们通过inheritAttrs: false将默认attrs传递给子组件的操作给关闭了。注意,这里虽然关闭了默认继承,但是attrs里面的值还是正常能拿到。
export default defineComponent({
inheritAttrs: false, //关闭继承
setup: (props, { emit, attrs }) => {
const a = ref("test");
console.log("父组件中props", props);
console.log("父组件中attrs", attrs);
return () => {
return (
<Sun
name={a.value}
age="18"
onTest={() => {
console.log("父级test监听执行");
}}
// {...attrs}
onHei={(val) => {
console.log("父级hei组件", val);
}}
style={{
color: "red",
}}
class="test"
/>
);
};
},
});
因为有这种默认的继承,会出现两种现象1、对应属性来说,父辈的属性能够出现在子子孙孙里面的(除非有人中间截胡);2、对应监听函数来说,这样一直传下去,会有一个现象是子孙里面派发一个事件处理,父辈的监听事件都能监听到(也是除非中间有人截胡)
以上这个信息很关键,在vue3封装高阶组件的时候,能体会到,你包装了一层其他的组件,那么其他组件本身派发的事件,你包装的那一层也能监听到,就是因为这种父辈给子孙事件继承的原因!!!这种设计也方便了组件的封装!!!
子组件派发事件与传入函数回调处理对比
父组件 -通过属性传递了一个函数进行
export default defineComponent({
props: {},
setup: (props, { emit }) => {
return () => {
return (
<>
<Child
hei={(val) => {
console.log("祖父组件", val);
}}
/>
</>
);
};
},
});
子组件 -子组件中利用执行props传入的函数来实现类似emit派发事件的效果。
export default defineComponent({
props: {
hei: Function,
},
setup: (props, { emit, attrs }) => {
return () => {
return (
<div
onClick={() => {
props.hei(666);
}}
>
点击
</div>
);
};
},
});
可以发现,利用传入一个函数同样可以实现emit的效果,但是还是建议用官方的emit。
标签:console,log,vue3,attrs,props,组件,return,小结 From: https://www.cnblogs.com/teamemory/p/17648326.html