美文网首页
$attrs 和 $listeners

$attrs 和 $listeners

作者: Cherry丶小丸子 | 来源:发表于2024-03-09 22:57 被阅读0次

通常情况下,父子组件之间的数据是通过 props 由父向子传递的,当子组件想要修改数据时,则需要通过 $emit 以事件形式交由父组件完成,而这种交互方式只存在于父子组件之间,多层嵌套的时候,处于内层的组件想要获取外层的数据时,需要外层组件一层一层地将数据向下传递;同理,当内层组件想要修改数据时,也需要将事件一层一层向上传递。

当外层组件向最终接收组件传递数据时,中间经过的每个组件都需要定义 props 去接收并向下传递,这种做法肯定是不太合理的,不仅代码冗余了,而且对于中间不需要数据的组件来说,定义自身不需要的 props 也是一种污染;同理,将事件一层一层向上传递也是不太合理的。

我们都知道,任何单页应用中的组件间都不可能只有简单的父子关系,如果有,说明这个应用并不需要做成单页应用。

那么如何才能减少(或避免)这种情况的发生呢?Vue 中提供了 $attrs 和 $listeners。

$attrs

包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。

简单的话翻译:接收所有给组件传的值(class,style 和 props 声名的属性除外)

$listeners

包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。

简单的话翻译:接收除了带有 .native 事件修饰符的所有事件监听器,即原生的事件是不包含在内的

$attrs 与 $listeners 怎么用

父组件 parent.vue
<template>
    <son :sentence="sentence" @customClick="handleClick"></son>
</template>
<script>
import son from "./son";
export default {
    components: {
        son
    },
    data() {
        return {
            sentence: "this is a sentence"
        };
    },
    methods: {
        handleClick(e) {
            console.log(e);
        }
    }
};
</script>

在 `data` 中定义一个变量 `sentence`,值为 `this is a sentence`。

引入子组件 `son`,将 `sentence` 传入,同时绑定自定义事件 `customClick`,在回调函数中将自定义事件的参数打印出来。
子组件 son.vue
<template>
    <div>
        I am son
        <p>$attrs in son {{ $attrs }}</p>
        <grandson v-bind="$attrs" v-on="$listeners"></grandson>
    </div>
</template>
<script>
import grandson from "./grandson";
export default {
    name: "son",
    components: {
        grandson
    },
    data() {
        return {};
    },
    methods: {}
};
</script>

引入孙组件 grandson,使用 v-bind="$attrs" 和 v-on="$listeners" 向下传递数据和事件监听器。

在页面上绑定 $attrs,用于显示效果。
孙组件 grandson.vue
<template>
    <div>
        I am grandson
        <p @click="handleClick">$attrs in grandson {{ $attrs }}</p>
        <greatGrandson v-bind="$attrs" v-on="$listeners"></greatGrandson>
    </div>
</template>

<script>
import greatGrandson from "./great-grandson";
export default {
    name: "grandson",
    components: {
        greatGrandson
    },
    methods: {
        handleClick() {
            this.$emit("customClick", "clicked grandson");
        }
    }
};
</script>

首先还是为组件添加自定义点击事件,取名 `customClick`,参数为一句话 `clicked grandson`,用以区分,并在点击时触发这个事件。

接着引入曾孙组件 `great-grandson`,使用 `v-bind="$attrs"` 和 `v-on="$listeners"` 向下传递数据和事件监听器。

在页面上绑定 $attrs,用于显示效果。
曾孙组件 great-grandson.vue
<template>
    <div @click="handleClick">$attrs in great grandson {{ $attrs }}</div>
</template>

<script>
export default {
    name: "great-grandson",
    methods: {
        handleClick() {
            this.$emit("customClick", "clicked great grandson");
        }
    }
};
</script>

添加自定义点击事件并在点击时触发这个事件,取名 customClick,参数为一句话 clicked great grandson。

在页面上绑定 $attrs,用于显示效果。

运行示例,打开浏览器,页面上的内容将会是下面的样子:

image.png

在组件 son、grandson 和 great-grandson 中都显示了 this is a sentence,而子组件 son 和孙组件 grandson 中都没有定义 props,说明 parent 组件中的数据正确的传递到了内部组件中。

打开控制台,分别点击组件 grandson 和 great-grandson 中 $attrs 所在的句子,可以看到事件也是生效的:


image.png

这就是 $attrs$listeners 的功能,去掉数据和事件在多层嵌套组件中传递时的定义部分。注意,仅仅是定义部分,绑定的步骤还是少不了的,即经过的每一层组件都需要使用 v-bind="$attrs"v-on="$listeners"

另外,这两个属性都是 只读 的,不要试图通过 $attrs 去直接修改原数据。

第二个案例
// 父组件,向子组件传递数据和定义自定义事件

<template>
    <div>
        <hintButton icon="el-icon-plus" size="mini" type="success" title="翻滚的露西" @click="handler"></hintButton>
    </div>
</template>
 
<script>
import hintButton from '@/components/hintButton.vue'
export default {
    name: 'app',
    components: {
        hintButton
    },
    methods: {
        handler() {
            alert('露西666')
        }
    }
}
</script>
// 子组件
// 通过 v-bind='$attrs' 接收父组件传递的数据
// 通过 v-on='$listeners' 可以获取到父组件给子组件传递自定义事件

<template>
    <div>
        <a :title="title">
            <el-button v-bind="$attrs" v-on="$listeners"></el-button>
        </a>
    </div>
</template>
 
<script>
export default {
    name: 'hintButton',
    props: ['title'],
    mounted() {
        console.log('this.$attrs', this.$attrs)
        console.log('this.$listeners', this.$listeners)
    }
}
</script>
this.$attrs 和 this.$listeners 的打印结果

相关文章

  • Attrs 和 Listeners

    这两个属性是 vue 2.4 版本之后提供的,它简直是二次封装组件或者说写高阶组件的神器。在我们平时写业务的时候免...

  • $attrs和$listeners

    $attrs 属于组件的一个属性,可以获取到父组件传递过来的props数据对于子组件而言,父组件给的数据可以利用p...

  • $listeners /$attrs

    使用方法概括: $attrs 是 父组件绑定给子组件的属性(prop里声明的除外) $listeners 是父...

  • Vue2.4 $attrs、$listeners、inherit

    在开始介绍之前先看下vue官方文档对 $attrs和 $listeners的解释: vm.$attrs包含了父作用...

  • 在Vue中使用JSX踩坑指南

    1.组件使用$attrs和$listeners传递参数时: 发现v-bind和v-on都不好用了,因为$attrs...

  • vue组件通信的几种方式

    1、props 2、$.emit $.on 3、$attrs, $listeners 4、provide / in...

  • $attrs和$listeners的使用

    vue中使v-bind="attrs",将父组件中不被认为props特性绑定的属性(即在父组件中或者说时中间组件中...

  • $attrs, $listeners, inheritAttrs

    2018-06-15创建 组价通信 vue中一个比较令人烦恼的事情是属性只能从父组件传递给子组件。这也就意味着当你...

  • $attrs 与 $listeners

    本文转自[https://juejin.cn/user/2858385961407853] 学会使用listene...

  • vue $attrs, $listeners

    vm.$attrs 包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style...

网友评论

      本文标题:$attrs 和 $listeners

      本文链接:https://www.haomeiwen.com/subject/cnyvidtx.html