vue2/vue3手写专题——实现父子组件通信、祖先通信的方法

news2024/11/20 11:22:58

Vue 组件通信可以使用以下几种方法:

  1. 父组件向子组件传递数据:使用 props 将数据从父组件传递给子组件,子组件可以通过 props 接收和使用数据。
  2. 子组件向父组件传递数据:使用 $emit 触发自定义事件,父组件可以通过事件监听器来接收数据。
  3. 非父子组件之间的通信:使用一个中央事件总线或 Vuex 状态管理库来管理和共享数据。
  4. 通过 provideinject 传递数据:在父组件中使用 provide 提供数据,在子组件中使用 inject 注入数据,可以实现跨级组件通信。
  5. 通过 ref 获取组件实例:在父组件中使用 ref 获取子组件的实例,可以直接调用子组件的方法或属性。
  6. 通过 $parent$children 访问父组件或子组件:在组件中使用 $parent 可以访问父组件,使用 $children 可以访问子组件,可以直接调用父组件或子组件的方法或属性。但是在实际开发中,它们的使用并不是很常见,因为它们可能会导致组件的耦合性过高,不利于代码的可维护性和可扩展性。

 组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。仔细想想,几乎任意类型的应用界面都可以抽象为一个组件树:

例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。为了能让页面正常工作,一些功能可能要求我们和父级组件进行沟通。

父子组件双向通信 props+$emit

在 Vue 中,父子组件通信是非常常见的场景,其中 props 和 $emit 是两种主要的机制用于实现父子组件之间的通信。

props 和 $emit 是两种主要的机制用于实现父子组件之间的通信。props 是父组件向子组件传递数据的一种机制,子组件可以通过 props 选项声明需要接收的数据,父组件可以通过标签的属性将数据传递给子组件。

如果子组件需要向父组件传递数据,子组件可以通过调用内建的 $emit 方法并传入事件名称来触发一个事件。父组件可以通过 v-on:或@方法监听子组件的自定义事件,并在事件回调函数中处理数据,从而实现子组件向父组件传递数据的需求。 

Props(属性)

  • 用法:在父组件中通过在子组件标签上绑定属性的方式传递数据,子组件通过 props 属性接收数据。
  • 特点:props 是单向数据流,父组件传递数据给子组件,子组件接收并渲染这些数据,但子组件不能直接修改 props 中的数据。

$emit(事件)

  • 用法:子组件通过 $emit 方法触发一个自定义事件,并传递数据,父组件通过在子组件标签上使用 @event 来监听这个事件,并在相应的方法中处理传递过来的数据。
  • 特点:$emit 是一种子组件向父组件通信的方式,子组件可以通过触发自定义事件来传递数据给父组件。

vue2示例——props+$emit

 子组件

<template>
  <div class="child-component">
    <h3>我是子组件</h3>
    <span>{{ msg }}</span>
    <button @click="sendMessageToParent">我可以将数据传给父组件</button>
  </div>
</template>
<script>
export default {
  name: "ChildComponent",
  props: {
    msg: String,
  },
  methods: {
    sendMessageToParent() {
      this.$emit("sendMessage", "我是子组件数据");
    },
  },
};
</script>
<style>
.child-component {
  border: 1px solid green;
  width: 50vw;
  margin: auto;
}
</style>

 vue2的选项式api写法。在script中通过export default导出一个对象。在对象中,使用data(){return {key:val,ke:val}定义响应式数据。method:{func1,func2}定义方法。通过props属性,定义需要接收父组件的变量及类型,props:{msg:String}。

在组件的选项中,data 函数是一个函数,而不是一个对象,这是因为 Vue 需要在每个实例上创建一个独立的数据对象,避免多个实例共享同一个数据对象,从而导致数据污染或冲突。 

props在子组件的使用:通过props属性声明一个msg变量,类型是String。

$emit在子组件的使用:通过this.$emit("事件名”,传递给父组件的数据),向父组件抛出一个sendMessage事件。

父组件

<template>
  <div class="parent-component">
    <h2>我是父组件</h2>
    <div>{{ childMsg }}</div>
    <ChildComponent
      :msg="msg"
      @sendMessage="getMessageFromChild"
    ></ChildComponent>
  </div>
</template>

<script>
import ChildComponent from "./ChildComponent.vue";
export default {
  name: "ParentComponent",
  components: {
    ChildComponent,
  },
  data() {
    return { msg: "父组件的数据", childMsg: "" };
  },
  methods: {
    getMessageFromChild(arg) {
      this.childMsg = this.childMsg + arg;
    },
  },
};
</script>
<style>
.parent-component {
  border: 1px solid blue;
}
</style>

 vue2的选项式api写法。在components:{组件}显示声明子组件。在组件的 methods、computed 和 watch 等选项中,访问数据需要使用 this 关键字,因为 this 指向当前组件的实例,而当前组件的实例上有一个 data 函数返回的数据对象,该对象中定义了所有的数据

props在父组件的使用:父组件通过属性绑定的方式,<ChildComponent :msg=“msg”>,将父组件中定义的数据传给子组件的msg属性。

$emit在父组件的使用:在父组件里通过事件监听@sendMessage,接收子组件抛出的sendMessage方法,并在父组件中通过getMessageFromChild方法,接收子组件在$emit中第二个参数传入的数据,并处理子组件的数据。 

 效果演示

 vue3示例——defineProps+defineEmits

子组件

vue3里,通过defneProps、defineEmits两个函数定义属性和事件。defneProps接收一个对象{key:{属性描述}},defineEmits接收一个数组,数组每项是个字符串,标识向外抛出的事件名。

<template>
  <div class="child-component">
    <h3>我是子组件</h3>
    <span>{{ msg }}</span>
    <button @click="sendMessageToParent">我可以将数据传给父组件</button>
  </div>
</template>
<script setup>
import { defineProps, defineEmits } from "vue";
//定义属性props
const props = defineProps({
  msg: {
    type: String,
    required: true,
  },
});
//定义emit事件
const emit = defineEmits(["sendMessage"]);
function sendMessageToParent() {
  emit("sendMessage", "我是子组件数据");
}
</script>
<style>
.child-component {
  border: 1px solid green;
  width: 50vw;
  margin: auto;
}
</style>

父组件

vue3 setup组合式api写法,不用写method:{},data()。不需要使用this。定义响应式数据用ref显示定义一切类型数据,使用.value获取实际数据值。

<template>
  <div class="parent-component">
    <h2>我是父组件</h2>
    <div>{{ childMsg }}</div>
    <ChildComponent
      :msg="msg"
      @sendMessage="getMessageFromChild"
    ></ChildComponent>
  </div>
</template>
<script setup>
import { ref } from "vue";
import ChildComponent from "./ChildComponent.vue";
const msg = ref("父组件的数据");
let childMsg = ref("");
function getMessageFromChild(arg) {
  childMsg.value = childMsg.value + arg;
}
</script>
<style>
.parent-component {
  border: 1px solid blue;
  width: 100vw;
}
</style>

 跨级组件单向通信provide+inject

在 Vue 2 中,props$emit 则只能在父子组件直接传值。但如果需要更加方便、灵活的进行通信,可以使用 provideinjectprovideinject 主要用于跨级组件传值,且没有限制 depth。

  • 这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在其上下游关系成立的时间里始终生效。
  • provide 选项允许我们指定我们想要提供给后代组件的数据/方法 ;祖先组件不需要知道哪些后代组件使用它提供的 property或方法
  • 在任何后代组件里,我们都可以使用 inject 选项来接收指定的我们想要添加在这个实例上的方法或数据。后代组件不需要知道被注入的 property 或方法来自哪里

 vue2示例

  • provideObject | () => Object
  • injectArray<string> | { [key: string]: string | Symbol | Object }

祖先组件

使用provide的函数式写法,访问data中定义的属性,和methods定义的方法,

<template>
  <div class="parent-component">
    <h2>我是父组件</h2>
    <ChildComponent></ChildComponent>
  </div>
</template>

<script>
import ChildComponent from "./ChildComponent.vue";
export default {
  name: "ParentComponent",
  components: {
    ChildComponent,
  },
  data() {
    return {
      parentMsg: "我是父组件消息",
    };
  },
  provide() {//provide函数,注入parentMsg属性和greet方法
    return {
      parentMsg: this.parentMsg,
      greet: this.greet,
    };
  },
  methods: {
    greet() {
      console.log("Hello from ParentComponent!");
    },
  },
};
</script>
<style>
.parent-component {
  border: 1px solid blue;
}
</style>

子孙组件

在子孙组件中使用inject属性,接收一个数组,将父组件传递的属性和方法名写进去。在子组件中通过this访问方法。属性可以直接使用。

<template>
  <div class="child-component">
    <h3>我是子组件</h3>
    <span>接收到的父组件的消息:{{ parentMsg }}</span>
    <button @click="callGreet">我是父组件传递的事件</button>
  </div>
</template>
<script>
export default {
  name: "ChildComponent",
  inject: ["parentMsg", "greet"], //通过inject属性,接受一个数组,每项是个字符串,表示属性名或方法名
  methods: {
    callGreet() {
      this.greet(); //调用父组件传递的方法
    },
  },
};
</script>
<style>
.child-component {
  border: 1px solid green;
  width: 50vw;
  margin: auto;
}
</style>

效果演示

思考:provide注入的数据,可以在定义provide的组件中使用methods方法修改吗?

在定义 provide 的组件中使用 methods 方法修改 provide 提供的数据是不推荐的,因为 provide 提供的数据应该是用于向子组件传递数据的,而不是在提供的组件中进行修改的。如果想要在提供的组件中修改数据并让子组件感知这些更改,可以考虑使用事件总线或 Vuex 等状态管理工具。

在vue生命周期中,provide和inject是在挂载前完成的。之后数据的更改update那些不会在对provide和inject执行操作。

vue3示例

在 Vue 3 中,provide 可以接受一个响应式对象作为参数,而在 Vue 2 中则只能接受普通对象。这意味着在 Vue 3 中,如果使用 provide 提供的数据发生变化,那么所有依赖它的组件都会重新渲染,而在 Vue 2 中则需要使用 Vue.observable 来手动创建一个响应式对象。

祖先组件

<template>
  <div class="parent-component">
    <h2>我是父组件</h2>
    <ChildComponent></ChildComponent>
  </div>
</template>
<script setup>
import { ref, provide } from "vue";
import ChildComponent from "./ChildComponent.vue";
const msg = ref("父组件的数据");
function greet() {
  console.log("Hello from ParentComponent!");
}

provide("parentMsg", msg);
provide("greet", greet);
</script>
<style>
.parent-component {
  border: 1px solid blue;
  width: 100vw;
}
</style>

子孙组件

<template>
  <div class="child-component">
    <h3>我是子组件</h3>
    <span>接收到的父组件的消息:{{ parentMsg }}</span>
    <button @click="callGreet">我是父组件传递的事件</button>
  </div>
</template>
<script setup>
import { inject } from "vue";
const parentMsg = inject("parentMsg");
const callGreet = inject("greet");
</script>
<style>
.child-component {
  border: 1px solid green;
  width: 50vw;
  margin: auto;
}
</style>

$refs获取子组件的实例

$refs 的主要用途是在父组件中获取子组件的实例,从而可以调用子组件的方法或直接操作子组件的数据。我们可以在父组件中为子组件设置一个 ref 属性,然后在父组件的方法中获取子组件的实例,并调用子组件的方法。

在 Vue 2 中,我们可以直接使用 $refs 来访问子组件的方法,而在 Vue 3 中,需要使用 defineExpose 函数将子组件中的方法抛出来,然后在父组件中使用 ref 函数获取到子组件的实例,并调用子组件中的方法。

这是因为在 Vue 2 中,子组件的实例是作为父组件的一个子属性保存下来的,并且子组件中的方法可以直接在父组件中调用。

但是,在 Vue 3 中,由于组件封装的设计,子组件中的方法不再是父组件的一个子属性,而是通过 provide 函数提供给子组件的,子组件可以通过 inject 函数来注入父组件提供的数据和方法。

 因此,在 Vue 3 中,需要使用 defineExpose 函数将子组件中的方法抛出来,然后在父组件中使用 ref 函数获取到子组件的实例,并调用子组件中的方法。

vue2示例——$refs+ref

 子组件

在子组件定义一个chidMethod方法

<template>
  <div class="child-component">
    <h3>我是子组件</h3>
  </div>
</template>
<script>
export default {
  name: "ChildComponent",
  methods: {
    childMethod() {
      console.log("我是子组件的方法");
    },
  },
};
</script>
<style>
.child-component {
  border: 1px solid green;
  width: 50vw;
  margin: auto;
}
</style>

 父组件

在父组件中调用子组件的时候通过ref绑定一个childRef属性,在methods中通过$refs.childRef调用子组件的方法。

<template>
  <div class="parent-component">
    <h2>我是父组件</h2>
    <button @click="callChildMethod">点我调用子组件方法</button>
    <ChildComponent ref="childRef"></ChildComponent>
  </div>
</template>

<script>
import ChildComponent from "./ChildComponent.vue";
export default {
  name: "ParentComponent",
  components: {
    ChildComponent,
  },

  methods: {
    callChildMethod() {
      this.$refs.childRef.childMethod();
    },
  },
};
</script>
<style>
.parent-component {
  border: 1px solid blue;
}
</style>

效果示例

vue3示例——$refs+ defineExpose

使用 <script setup> 的组件是默认关闭的——即通过模板引用或者 $parent 链获取到的组件的公开实例,不会暴露任何在 <script setup> 中声明的绑定。

如果子组件中的方法需要被父组件访问,需要使用 defineExpose 函数将其抛出来,这样父组件就可以通过 ref 函数获取到子组件的实例,并调用子组件中的方法。

子组件

组件定义一个childMethod方法,通过defineExpose抛出去

<template>
  <div class="child-component">
    <h3>我是子组件</h3>
  </div>
</template>
<script setup>
function childMethod() {
  console.log("我是子组件的方法");
}
//调用defineExpose方法,将子组件要抛出的方法放在对象里
defineExpose({
  childMethod,
});
</script>
<style>
.child-component {
  border: 1px solid green;
  width: 50vw;
  margin: auto;
}
</style>

父组件

<template>
  <div class="parent-component">
    <h2>我是父组件</h2>
    <button @click="callChildMethod">点我调用子组件方法</button>
    <ChildComponent ref="childRef"></ChildComponent>
  </div>
</template>
<script setup>
import { ref, provide } from "vue";
import ChildComponent from "./ChildComponent.vue";
const msg = ref("父组件的数据");

const childRef = ref(null); //定义childRef变量,赋给子组件的ref属性

function callChildMethod() {
  childRef.value.childMethod(); //通过childRef拿到子组件访问实例,调用子组件的方法
}
</script>
<style>
.parent-component {
  border: 1px solid blue;
  width: 100vw;
}
</style>

思考,为什么拿到子组件实例的ref变量childRef必须定义为响应式的?

可以试下,使用childRef=null;然后childRef.childMethod()会报错。

vue的语法规定:如果要在模板中访问或操作一个变量,该变量必须是响应式的。使用 ref 函数可以将一个普通变量转换为响应式变量,从而确保在模板中能够正确地追踪和更新变量的变化。因此,为了确保在 Vue 3 中能够正确地引用子组件实例,需要将 childRef 定义为响应式的 ref 变量。

$attrs+$listeners获取父组件传递的属性和事件

在 Vue 中,$attrs$listeners 在二次封装组件中的使用比较多。通常的业务组件用props+emit或者ref比较多。但是,在开发可复用的组件时,我们可能需要将组件的属性和事件暴露给父组件,以便父组件可以自定义组件的行为。在这种情况下,我们可以使用 $attrs$listeners 来传递属性和事件

在使用 $attrs$listeners 时,我们需要注意以下几点:

  • 在组件的 props 中定义了与父组件相同的属性时,父组件传递的这些属性会被 props 接收,不会被 $attrs 接收。
  • 在组件的 inheritAttrs 选项设置为 false 时,父组件传递的属性不会被默认添加到组件的根元素上,需要手动使用 v-bind="$attrs" 来绑定这些属性。
  • vue2中,在组件的 methods 中定义的事件处理函数,不会被 $listeners 接收

vue2 VS vue3

  • 在 Vue 2 中,$attrs 对象中不包含父组件中的 classstyle 属性,使用 :class:style 绑定分别将父组件中的 classstyle 属性传递给子组件的根元素
  • Vue 3 中,$listeners 对象在 Vue 3 中已被移除。事件监听器现在是 $attrs 的一部分。$attrs 对象包含了父组件中传递给子组件的所有属性以及事件。当然props定义的不在$attrs内。
  • $attrs只能在template模板使用,在script中用useAttrs方法获取属性。

设置inheritAttrs: false的作用

注意:设置inheritAttrs: false的作用是禁用属性继承,这意味着父组件中的未被子组件声明的属性不会自动应用到子组件的根元素上。这样做的目的是为了避免样式冲突等:例如当父组件中的属性与子组件的 classstyle 发生冲突时,可以使用inheritAttrs:false。

但是,即使设置了inheritAttrs: false,父组件的属性仍然会传递给子组件,仍然可以通过$attrs拿到属性,只是不会自动应用到子组件的根元素上。 

 vue2示例——$attrs+$listeners

在 Vue 2 中,你可以通过 this.$attrs 访问传递给组件的 attribute,以及通过 this.$listeners 访问传递给组件的事件监听器。结合 inheritAttrs: false,开发者可以将这些 attribute 和监听器应用到根元素之外的其它元素。

Vue 2 中,$attrs 对象中不包含父组件中的 classstyle 属性,因为这两个属性在 Vue 中有特殊的处理方式。 用 :class:style 绑定分别将父组件中的 classstyle 属性传递给子组件的根元素。

父组件

父组件定义了两个事件,两个属性,和一个class样式类。绑定到子组件ChildComponent中。

使用子组件,假设子组件是一个已经封装好的组件,事件也是子组件抛出可以使用的。

在ChildComponent通过@绑定事件,通过:绑定属性。并且测试绑定class能否生效。

ChildComponent不通过props接收属性。测试一下子组件通过$attrs和$listeners能否接受到方法和属性。

<template>
  <div class="parent-component">
    <h2>我是父组件</h2>
    <ChildComponent
      @custom-event="handleCustomEvent"
      @change="handleChange"
      :class="class1"
      :data="data"
      :formData="formData"
      :propData="propData"
    ></ChildComponent>
  </div>
</template>

<script>
import ChildComponent from "./ChildComponent.vue";
export default {
  name: "ParentComponent",
  components: {
    ChildComponent,
  },
  data() {
    return {
      class1: "color:red",
      data: "我是父组件的属性",
      formData: "我是父组件的表单数据值",
      propData: "我是父组件数据,但是我在子组件中被props接收",
    };
  },
  methods: {
    handleCustomEvent() {
      console.log("父组件手动子组件的自定义事件");
    },
    handleChange() {
      console.log("测试传给子组件方法");
    },
    handleClick() {
      console.log("我只在父组件中使用");
    },
  },
};
</script>
<style>
.parent-component {
  border: 1px solid blue;
}
</style>

子组件

如果在 createdbeforeMount 钩子函数中使用 $attrs$listeners,可能会导致组件的属性和事件未能正确地传递给子组件。因此,我们可以在 mounted 钩子函数中使用 $attrs$listeners,以确保组件的属性和事件能够正确地传递给子组件。

<template>
  <div class="child-component">
    <h3>我是子组件</h3>
    <p>接收到的属性:</p>
    <ul>
      <li v-for="(value, key) in $attrs" :key="key">{{ key }}: {{ value }}</li>
    </ul>
    <p>接收到的事件:</p>
    <ul>
      <li v-for="(value, key) in $listeners" :key="key">
        {{ key }}
      </li>
    </ul>

  </div>
</template>
<script>

export default {
  name: "ChildComponent",
  props: {
    propData: String,
  },
  mounted() {
    console.log("我是子组件,接收父组件的事件如下");
    console.log(this.$listeners); //输出父组件传递的事件监听器
    // console.log("我是子组件,接收父组件的属性如下");
    // console.log(this.$attrs); //输出父组件的属性
  },
};
</script>
<style>
.child-component {
  border: 1px solid green;
  width: 50vw;
  margin: auto;
}
</style>

 效果演示

可以看到$attrs接收的是父组件传递的非props和class属性。

$listeners接收到的是父组件传递的绑定在子组件上的事件。

 代码解释:父组件的属性如果在子组件中通过props接收了,那么数据不会在走$attrs了。并且样式不会通过$attrs传下去。通过事件绑定在子组件的事件都会被子组件监听到。

思考: $attrs$listeners 会默认向下传递吗?

增加一个孙组件,打印一下$attrs和$listeners。看能否拿到祖先组件的属性和事件

<template>
  <div class="child-component">
    <h3>我是孙子组件</h3>
    <p>接收到的属性:</p>
    <ul>
      <li v-for="(value, key) in $attrs" :key="key">{{ key }}: {{ value }}</li>
    </ul>
    <p>接收到的事件:</p>
    <ul>
      <li v-for="(value, key) in $listeners" :key="key">
        {{ key }}
      </li>
    </ul>
  </div>
</template>
<script>
export default {
  name: "ChildChildComponent",
  mounted() {
    console.log("孙子组件接收的事件"); //输出父组件传递的事件监听器
    console.log(this.$listeners); //输出父组件传递的事件监听器
  },
};
</script>
<style>
.child-component {
  border: 1px solid green;
  width: 25vw;
  margin: auto;
}
</style>

 可以看到孙组件中并没有接收到祖先传递的属性和事件

如何将属性和事件透传下去?

只要在子组件中调用子孙组件的地方显示的绑定$attrs和$listeners即可

    <ChildChildComponent
      v-bind="$attrs"
      v-on="$listeners"
    ></ChildChildComponent>

 在公司二次封装公共组件的时候,会频繁使用$attrs和$listeners,这个孙组件就相当与第三方公共组件,比如element-ui或ant-design-vue。这个子组件就相当于你公司自己二次封装一次的组件。父组件就相当于你要写业务组件的地方。那在使用二次封装的组件的时候怎么无感的继续访问使用element-ui的属性和方法呢?

你就把父组件传到二次封装的属性和事件通过透传给传到element-ui就好了。

 vue3示例——$attrs+useAttrs

$listeners 对象在 Vue 3 中已被移除。事件监听器现在是 $attrs 的一部分。在模板中直接通过 $attrs方法文属性。但是如果你想在script里访问透传属性,必须使用useAttrs辅助函数。

 父组件

在父组件定义两个绑定事件,一个非绑定事件。一个class属性,两个非props数据,一个prop数据。看子组件能拿到哪些属性和事件

<template>
  <div class="parent-component">
    <h2>我是父组件</h2>
    <ChildComponent
      @custom-event="handleCustomEvent"
      @change="handleChange"
      :class="class1"
      style="width: 300px"
      :data="data"
      :formData="formData"
      :propData="propData"
    ></ChildComponent>
  </div>
</template>
<script setup>
import { ref } from "vue";
import ChildComponent from "./ChildComponent.vue";
let class1 = ref("color:red");
let data = ref("我是父组件的属性");
let formData = ref("我是父组件的表单数据值");
let propData = ref("我是父组件的数据,但是我在子组件中被props接收");
function handleCustomEvent() {
  console.log("父组件手动子组件的自定义事件");
}
function handleChange() {
  console.log("测试传给子组件方法");
}
function handleClick() {
  console.log("我只在父组件中使用");
}
</script>
<style>
.parent-component {
  border: 1px solid blue;
  width: 100vw;
}
</style>

子组件

在vue3中,属性和事件都通过$attrs拿到。 通过v-bind:$attrs显示绑定子组件获取的属性和孙组件,使得属性和方法得以向下传递。在模板外,script标签里,必须通过useAttrs方法拿到属性或方法。

<template>
  <div class="child-component" v-bind="$attrs">
    <h3>我是子组件</h3>
    <p>接收到的属性和事件</p>
    {{ $parent }}
    <ul>
      <li v-for="(value, key) in $attrs" :key="key">{{ key }}: {{ value }}</li>
    </ul>
    <ChildChildComponent v-bind="$attrs"></ChildChildComponent>
  </div>
</template>
<script setup>
import { useAttrs } from "vue";
import ChildChildComponent from "./ChildChildComponent.vue";

defineProps({
  propData: {
    type: String,
    required: true,
  },
});
defineOptions({
  inheritAttrs: false,
});
const attrs = useAttrs(); //通过useAttrs在脚本里获取属性和方法
console.log("我是子组件,接收父组件的属性和事件如下");
console.log(attrs);
</script>
<style>
.child-component {
  border: 1px solid green;
  width: 50vw;
  margin: auto;
}
</style>

 孙组件

<template>
  <div class="child-component">
    <h3>我是孙子组件</h3>
    <p>接收到的属性和事件</p>
    <ul>
      <li v-for="(value, key) in $attrs" :key="key">{{ key }}: {{ value }}</li>
    </ul>
  </div>
</template>
<script setup>
defineProps({
  propData: {
    type: String,
    required: true,
  },
});
</script>
<style>
.child-component {
  border: 1px solid green;
  width: 50vw;
  margin: auto;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1572801.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Kaggle】练习赛《鲍鱼年龄预测》(上)

前言 上一篇文章&#xff0c;讲解了《肥胖风险的多类别预测》机器学习方面的文章&#xff0c;主要是多分类算法的运用&#xff0c;本文是一个回归的算法&#xff0c;本期是2024年4月份的题目《Regression with an Abalone Dataset》即《鲍鱼年龄预测》&#xff0c;在此分享高手…

Vuex的模块化管理

1&#xff1a;定义一个单独的模块。由于mutation的第二个参数只能提交一个对象&#xff0c;所以这里的ThisLog是个json串。 2&#xff1a;在Vuex中的index.js中引入该模块 3&#xff1a;在别的组件中通过...mapState调用模块保存的State的值。 4&#xff1a;用...mapMutations修…

K8S之Job和CronJob控制器

这里写目录标题 Job概念适用场景使用案例 CronJob概念适用场景使用案例 Job 概念 Job控制器用于管理Pod对象运行一次性任务&#xff0c;例如&#xff1a;对数据库备份&#xff0c;可以直接在k8s上启动一个mysqldump备份程序&#xff0c;也可以启动一个pod&#xff0c;这个pod…

LRU的原理与实现(java)

介绍 LRU的英文全称为Least Recently Used&#xff0c;即最近最少使用。它是一种内存数据淘汰算法&#xff0c;当添加想要添加数据而内存不足时&#xff0c;它会优先将最近一段时间内使用最少的数据淘汰掉&#xff0c;再将数据添加进来。 原理 LRU的原理在介绍中就已经基本说…

C++之类和对象(上)

目录 1.面向过程和面向对象初步认识 2.类的引入 3.类的定义 4.类的访问限定符及封装 4.1访问限定符 4.2 类的两种定义方式 第一种&#xff1a; 第二种&#xff1a; 4.3封装 5.类的实例化 6.类对象模型 1.面向过程和面向对象初步认识 C语言是面向过程的&#xff0c;…

华为汽车的“计算+通信”电子电气架构

文章目录 整车结构 硬件平台 软件平台 总结展望 整车EEA&#xff08;电子电气架构&#xff09;&#xff0c;按照博世提出的演进路径&#xff0c;大致可以划分为四个阶段&#xff1a;分布式模块阶段、区域控制阶段、中央计算阶段、云计算阶段。示例如下&#xff1a; 本文选取…

Java8 进阶

Java8 进阶 文章目录 Java8 进阶什么是函数式接口&#xff1f;public interface Supplierpublic interface Consumerpublic interface Predicatepublic interface FunctionJava8 特性总结&#xff1a;一、Function<T, R>二、Consumer<T>三、Supplier<T>四、P…

BUUCTF:BUU UPLOAD COURSE 1[WriteUP]

构造一句话PHP木马 <?php eval(system($_POST[shell])); ?> 利用eval函数解析$shell的值使得服务器执行system命令 eval函数是无法直接执行命令的&#xff0c;只能把字符串当作php代码解析 这里我们构造的木马是POST的方式上传&#xff0c;那就用MaxHacKBar来执行 …

分布式锁实战

4、分布式锁 4.1 、基本原理和实现方式对比 分布式锁&#xff1a;满足分布式系统或集群模式下多进程可见并且互斥的锁。 分布式锁的核心思想就是让大家都使用同一把锁&#xff0c;只要大家使用的是同一把锁&#xff0c;那么我们就能锁住线程&#xff0c;不让线程进行&#x…

springBoot--阿里云短信验证

阿里云短信验证 前言阿里云短信服务免费领取100条短信服务1、开通短信服务2、申请签名3、申请模板4、通过子用户获取账号的AccessKey ID 和AccessKey Secret5、使用教程 前言 在我们平时登录中短信验证吗验证在当今是必不可少的&#xff0c;下面是基于阿里云开发的短信验证操作…

【Qt 学习笔记】详解Qt中的信号和槽

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 详解Qt中的信号与槽 文章编号&#xff1a;Qt 学习笔记 / 12 文章目录…

【数据结构】ArrayList详解

目录 前言 1. 线性表 2. 顺序表 3. ArrayList的介绍和使用 3.1 语法格式 3.2 添加元素 3.3 删除元素 3.4 截取部分arrayList 3.5 其他方法 4. ArrayList的遍历 5.ArrayList的扩容机制 6. ArrayList的优缺点 结语 前言 在集合框架中&#xff0c;ArrayList就是一个…

代码随想录第19天

654. 最大二叉树 已解答 中等 相关标签 相关企业 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。递归地在最大值 左边 的 子数组前缀上 构建左子树。递归地在最大值 右边 的 子数组后缀…

Mac 配置 Aria2

文章目录 1. Aria2 安装1.1 安装 brew1.2 安装 Aria2 2. 配置 Aria22.1 创建配置文件 aria2.conf 和空对话文件 aria2.session2.2 编辑配置文件 aria2.conf 3. 开机启动设置3.1 创建用户启动文件3.2 管理自启动项 4. 配置 BT tracker 自动更新4.1 XIU2/TrackersListCollection …

通义灵码-ai编码

https://developer.aliyun.com/topic/lingma/activities/202403?taskCode14508&recordIdb1ef3ba27250a5818b1b6ffe418af658#/?utm_contentm_fission_1 「通义灵码 体验 AI 编码&#xff0c;开 AI 盲盒」

sourcetree提交代码出现闪退报错(已解决)

当我在sourcetree提交代码时&#xff0c;点击提交按钮出现闪退关闭&#xff0c;并弹出下面的报错框&#xff0c;报错的图片如下&#xff1a; 那么经过了解&#xff0c;出现这样的报错原因是&#xff0c;git的提交时无法定位提交的人是谁&#xff0c;导致无法提交 那么解决的方…

Allavsoft for Mac v3.27.0.8852注册激活版 优秀的视频下载工具

Allavsoft for Mac是一款功能强大的多媒体下载和转换工具&#xff0c;支持从各种在线视频网站和流媒体服务下载视频、音频和图片。它具备批量下载和转换功能&#xff0c;可将文件转换为多种格式&#xff0c;以适应不同设备的播放需求。此外&#xff0c;Allavsoft还提供视频编辑…

ARM v8 Cortex R52内核 02 程序模型 Programmers Model

ARM v8 Cortex R52内核 02 程序模型 Programmers Model 2.1 关于程序模型 Cortex-R52处理器实现了Armv8-R架构。这包括&#xff1a; 所有的异常级别&#xff0c;EL0-EL2。 每个异常级别下的AArch32执行状态。 T32和A32指令集&#xff0c;其中包括&#xff1a; 浮点运算。 …

电子商务平台中大数据的应用|主流电商平台大数据采集API接口

(一)电商平台物流管理中大数据的应用 电商平台订单详情订单列表物流信息API接口应用 电子商务企业对射频识别设备、条形码扫描设备、全球定位系统及销售网站、交通、库存等管理软件数据进行实时或近实时的分析研究,提高物流速度和准确性。部分电商平台已建立高效的物流配送网…

Ruoyi-vue-pro Vue + nginx 二级目录部署到云服务器

http://www.your-server.com/ 这是一级目录&#xff0c;由于项目多&#xff0c;一般会通过二级域名http://oa.your-server.com/或二级目录http://www.your-server.com/oa来发布&#xff0c;本篇记录一下二级目录发布。先看效果 1、router/index.js配置base export default new …