如何“透传属性和事件”

父组件在使用子组件的时候,如何“透传属性和事件”给子组件呢?

  • 透传属性和事件并没有在子组件中用propsemits声明
  • 透传属性和事件最常见的如@clickclassidstyle 
  • 当子组件只有一个根元素时,透传属性和事件会自动添加到该根元素上;如果根元素已有classstyle属性,它会自动合并                       

组合式API测试 :

        父组件App.vue

<script setup>
import ChipVue from './components/Chip.vue';

function say() {
    alert('Hello')
}
</script>

<template>
    <!-- 透传的属性(style,class,title)在子组件中并没有在 props 声明 -->
    <!-- 透传的事件(click)在子组件中并没有在 emits 声明 -->
    <ChipVue
        class="rounded"
        style="border: 1px solid blue;"
        title="纸片"
        @click="say"
    />
</template>

         子组件 Chip.vue

<template>
    <!-- 
        当子组件只有一个根元素时,透传属性和事件会自动添加到该根元素上
        如果根元素已有 class 或 style 属性,它会自动合并
     -->
    <button class="chip" style="box-shadow: 0 0 8px grey;">
        普通纸片
    </button>
</template>

<style>
.chip {
    border: none;
    background-color: rgb(231, 231, 231);
    padding: 8px 15px;
}

.rounded {
    border-radius: 100px;
}
</style>

         渲染结果:

 如何禁止“透传属性和事件”     

  • 当子组件只有一个根元素时,透传属性和事件会自动添加到该根元素上,那怎么阻止呢?
  • 在选项式 API 中,你可以在组件选项中设置inheritAttrs: false来阻止;
  • 在组合式 API 的<script setup>中,你需要一个额外的<script>块来书写inheritAttrs: false选项声明来禁止

组合式API测试 :

        父组件App.vue

<script setup>
import ChipVue from './components/Chip.vue';

function say() {
    alert('Hello')
}
</script>

<template>
    <!-- 透传的属性(style,class,title)在子组件中并没有在 props 声明 -->
    <!-- 透传的事件(click)在子组件中并没有在 emits 声明 -->
    <ChipVue
        class="rounded"
        style="border: 1px solid blue;"
        title="纸片"
        @click="say"
    />
</template>

         子组件 Chip.vue

<script>
export default {
    inheritAttrs: false // 阻止自动透传给唯一的根组件
}
</script>

<!-- 
    在组合式 API 的 <script setup> 中,
    你需要一个额外的 <script> 块来书写 inheritAttrs: false 选项声明来禁止 
-->
<script setup></script>

<template>
    <!-- 
        当子组件只有一个根元素时,透传属性和事件会自动添加到该根元素上
        如果根元素已有 class 或 style 属性,它会自动合并
     -->
    <button class="chip" style="box-shadow: 0 0 8px grey;">
        普通纸片
    </button>
</template>

<style>
.chip {
    border: none;
    background-color: rgb(231, 231, 231);
    padding: 8px 15px;
}

.rounded {
    border-radius: 100px;
}
</style>

多根元素的“透传属性和事件” 

        多根节点的组件并没有自动“透传属性和事件”的行为,由于Vue不确定要将“透传属性和事件”透传到哪里,所以我们需要v-bind="$attrs"来显式绑定,否则将会抛出一个运行时警告。

        组合式API测试:

                父组件App.vue

<script setup>
import ChipVue from './components/Chip.vue';

function say() {
    alert('Hello')
}
</script>

<template>
    <!-- 透传的属性(style,class,title)在子组件中并没有在 props 声明 -->
    <!-- 透传的事件(click)在子组件中并没有在 emits 声明 -->
    <ChipVue
        class="rounded"
        style="border: 1px solid blue;"
        title="纸片"
        @click="say"
    />
</template>

        子组件Chip.vue

<template>
    <!-- 多根节点的组件并没有自动“透传属性和事件”的行为 -->

    <button class="chip">
        普通纸片
    </button>

    <hr>

    <button class="chip" v-bind="$attrs">
        普通纸片
    </button>

    <hr>

    <button class="chip" v-bind="$attrs">
        普通纸片
    </button>
</template>

<style>
.chip {
    border: none;
    background-color: rgb(231, 231, 231);
    padding: 8px 15px;
}

.rounded {
    border-radius: 100px;
}
</style>

访问“透传属性和事件”   

  • 在选项式 API 中,我们可通过this.$attrs来访问“透传属性和事件”
  • 在组合式 API 中的<script setup>中引入useAttrs()来访问一个组件的“透传属性和事件”

        组合式API测试:

                父组件App.vue

<script setup>
import ChipVue from './components/Chip.vue';

function say() {
    alert('Hello')
}
</script>

<template>
    <!-- 透传的属性(style,class,title)在子组件中并没有在 props 声明 -->
    <!-- 透传的事件(click)在子组件中并没有在 emits 声明 -->
    <ChipVue
        class="rounded"
        style="border: 1px solid blue;"
        title="纸片"
        @click="say"
    />
</template>

        子组件Chip.vue

<script setup>
import { useAttrs } from 'vue';

// 透传的属性和事件对象
let attrs = useAttrs()

 // 在 JS 中访问透传的属性和事件
function showAttrs() {
    console.log(attrs)
    console.log(attrs.class)
    console.log(attrs.title)
    console.log(attrs.style)
    attrs.onClick()
}
</script>

<template>
    <button class="chip" v-bind="attrs">
        普通纸片
    </button>

    <hr>

    <h6>{{ attrs }}</h6>

    <ul>
        <li>{{ attrs.title }}</li>
        <li>{{ attrs.class }}</li>
        <li>{{ attrs.style }}</li>
    </ul>

    <button @click="attrs.onClick()">执行透传的事件</button>

    <hr>

    <button @click="showAttrs">在 JS 中访问透传的属性和事件</button>
</template>

<style>
.chip {
    border: none;
    background-color: rgb(231, 231, 231);
    padding: 8px 15px;
    margin: 10px;
}

.rounded {
    border-radius: 100px;
}
</style>

注意:

  • 虽然这里的attrs对象总是反映为最新的“透传属性和事件”,但它并不是响应式的 (考虑到性能因素),你不能通过侦听器去监听它的变化
  • 如果你需要响应性,可以使用prop或者你也可以使用onUpdated()使得在每次更新时结合最新的attrs执行副作用

 

Logo

前往低代码交流专区

更多推荐