记录下vue的$attrs和$listeners

本文详细介绍了Vue.js中$attrs和$listeners的作用及应用方式,$attrs用于传递非props属性,而$listeners则负责传递事件监听器。通过实例展示了如何利用这两个特性在多级组件间传递数据与事件。

$attrs

官网上的类型是{ [key: string]: string },但是我试了下,如果传递是的是个对象也是可以接受到的。所以我认为这个value应该为 any 类型

  • 类型:{ [key: string]: any } //{ [key: string]: string }
  • 只读
  • 详细
    • 包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。
    • 简单来说就是 $attrs 可以获取其父组件接收到的所有除了当前组件 props 里面接受了的props字段 和 class/style 之外的字段

例子:

  • 目录结构
    在这里插入图片描述

这个时候如果 grandson 组件需要获取到 从 app.vue 传递过来的参数,可以使用 $attrs

  1. 首先在需要向需要接受 $attrs 的组件传递 $attrs 参数(因为是在 children 中引入的 grandson组件,所以在 children组件中给grandson传递参数即可)
<template>
    <div class="children">
        <div>这是子组件</div>
        <grandson v-bind="$attrs"></grandson>
    </div>
</template>

<script>
import grandson from './grandson.vue'
export default {
    name: 'children',
    components: { grandson }
}
</script>
  1. 在 grandson 中直接使用即可,不需要接受,如果在引入 grandson 组件的时候未绑定,则 $attrs 的值默认为 {}
<template>
    <div class="grandson">
        <pre>{{ $attrs }}</pre>
    </div>
</template>

<script>
export default {
    name: 'grandson',
    // 这里接受传递过来的参数 prop
    props: ['prop']
}
</script>
  1. 在祖先组件(app.vue)中传递参数
<template>
  <div id="app">
    <children :text="{a: 1}" :params="2" :prop="3"></children>
  </div>
</template>

<script>
import children from './components/children'
export default {
  name: 'App',
  components: {children}
}
</script>

<style lang="less">
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
  .children {
    width: 200px;
    height: 250px;
    border: 1px solid #ccc;
    .grandson {
      width: 150px;
      height: 180px;
      border: 1px solid #ccc;
    }
  }
}
</style>

  1. 运行项目,结果:
    在这里插入图片描述

得出结论:可以通过 $attrs 在组件中传递参数给 子孙组件,子孙组件可以通过 $attrs 获取传递给父组件下的子组件的所有非props接受的参数
注意:如果是隔代传递,无法接受。比如:给当前组件新增一个层级,parent 组件。将 parent 组件作为 children 组件的父组件。app 作为 parent 的父组件。如果在 app 中给 parent 传递参数。这个时候 grandson 是无法接受到的

可以看到传递给 $attrs的参数是 { [key: string]: any }。。。。。

$listeners

  • 类型 { [key: string]: Function | Array< Function > }
  • 只读
  • 详细
    • 包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。
    • 简单来说就是这玩意可以向祖先组件 emit 没有带 .native 修饰符的 事件

同一个目录,文件不做修改
例子:

  1. 还是在 children 组件中给 grandson 组件增加 $listeners 绑定
......
<!-- 给 grandson 组件新增 v-on="$listeners" -->
<grandson v-bind="$attrs" v-on="$listeners"></grandson>
......
  1. 修改 grandson 组件
<template>
    <div class="grandson">
        <pre>{{$attrs}}</pre>
        <div @click="$emit('grandsonEvent', 'grandson组件被点击')">按钮1</div>
        <div @click="$emit('grandsonEventNative', '带有.native修饰符事件触发')">按钮2</div>
    </div>
</template>
......
  1. 在app.vue中接收
<template>
  <div id="app">
    <children :text="{a: 1}" :params="2" :prop="3" @grandsonEvent="grandsonEvent" @grandsonEventNative.native="grandsonEventNative"></children>
  </div>
</template>

<script>
import children from './components/children'
export default {
  name: 'App',
  components: {children},
  methods: {
  	// 接受来自 grandson 组件传递过来的方法。没有加 .navtive修饰符
    grandsonEvent (params) {
      alert(params)
    },
    // 接受来自 grandson 组件传递过来的方法。加了 .navtive修饰符
    grandsonEventNative (params) {
      alert(params)
    }
  }
}
</script>
......
  1. 运行结果
    • 点击 按钮1,运行结果:
      在这里插入图片描述
    • 点击 按钮2,页面无反应。增加了 .navtive 修饰符的不会接收到来自非子组件的事件

所以 $listeners 就是用来 孙组件给 组件组件 emit 事件用的?。。。

如果设置了 $attrs 父组件某个参数,祖先组件也传递一样的参数,那么孙组件接受到的是谁的参数?

  1. 照原来的例子,对 children 做修改,给 grandson 传递 text 参数
......
<grandson v-bind="$attrs" v-on="$listeners" :text="0"></grandson>
......
  1. 运行项目,看效果
    在这里插入图片描述
    _ 从app.vue组件传递过来的参数被 children 组件覆盖了_
    也就是说 $attrs 接收的时候 是先接受到祖先组件的参数,然后接收父组件的参数,这个时候父组件的参数会覆盖祖先组件的值

  2. $listeners 一样。。

### Vue2与Vue3中 `$attrs` `$listeners` 的区别 #### 1. **Vue2中的 `$attrs` `$listeners`** 在 Vue2 中,`$attrs` 是指父组件传递下来的所有属性包括 `class`、`style` 已经被声明为 `props` 的属性)。这些属性可以通过 `v-bind="$attrs"` 转递给子组件[^5]。 另一方面,`$listeners` 则是一个对象,包含了当前作用域内的所有事件监听器。开发者可以使用 `v-on="$listeners"` 将这些事件转发给子组件[^5]。 需要注意的是,在 Vue2 中,如果希望阻止某些属性或事件被自动继承到根元素,则需要设置 `inheritAttrs: false`[^4]。 #### 2. **Vue3中的 `$attrs` 变化** 到了 Vue3,设计发生了显著变化。`$listeners` 已经被废弃,其功能完全融入了 `$attrs` 对象之中。这意味着 `$attrs` 仅包含未声明的属性,还涵盖了所有的事件监听器[^2]。因此,在 Vue3 中再需要单独处理 `$listeners`,而是统一通过 `v-bind="$attrs"` 同时绑定属性事件监听器。 此外,由于 `$listeners` 的移除,Vue3 提供了一种更简洁的方式来管理事件属性的传播[^1]。 --- ### Vue3虚拟DOM静态标记的时机 在 Vue3 中,当生成虚拟 DOM 节点时,会对其进行优化分析。对于那些会动态更新的部分(即所谓的“静态节点”),框架会在初始化阶段打上特定标志位以便后续跳过必要的比较操作[^1]。这种机制有助于提升渲染性能,尤其是在复杂场景下能够减少大量无意义的工作量。 具体来说,静态标记发生在以下几个时刻: - 当解析模板字符串构建 AST 抽象语法树期间; - 或者是在手动创建 VNode 实例过程中由内部逻辑完成此判断过程。 这一改进使得即使面对大规模应用也能保持较高的运行效率。 --- ### 示例代码对比 以下是基于上述理论的一个简单实现案例: #### Vue2 版本 ```html <!-- ParentComponent.vue --> <template> <ChildComponent foo="bar" @custom-event="handleCustomEvent"></ChildComponent> </template> <script> export default { methods: { handleCustomEvent() { console.log('Custom event triggered!'); } } }; </script> <!-- ChildComponent.vue --> <template> <div> <!-- Props and events are passed down manually --> <GrandchildComponent v-bind="$attrs" v-on="$listeners"></GrandchildComponent> </div> </template> <script> export default { inheritAttrs: false, }; </script> ``` #### Vue3 版本 ```html <!-- ParentComponent.vue --> <template> <ChildComponent foo="bar" @custom-event="handleCustomEvent"></ChildComponent> </template> <script> import { defineComponent } from 'vue'; export default defineComponent({ setup() { const handleCustomEvent = () => { console.log('Custom event triggered!'); }; return { handleCustomEvent }; }, }); </script> <!-- ChildComponent.vue --> <template> <div> <!-- Both attributes and listeners are forwarded using $attrs --> <GrandchildComponent v-bind="$attrs"></GrandchildComponent> </div> </template> <script> export default { inheritAttrs: false, }; </script> ``` --- ### 总结 综上所述,Vue3 对于 `$attrs` `$listeners` 的整合简化了开发流程,并提高了 API 的一致性;与此同时,通过对虚拟 DOM 进行静态标记进一步增强了框架的整体表现力。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值