$attrs 和 $listeners (vue2vue3)

目录

透传 Attributes

Attributes 继承​

对 class 和 style 的合并

v-on 监听器继承

深层组件继承 

禁用 Attributes 继承 

多根节点的 Attributes 继承 

vue2 $attrs 和 $listeners 

$attrs 概念说明

$attrs 案例

$listeners 概念说明

$listeners案例

 vue3 $attrs 和 $listeners 

 attrs在 template 中的用法

只有1个根元素的情况下

有2个根元素的情况下

$listeners  弃用

 attrs在 js 中的用法

Options API

Composition API 3.0的语法 

Composition API 3.2的语法 

总结

移除 $listeners 

概览

2.x 语法

3.x 语法

$attrs 包含 class & style 

概览

2.x 行为 

3.x 行为


(1)$props:当前组件接收到的 props 对象。Vue 实例代理了对其 props 对象属性的访问。

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

(3)$listeners:包含了父作用域中(不含 .native 修饰器的)v-on事件监听器。他可以通过 v-on="listeners"传入内部组件

透传 Attributes

透传 Attributes 是指由父组件传入,且没有被子组件声明为 props 或是组件自定义事件的 attributes 和事件处理函数。

Attributes 继承​

“透传 attribute”指的是传递给一个组件,却没有被该组件声明为 props 或 emits 的 attribute 或者 v-on 事件监听器。最常见的例子就是 classstyle 和 id

当一个组件以单个元素为根作渲染时,透传的 attribute 会自动被添加到根元素上。举例来说,假如我们有一个 <MyButton> 组件,它的模板长这样:

<!-- <MyButton> 的模板 -->
<button>click me</button>

一个父组件使用了这个组件,并且传入了 class

<MyButton class="large" />

最后渲染出的 DOM 结果是:

<button class="large">click me</button>

 这里,<MyButton> 并没有将 class 声明为一个它所接受的 prop,所以 class 被视作透传 attribute,自动透传到了 <MyButton> 的根元素上。

对 class 和 style 的合并

如果一个子组件的根元素已经有了 class 或 style attribute,它会和从父组件上继承的值合并。如果我们将之前的 <MyButton> 组件的模板改成这样:

<!-- <MyButton> 的模板 -->
<button class="btn">click me</button>

 则最后渲染出的 DOM 结果会变成:

<button class="btn large">click me</button>

v-on 监听器继承

同样的规则也适用于 v-on 事件监听器

<MyButton @click="onClick" />

click 监听器会被添加到 <MyButton> 的根元素,即那个原生的 <button> 元素之上。当原生的 <button> 被点击,会触发父组件的 onClick 方法。同样的,如果原生 button 元素自身也通过 v-on 绑定了一个事件监听器,则这个监听器和从父组件继承的监听器都会被触发。

深层组件继承 

有些情况下一个组件会在根节点上渲染另一个组件。例如,我们重构一下 <MyButton>,让它在根节点上渲染 <BaseButton>

<!-- <MyButton/> 的模板,只是渲染另一个组件 -->
<BaseButton />

此时 <MyButton> 接收的透传 attribute 会直接继续传给 <BaseButton>

请注意:

  1. 透传的 attribute 不会包含 <MyButton> 上声明过的 props 或是针对 emits 声明事件的 v-on 侦听函数,换句话说,声明过的 props 和侦听函数被 <MyButton>“消费”了。

  2. 透传的 attribute 若符合声明,也可以作为 props 传入 <BaseButton>

禁用 Attributes 继承 

如果你不想要一个组件自动地继承 attribute,你可以在组件选项中设置 inheritAttrs: false

最常见的需要禁用 attribute 继承的场景就是 attribute 需要应用在根节点以外的其他元素上。通过设置 inheritAttrs 选项为 false,你可以完全控制透传进来的 attribute 被如何使用。

vue2 

Vue 2 的虚拟 DOM 实现对 class 和 style attribute 有一些特殊处理。因此,与其它所有 attribute 不一样,它们没有被包含在 $attrs 中。

上述行为在使用 inheritAttrs: false 时会产生副作用:

  • $attrs 中的 attribute 将不再被自动添加到根元素中,而是由开发者决定在哪添加。
  • 但是 class 和 style 不属于 $attrs,它们仍然会被应用到组件的根元素中:
<template><label><input type="text" v-bind="$attrs" /></label>
</template>
<script>
export default {inheritAttrs: false
}
</script>

vue3

从 3.3 开始你也可以直接在 <script setup> 中使用 defineOptions:

<script setup>
defineOptions({inheritAttrs: false
})
// ...setup 逻辑
</script>

这些透传进来的 attribute 可以在模板的表达式中直接用 $attrs 访问到。

<span>Fallthrough attribute: {{ $attrs }}</span>

这个 $attrs 对象包含了除组件所声明的 props 和 emits 之外的所有其他 attribute,例如 classstylev-on 监听器等等。

有几点需要注意:

  • 和 props 有所不同,透传 attributes 在 JavaScript 中保留了它们原始的大小写,所以像 foo-bar 这样的一个 attribute 需要通过 $attrs['foo-bar'] 来访问。

  • 像 @click 这样的一个 v-on 事件监听器将在此对象下被暴露为一个函数 $attrs.onClick

多根节点的 Attributes 继承 

和单根节点组件有所不同,有着多个根节点的组件没有自动 attribute 透传行为。如果 $attrs 没有被显式绑定,将会抛出一个运行时警告。

<CustomLayout id="custom-layout" @click="changeValue" />

如果 <CustomLayout> 有下面这样的多根节点模板,由于 Vue 不知道要将 attribute 透传到哪里,所以会抛出一个警告。

<header>...</header>
<main>...</main>
<footer>...</footer>

如果 $attrs 被显式绑定,则不会有警告:

<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>

vue2 $attrs 和 $listeners 

$attrs 概念说明

  • 包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)
  • $attrs 包含了传递给一个组件的 attribute 名和 attribute 值;即一个JSON对象
  • 可以通过v-bind="$attrs"传入内部组件


$attrs 案例

父组件

<template><SlotContainerref="slotContainer"name="huangbiao":isOk="false":option="{ a: 1, b: true, c: 'ddd' }"></SlotContainer>
</template><script>
import SlotContainer from "./SlotContainer"export default {data() {return {};},components: {SlotContainer,}
};
</script><style lang="scss" scoped></style>

子组件

<script>
export default {data() {return {};},props: {option: {type: Object,default: function() {return {};}}},mounted() {console.log(this.$attrs);},methods: {}
};
</script>

结果

不注释掉子组件的props, $attrs的值

注释掉子组件的props, $attrs的值

inheritAttrs: false 和 $attrs ;配合使用解决的问题? 

  1. 可以手动决定这些 attribute 会被赋予哪个元素
  2. inheritAttrs: false 选项不会影响 style 和 class 的绑定
  3. 这个模式允许你在使用基础组件的时候更像是使用原始的 HTML 元素,而不会担心哪个元素是真正的根元素

$listeners 概念说明

  • 包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器
  • 可以配合 v-on="$listeners" 将所有的事件监听器指向这个组件的某个特定的子元素
  • 它是一个对象,里面包含了作用在这个组件上的所有监听器。

$listeners案例

<template><div class><SlotContainerref="slotContainer"v-on:m1="m1"v-on:m2="m2"@m3="m3"@m4="m4"@click.native="testJiami"></SlotContainer></div>
</template><script>
import SlotContainer from "./SlotContainer";
import CryptoJS from "crypto-js";
export default {data() {return {};},components: {SlotContainer,},methods: {testJiami() {this.m1();this.m2();this.m3();this.m4();},m1() {console.log("加密结果一 MD5:" + CryptoJS.MD5("你好"));// 加盐 对应的APIconsole.log("加密结果一 MD5:" + CryptoJS.HmacMD5("你好", "salt"));console.log(CryptoJS.SHA256("123456").toString());// 加盐 对应的APIconsole.log(CryptoJS.HmacSHA256("123456", "salt").toString());},m2() {var pwd = "passwor";console.log("加密结果二 Hmac-MD5: " + CryptoJS.HmacMD5("你好", pwd));},m3() {var salt = CryptoJS.enc.Utf8.parse("salt"); //盐var iter = 1000; //迭代次数var mi = CryptoJS.PBKDF2("你好", salt, {keySize: parseInt(4),iterations: parseInt(iter),});console.log("加密结果三:" + mi);},m4() {var pswd = "我的密码";var mi = CryptoJS.AES.encrypt("你好", pswd);console.log("加密结果四" + mi);//解密var result = CryptoJS.AES.decrypt(mi, pswd).toString(CryptoJS.enc.Utf8);console.log("解密结果:" + result);},},
};
</script><style lang="scss" scoped></style>

子组件(SlotContainer.vue)

<script>
export default {data() {return {};},mounted() {console.log(this.$listeners);},methods: {}
};
</script><style lang="scss" scoped></style>

结果

@click.native="testJiami"的方法没有在 $listeners中

 vue3 $attrs 和 $listeners 

简单来说, attrs 主要接收没在 props 里定义,但父组件又传过来的属性。

<!-- 父组件 ParentCom.vue -->
<template><ChildCommsg="雷猴"data="123"/>
</template><script setup>
import ChildCom from './ChildCom.vue'
</script><!-- 子组件 ChildCom.vue -->
<template><div>{{ msg }} - {{ $attrs }}</div>
</template><script setup>
defineProps({msg: {type: String}
})
</script>

可以看到,在子组件中,msg 使用了 props 接收,所以 {{ msg }} 可以直接输出 props 里接收的内容。

而没在 props 里接收的内容,全部都放到了 $attrs 里,并且存在一个对象里面。

接下来将展开讲解不同情况下 attrs 的使用方法。

 attrs在 template 中的用法

在前面简单的例子里其实已经大概知道 attrs 在 template 的用法。但 Vue3 中 template 不再要求只有一个根元素了。所以 attrs 在 template 中分2种情况使用。

只有1个根元素的情况下

只有1个根元素的情况下,子组件中,没被 props 接收的属性,都会绑定在根元素上。

<!-- 父组件 ParentCom.vue -->
<template><ChildCommsg="雷猴"data="123"name="鲨鱼辣椒"style="color: red;"/>
</template><script setup>
import ChildCom from './ChildCom.vue'
</script><!-- 子组件 ChildCom.vue -->
<template><div>{{ msg }}</div>
</template><script setup>
defineProps({msg: {type: String}
})
</script>          

可以看到,没被 props 接收的属性都被绑定到根元素上了。

连 style 里传入的样式也被执行,文字变成红色了。

有2个根元素的情况下

当子组件有2个根元素时,没被 props 接收的属性不会绑定到子组件的元素上。

<!-- 父组件 ParentCom.vue -->
<template><ChildCommsg="雷猴"data="123"name="鲨鱼辣椒"style="color: red;"/>
</template><script setup>
import ChildCom from './ChildCom.vue'
</script><!-- 子组件 ChildCom.vue -->
<template><div>{{ msg }}</div><div>{{ msg }}</div>
</template><script setup>
defineProps({msg: {type: String}
})
</script>

 

此时连父组件传入是 style 样式都不生效了。

如果我们此时希望第二个元素绑定所有没被 props 接收的属性,可以使用 v-bind="$attrs" 的方法实现

<!-- 父组件 ParentCom.vue -->
<template><ChildCommsg="雷猴"data="123"name="鲨鱼辣椒"style="color: red;"/>
</template><script setup>
import ChildCom from './ChildCom.vue'
</script><!-- 子组件 ChildCom.vue -->
<template><div>{{ msg }}</div><div v-bind="$attrs">{{ msg }}</div>
</template><script setup>
defineProps({msg: {type: String}
})
</script>

 

$listeners  弃用

$listeners 对象在 Vue 3 中已被移除。事件监听器现在是 $attrs 的一部分:

{text: '这是一个 attribute',onClose: () => console.log('close 事件被触发')
}

 attrs在 js 中的用法

除了在 template 中可以访问到 $attrs ,在 JS 中也可以访问到。

vue 3 其实是兼容大部分 Vue 2 语法的,也就是 Options API 。而 attrs 在 Options APi 和 Composition Api 中的使用方法会稍微有一丢丢区别。而 Composition API 又分为 Vue 3.2 前的语法和 3.2 后的语法。

接下来将分开讨论这3种情况。

Options API

<!-- 父组件 ParentCom.vue -->
<template><ChildCommsg="雷猴"data="123"name="鲨鱼辣椒"style="color: red;"/>
</template><script setup>
import ChildCom from './ChildCom.vue'
</script><!-- 子组件 ChildCom.vue 暂不关注 template 部分 -->
<script>
export default {props: {msg: {type: String}},mounted() {console.log(this.$attrs)}
}
</script>

此时控制台会输出没被 props 接收的属性。 

Composition API 3.0的语法 

<!-- 父组件 ParentCom.vue -->
<template><ChildCommsg="雷猴"data="123"name="鲨鱼辣椒"style="color: red;"/>
</template><script setup>
import ChildCom from './ChildCom.vue'
</script><!-- 子组件 ChildCom.vue 暂不关注 template 部分 -->
<script>
export default {props: {msg: {type: String}},setup(props, context) {console.log('props: ', props)console.log('attrs: ', context.attrs)}
}
</script>

Vue 3.2 前的写法,需要在 setup 方法里接收2个参数,而 attrs 就在 context 参数里。

Composition API 3.2的语法 

Vue 3.2 后的语法,可以在 <script> 标签上添加 setup 属性。所以在代码里就不需要再调用 setup 方法了。

在这种情况下,props 成了默认的全局方法,而 attrs 则需要另外引入。

<!-- 父组件 ParentCom.vue -->
<template><ChildCommsg="雷猴"data="123"name="鲨鱼辣椒"style="color: red;"/>
</template><script setup>
import ChildCom from './ChildCom.vue'
</script><!-- 子组件 ChildCom.vue 暂不关注 template 部分 -->
<script setup>
import { useAttrs } from 'vue'const props = defineProps({msg: {type: String}
})const attrs = useAttrs()console.log('props: ', props)
console.log('attrs: ', attrs)
</script>

需要引入 vue 中的 useAttrs ,在调用 useAttrs 后会返回当前未被 props 接收的属性。

重点是以下两句。

import { useAttrs } from 'vue'
const attrs = useAttrs()

总结

移除 $listeners 

概览

$listeners 对象在 Vue 3 中已被移除。事件监听器现在是 $attrs 的一部分:

{text: '这是一个 attribute',onClose: () => console.log('close 事件被触发')
}

2.x 语法

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

<template><label><input type="text" v-bind="$attrs" v-on="$listeners" /></label>
</template>
<script>export default {inheritAttrs: false}
</script>

3.x 语法

在 Vue 3 的虚拟 DOM 中,事件监听器现在只是以 on 为前缀的 attribute,这样它就成为了 $attrs 对象的一部分,因此 $listeners 被移除了。

<template><label><input type="text" v-bind="$attrs" /></label>
</template>
<script>
export default {inheritAttrs: false
}
</script>

如果这个组件接收一个 id attribute 和一个 v-on:close 监听器,那么 $attrs 对象现在将如下所示:

{id: 'my-input',onClose: () => console.log('close 事件被触发')
}

$attrs 包含 class & style 

概览

$attrs 现在包含了所有传递给组件的 attribute,包括 class 和 style

2.x 行为 

Vue 2 的虚拟 DOM 实现对 class 和 style attribute 有一些特殊处理。因此,与其它所有 attribute 不一样,它们没有被包含在 $attrs 中。

上述行为在使用 inheritAttrs: false 时会产生副作用:

  • $attrs 中的 attribute 将不再被自动添加到根元素中,而是由开发者决定在哪添加。
  • 但是 class 和 style 不属于 $attrs,它们仍然会被应用到组件的根元素中:
<template><label><input type="text" v-bind="$attrs" /></label>
</template>
<script>
export default {inheritAttrs: false
}
</script>

像这样使用时:

<my-component id="my-id" class="my-class"></my-component>

……将生成以下 HTML:

<label class="my-class"><input type="text" id="my-id" />
</label>

3.x 行为

$attrs 包含了所有的 attribute,这使得把它们全部应用到另一个元素上变得更加容易了。现在上面的示例将生成以下 HTML:

<label><input type="text" id="my-id" class="my-class" />
</label>

在使用了 inheritAttrs: false 的组件中,请确保样式仍然符合预期。如果你之前依赖了 class 和 style 的特殊行为,那么一些视觉效果可能会遭到破坏,因为这些 attribute 现在可能被应用到了另一个元素中。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

zsh: command not found: conda问题解决

参考:https://zhuanlan.zhihu.com/p/158703094 一、问题介绍与环境介绍 系统为macOS Catalina 10.15.4 所用终端为zsh 安装了oh-my-zsh之后conda命令在终端中不可用。 二、原因分析 终端中zsh的可访问的程序一般放在/bin, /usr/bin, /usr/local/bin&#xff0c;/bin目录下&…

Android Studio git 取消本地 commit(未Push)

操作比较简单 1.选中项目然后依次选择&#xff1a;Git->Repository->Reset HEAD 2.然后再to Commit中输入HEAD^&#xff0c;表示退回到上一个版本。

区块链金融的开发流程

区块链金融应用的开发流程与一般的软件开发流程有许多相似之处&#xff0c;但它还涉及到智能合约的编写、区块链网络集成和加密货币处理等特定方面的工作。以下是一般区块链金融应用的开发流程&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件…

工程物料管理信息化建设(十二)——关于工程物料管理系统最后的思考

目录 1 功能回顾1.1 MTO模块1.2 请购模块1.3 采购模块1.4 催交模块1.5 现场管理模块1.6 数据分析和看板模块1.7 其它模块 2 最后几个问题2.1 按管线发料和直接发料重叠2.2 YHA 材料编码的唯一性问题2.3 “合同量单-箱单-入库单” 数据映射 3 关于未来的思考3.1 三个专业之间的关…

Springboot 订餐管理系统idea开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 springboot 订餐管理系统是一套完善的信息系统&#xff0c;结合springboot框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用springboot框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有 完整的源代码和数据库&…

PBA.客户需求分析管理

1 需求的三个层次: Requirement/Wants/Pains 大部分人认为&#xff0c;产品满足不了客户需要&#xff0c;是因为客户告知的需求是错误的&#xff0c;这听起来有一些道理&#xff0c;却没有任何意义。不同角色对于需求的理解是不一样的。在客户的需求和厂家的需求之间必然有一定…

vue3 + element Plus实现表格根据关键字合并行,并实现行的增删改操作

根据关键字合并表格 1.实现初始化表格2.实现添加班级与学生的功能3.添加的弹窗4.删除班级5.删除学生 首先看最终实现的效果 1.实现初始化表格 <template><div class"main-page"><div class"flex-end"><div class"public-search…

【C++】哈希表

个人主页&#xff1a;&#x1f35d;在肯德基吃麻辣烫 我的gitee&#xff1a;C仓库 个人专栏&#xff1a;C专栏 文章目录 前言一、什么是哈希&#xff1f;二、哈希表的插入及哈希冲突解决哈希冲突的方式1.闭散列的哈希表闭散列哈希表的删除实现&#xff08;重点细节处理&#xf…

LNMP和数据库的安装

LNMP是什么 L&#xff1a;Linux平台&#xff0c;操作系统&#xff0c;另外桑组件的运行平台 N&#xff1a;nginx 提供前端页面 M&#xff1a;MySQL&#xff0c;开源关系的数据库&#xff0c;主要是用来保存用户账号信息。 P&#xff1a;PHP&#xff0c;开发一种动态页面的编程语…

基于 ACK Fluid 的混合云优化数据访问(一):场景与架构

作者&#xff1a;车漾&#xff08;必嘫&#xff09; 本系列文章将介绍如何基于 ACK Fluid 支持和优化混合云的数据访问场景。 概述 在 AI 和大数据时代&#xff0c;算力即正义&#xff0c;强大的算力推动了源源不断的创新。然而&#xff0c;企业自建的算力集群存在资源容量和…

C#中的Dispatcher:Invoke与BeginInvoke的使用

Dispatcher是.NET框架中的一个重要概念&#xff0c;用于处理异步消息传递。在C#中&#xff0c;Dispatcher提供了两种方法&#xff1a;Invoke和BeginInvoke&#xff0c;用于控制线程上消息的顺序和执行方式。 目录 一、Dispatcher.Invoke二、Dispatcher.BeginInvoke三、使用场景…

安卓三防平板在行业应用中有哪些优势

在工业维修和检测中&#xff0c;安卓三防平板的应用也十分广泛。它可以搭载各种专业软件和工具&#xff0c;帮助工人们进行设备故障排查和维护&#xff0c;降低了维修成本和停机时间。 一、产品卖点&#xff1a; 1. 防水性能&#xff1a;该手持平板采用了防水设计&#xff0c;…