vue3 透传 Attributes

news2024/9/22 19:36:30

前言

Vue 3 现在正式支持了多根节点的组件,也就是片段!

Vue 2.x 遵循单根节点组件的规则,即一个组件的模板必须有且仅有一个根元素。

为了满足单根节点的要求,开发者会将原本多根节点的内容包裹在一个<div>元素中:

<!-- Layout.vue -->
<template>
  <div>
    <h1>标题</h1>
    <p>段落</p>
  </div>
</template>

这是因为Vue 的编译器在解析组件模板时,是基于单根节点的树形结构进行处理的。如果存在多个根节点,编译器无法明确地构建组件的虚拟 DOM 结构。

因此,在Vue 2.x中,父组件在使用子组件时,写在子组件上的 classstyleid 等属性会直接传递到子组件的根元素上。

Vue 3.x 打破了 Vue 2.x 中组件模板必须有且仅有一个根元素的限制,现在组件可以包含多个根节点。

<template>
  <h1>标题</h1>
  <p>段落</p>
</template>

当组件存在多个根节点时,在父组件中给该组件传递属性(attribute)就需要明确指定这些属性应该绑定到哪个根节点上。如果不进行显式指定,Vue 无法确定属性的归属。

<template>
  <ChildComponent>
    <template v-slot:default="{ attrs }">
      <div v-bind="attrs">这是一个 div 根节点</div>
      <p>这是一个 p 根节点</p>
      <span>这是一个 span 根节点</span>
    </template>
  </ChildComponent>
</template>

在示例中,通过v-slot:default="{attrs}"获取到ChildComponent.vue通过插槽传递给父组件的所有属性(存储在attrs中),然后使用v-bind="attrs"将这些属性显式地绑定到其中一个根节点<div>上。

Attributes 继承

“透传 attribute”指的是传递给一个组件,却没有被该组件声明为 propsemits 的 attribute 或者 v-on 事件监听器。

当一个组件以单个元素为根作渲染时,透传的 attribute 会自动被添加到根元素上。

最常见的例子就是 classstyleid

子组件ChildComponent.vue的模板内容如下:

<div>这是子组件的div</div>

在父组件使用子组件ChildComponent.vue,并且传入了 classstyleid

<template>
  <div>
    <h1>父组件</h1>
    <ChildComponent class="child-div"  id="child-div"
      style="font-size: 20px; color: brown;" />
  </div>
</template>
<script setup lang="ts">
import ChildComponent from './ChildComponent.vue';
</script>

渲染出的DOM结果是:

<div class="child-div" id="child-div" style="font-size: 20px; color: brown">
  这是子组件的div
</div>

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

style 属性透传到子组件的根元素后,它的生效方式与直接在 HTML 元素上设置 style 属性是一样的:
在这里插入图片描述

自动合并 classstyle

如果一个子组件的根元素已经有了 classstyle attribute,它会和从父组件上继承的值合并。

给子组件ChildComponent.vue加上classstyleid属性:

<div
  class="child-box"
  id="child-box"
  style="padding: 15px; background-color: #f8f8f8"
>
  这是子组件的div
</div>

渲染出的DOM结果是:

<div
 class="child-box child-div"
  id="child-div"
  style="
    padding: 15px;
    background-color: rgb(248, 248, 248);
    font-size: 20px;
    color: brown;
  "
>
  这是子组件的div
</div>

子组件的classstyle 属性值 和 从父组件上继承的值合并,子组件的 id 属性值被从父组件继承的 id 属性值覆盖。

页面渲染结果如下图:
在这里插入图片描述

v-on 监听器继承

子组件ChildComponent.vue的模板内容如下:

<div @click="console.log('子组件的点击事件被触发了')"> 这是子组件的div </div>

在父组件中,给<ChildComponent>绑定一个点击事件:

<template>
  <div class="home-wrap">
    <h1>父组件</h1>
    <ChildComponent @click="console.log('在父组件中,给子组件绑定的点击事件被触发了!')"/>
  </div>
</template>
<script setup lang="ts">
import ChildComponent from './ChildComponent.vue';
</script>

父组件中绑定的click 监听器会被添加到 <ChildComponent> 的根元素:子组件的 <div> 元素之上。
子组件的<div>元素自身也通过 v-on 绑定了一个事件监听器。

当点击子组件的<div>元素,子组件的click监听器和从父组件继承的监听器都会被触发:
在这里插入图片描述

深层组件继承

有些情况下一个组件会在根节点上渲染另一个组件。

ChildComponent.vue的根节点渲染的是另一个组件GrandChild.vue时:

<!-- ChildComponent.vue 的模板,只是渲染另一个组件:<GrandChild /> -->
<template>
  <GrandChild />
</template>

此时 <ChildComponent> 接收的透传 attribute 会直接继续传给 <GrandChild>

注意:

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

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

禁用 Attributes 继承

在选项式API中,在组件选项中设置 inheritAttrs: false 可以禁止 组件自动地继承 attribute。

在组合式API中,在 <script setup> 中使用 defineOptions

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

通过设置 inheritAttrs 选项为 false,可以完全控制透传进来的 attribute 被如何使用。

注意:透传进来的 attribute 可以在模板的表达式中直接用 $attrs 访问到

ChildComponent.vue中,设置 inheritAttrs: false 并通过$attrs访问透传属性 customValue

<!-- ChildComponent.vue 的模板 -->
<template>
  <div>在ChildComponent.vue中,读取透传 Attributes: {{ $attrs.customValue }}</div>
</template>
<script setup lang="ts">
defineOptions({
  inheritAttrs: false
})
</script>

在父组件中,使用子组件ChildComponent.vue,传递class属性、customValue属性:

<template>
  <div class="home-wrap">
    <h1>父组件</h1>
    <ChildComponent class="child-div" :customValue="customValue" />
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const customValue = ref(10)
</script>

渲染出的DOM结果是:

<div>在ChildComponent.vue中,读取透传 Attributes: 10</div>

可以看到,父组件传的class属性并没有被直接透传到子组件的根元素上。

通过Vue Devtools查看$attrs$attrs 包含了 透传进来的 classcustomValue属性:
在这里插入图片描述
$attrs 对象包含了除组件所声明的 propsemits 之外的所有其他 attribute,例如 classstylev-on 监听器等等。

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

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

通过设定 inheritAttrs: false 和使用 v-bind="$attrs" 来实现将 透传 attribute 应用在合适的元素上:

<!-- ChildComponent.vue 的模板 -->
<template>
  <div>
    <div v-bind:="$attrs">在ChildComponent.vue中,读取透传 Attributes: {{ $attrs.customValue }}</div>
  </div>
</template>
<script setup lang="ts">
defineOptions({
  inheritAttrs: false
})
</script>

渲染出的DOM结果是:

<div>
  <div class="child-div" customvalue="10">
    在ChildComponent.vue中,读取透传 Attributes: 10
  </div>
</div>

通过不带参数的 v-bind,将一个对象的所有属性都作为 attribute 应用到目标元素上。

多根节点的 Attributes 继承

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

修改ChildComponent.vue

<!-- ChildComponent.vue 的模板 -->
<template>
  <h2>ChildComponent的标题</h2>
  <div>ChildComponent的内容</div>
</template>

此时,ChildComponent.vue是多根节点模板,由于 Vue 不知道要将 attribute 透传到哪里,所以会抛出一个警告:

Extraneous non-props attributes (class, customValue) were passed to component but could not be automatically inherited because component renders fragment or text root nodes.

ChildComponent.vue有多个根节点时,需要显式绑定 $attrs

<!-- ChildComponent.vue 的模板 -->
<template>
  <h2 v-bind="$attrs">ChildComponent的标题</h2>
  <div>ChildComponent的内容</div>
</template>

在 JavaScript 中访问透传 Attributes

在选项式API中,attrs 会作为 setup() 上下文对象的一个属性暴露:

<script>
export default {
  setup(props, ctx) {
    // 透传 attribute 被暴露为 ctx.attrs,且 没有响应性
    console.log(ctx.attrs)
  }
}
</script>

在组合式API中,在 <script setup> 中使用 useAttrs() API 来访问一个组件的所有透传 attribute:

<script setup>
import { useAttrs } from 'vue'
const attrs = useAttrs()
</script>

有个疑问待解决:

官网说法:attrs 对象总是反映为最新的透传 attribute,但它没有响应性,不能通过侦听器去监听它的变化。

我直接在模板中使用$attrs,以及使用上述2种方式获取attrs,修改透传 attribute 后,页面也更新了。
所以没get到,官方说的attrs对象没有响应性是指哪方面。
知道为什么的童鞋可以在评论区讲一下或者是私信给我说一下,非常感谢!

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

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

相关文章

【MySQL】基础部分——DDL,DML,DQL,DCL,函数,约束,多表查询,事务

个人学习记录&#xff0c;供以后回顾和复习 ubuntu下安装使用1.DDL&#xff0c;DML&#xff0c;DQL&#xff0c;DCLDDL数据库表 DML增改删 DQL条件查询分组查询排序查询分页查询 DCL管理用户权限控制 2.函数字符串函数数值函数日期函数流程函数 3.约束4.多表查询多表关系内连接…

学习大数据DAY58 增量抽取数据表

作业 1 SQL 优化的常见写法有哪些 - 面试经常被问 使用索引&#xff1a;合理创建和使用索引是提高查询效率的关键。索引可以加速数据的检 索速度&#xff0c;但是索引也会占用额外的存储空间&#xff0c;并且在插入、删除和更新操作时会 有额外的开销。 避免全表扫描&…

Git+Jenkins 基本使用(Basic Usage of Git+Jenkins)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

Linux命令分享 四 (ubuntu 16.04)(vi操作文件)

1、su 切换用户 su - 用户名 切换到该用户并将目录切换至该用户的主目录 **注意该语句执行后需要输入密码&#xff0c;输入密码时终端不回显&#xff08;不会显示你输入的密码&#xff09;&#xff0c;输完直接回车即可 su 用户名 切换用户但不切换目录 su - root su root **注…

你可能遗漏的一些C#/.NET/.NET Core知识点

前言 在这个快速发展的技术世界中&#xff0c;时常会有一些重要的知识点、信息或细节被忽略或遗漏。《C#/.NET/.NET Core拾遗补漏》专栏我们将探讨一些可能被忽略或遗漏的重要知识点、信息或细节&#xff0c;以帮助大家更全面地了解这些技术栈的特性和发展方向。 拾遗补漏Git…

NISP 一级 | 5.3 电子邮件安全

关注这个证书的其他相关笔记&#xff1a;NISP 一级 —— 考证笔记合集-CSDN博客 0x01&#xff1a;电子邮件安全威胁 电子邮件&#xff08;Electronic mail&#xff0c;Email&#xff09;是一种用电子手段提供信息交换的服务方式&#xff0c;是因特网上应用最为广泛的服务之一。…

【原创 架构设计】多级缓存的应用、常见问题与解决方式

1. 简介 多级缓存是一种常见的性能优化手段&#xff0c;对于多级缓存一般意义上的理解具体主要实现其实指的就是本地缓存和分布式缓存。 本地缓存一般采用Caffeine或者Guava Cache来进行实现&#xff0c;而分布式缓存一般采用Redis来进行实现。 2. 业务流程 业务线程先在本…

聚类_K均值

import numpy as np import matplotlib.pyplot as plt from sklearn.datasets import make_blobs1.数据预处理 #创建基于高斯分布的样本点, x是点的坐标&#xff0c;y是所属聚类值 x, y make_blobs(n_samples100, centers6, random_state100, cluster_std0.6) # 设置图形尺寸…

整数在内存中的存储原码反码补码

目录 1.整数在内存中以二进制的形式存在 1.1&#xff08;正数存储情况&#xff09; 1.2 负数存储情况 1.3整数的补码如何得到原码 2.无符号整数的原反补码 小心&#xff01;VS2022不可直接接触&#xff0c;否则&#xff01;没这个必要&#xff0c;方源面色淡然一把抓住&am…

Linux网络——守护进程、会话、进程组

文章目录 会话守护进程编写守护进程的注意事项编写样例 会话 会话是session&#xff0c;代表的是客户端与服务器的一次交互过程&#xff0c;我们可以简单理解为&#xff0c;当我们打开一个终端&#xff0c;在用户登录时&#xff0c;就是创建了一个会话 一般来说会话都与各自的…

62. 不同路径、64. 最小路径和

思路 dp&#xff1a;代表到达当前位置的总方式 初始化&#xff1a;第一行的位置dp[0][j]&#xff1a;当前位置只能由左边的位置向右移动得到 所以只有1种方式 d[0][j]1, d[0][0]1 第一列的位置 dp[i][0]&#xff1a;当前位置只能由上一个位置向下移动得到 除此之外的位置可以由…

python画图|同时输出二维和三维图

前面已经学习了如何输出二维图和三维图&#xff0c;部分文章详见下述链接&#xff1a; python画图|极坐标下的3D surface-CSDN博客 python画图|垂线标记系列_如何用pyplot画垂直x轴的线-CSDN博客 有时候也需要同时输出二位和三维图&#xff0c;因此有必要学习一下。 【1】…

三明儿童自闭症寄宿制学校:关爱、教育、成长一站式服务

三明儿童自闭症寄宿制学校的启示&#xff1a;广州星贝育园——自闭症儿童的一站式成长乐园 在探讨自闭症儿童教育的道路上&#xff0c;寄宿制学校以其独特的优势&#xff0c;为孩子们提供了集关爱、教育、成长于一体的全方位服务。虽然文章开头提及了“三明儿童自闭症寄宿制学…

AI预测体彩排3采取888=3策略+和值012路或胆码测试9月15日升级新模型预测第81弹

经过80多期的测试&#xff0c;当然有很多彩友也一直在观察我每天发的预测结果&#xff0c;得到了一个非常有价值的信息&#xff0c;那就是9码定位的命中率非常高&#xff0c;已到达90%的命中率&#xff0c;这给喜欢打私菜的朋友提供了极高价值的预测结果~当然了&#xff0c;大部…

请求响应-05.请求-日期参数JSON参数

一.日期参数 当浏览器发起的请求参数类型是日期参数时&#xff0c;我们通常使用LocalDateTime对象来接收&#xff0c;前面使用DateTimeFormat注解来完成日期的格式转换&#xff08;日期时间格式有多种&#xff0c;需要哪种就设置为哪种&#xff1a;如yyyy-MM-dd HH:mm:ss&…

C++比大小游戏

目录 开头程序程序的流程图程序游玩的效果下一篇博客要说的东西 开头 大家好&#xff0c;我叫这是我58。 程序 #include <iostream> #include <Windows.h> using namespace std; int main() {int ir 1;char chparr[2] { 0 };int ip1 0;int ip2 0;int i 1;c…

【ARM】Cache深度解读

Cache的基本概念和使用场景 不同的Master硬件共享数据时—invalid cache 外设和DDR之间没有cache&#xff0c;所以外设直接把数据写入DDR中&#xff0c;但是cpu和DDR之间有cache&#xff0c;cpu会首先访问cache&#xff0c;如果命中直接从cache中拿数据&#xff0c;但是此时的…

完整版订单超时自动取消功能

前几天对实习还是继续学习技术产生了抉择&#xff0c;问了一个前辈&#xff0c;他抛给我一个问题&#xff0c;怎么做15分钟订单自动取消&#xff0c;我说然后到时间之后&#xff0c;自动执行这个订单关闭业务&#xff0c;比如把锁了的库存给解开等等操作&#xff0c;然后在数据…

后续学习规划 ----含我个人的学习路线,经历及感受

目前的基础 开发相关&#xff08;最重要&#xff09; 1.Java SE 从入门到起飞 2.Java Web开发 3.苍穹外卖 以上三个是和开发相关的基础。 我是按照书写的顺序学习的&#xff0c;有需要的朋友可以参考。 计算机相关 其他的话&#xff0c;都是比较久远的了。隔得时间一年半…

【大数据方案】智慧大数据平台总体建设方案书(word原件)

第1章 总体说明 1.1 建设背景 1.2 建设目标 1.3 项目建设主要内容 1.4 设计原则 第2章 对项目的理解 2.1 现状分析 2.2 业务需求分析 2.3 功能需求分析 第3章 大数据平台建设方案 3.1 大数据平台总体设计 3.2 大数据平台功能设计 3.3 平台应用 第4章 政策标准保障体系 4.1 政策…