vue3父子组件通信小结

父子组件中的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>
      );
    };
  },
});

通过这种层层嵌套的组件关系,我们可以观察出以下结论

  1. 我们可以看到,父组件传入的属性或者监听函数都能被props和attrs、emits,具体可以用如下表达式来体现
    **父组件传入的所有内容 = 子组件中props + 子组件声明的emits + 子组件中attrs **
  2. 如果不声明props、emits,则所有内容都可以用attrs拿到,包括style属性等。声明一个props,或者声明一个emits,attrs就少一个内容。
  3. 一般我们子组件中不直接用on监听的事件,只是用到传递过来的属性值,父组件中的事件监听,可以靠emit主动派发出去。
  4. 如果子组件中不声明props,emits,attrs可以拿到所有的内容,而attrs的内容,又默认都给了子组件继承下去了!!!
  5. 基于第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。

posted @ 2023-08-22 13:49  茶记忆  阅读(124)  评论(0编辑  收藏  举报