vue3使用h函数如何封装组件和$attrs和props的区别

news/2025/10/9 9:12:50/文章来源:https://www.cnblogs.com/IwishIcould/p/19125897

二次封装组件需要考虑的3个重要的问题

1,props 如何进行传递
2,插槽如何穿透
3,暴露实例以及实例中的方法

在vue3中的$attrs的变化

vue3中$listeners已被删除合并到$attrs中。
vue3的$attrs现在包括class和style属性。
vue2中不包含class和style属性。
也就是说:当子组件写上 v-bind="$attrs"
父组件就可以使用子组件的内置事件和内置属性了。
下面我们会详细说一下$attrs

props 如何进行传递属性和事件

我们可以在子组件中使用 v-bind="$attrs"
这样可以把父组件中的属性传递给子组件了

// 子组件
<template><div><!-- v-bind="$attrs"  可以接收到父组件中的属性设置 --><el-input v-bind="$attrs"></el-input></div>
</template>
// 父组件
<template><div><MyInput class="set-width" placeholder="请输入名称" clearable v-model="name" @blur="clearHandler"></MyInput></div>
</template><script setup lang="ts">
import MyInput from '@/components/MyInput.vue'
import { ref } from 'vue';
let name = ref('')const clearHandler = () => {console.log('失去焦点啦')name.value += 'copy'
}
</script><style lang="scss" scoped>
.set-width {margin: 100px;width: 300px;
}
</style>

01
01-1

如何解决写组件时没有属性提示的问题

我们发现一个问题:在父组件中的组件写相关属性时,没有属性提示。

// 子组件
<template><div><!-- v-bind="props"  现在我们的属性肯定是 element-plus 的内置属性了 --><el-input v-bind="props"></el-input></div>
</template><script setup lang="ts">
// 引入 input 的所有属性
import { type InputProps} from 'element-plus'
// 定义 props, Partial将必填属性变成可选属性
const props = defineProps<Partial<InputProps>>()
</script>

这样父组件在使用的时候,就可以看到属性提示了。

插槽如何封装1: 通过 template 来封装插槽

<template><div><el-input v-bind="props"><!-- 插槽 --><template v-for="(_, slotName) in $slots" #[slotName]><slot :name="slotName"></slot></template></el-input></div>
</template><script setup lang="ts">
// 引入 input 的所有属性
import { type InputProps} from 'element-plus'
// 定义 props, Partial将必填属性变成可选属性
const props = defineProps<Partial<InputProps>>()

插槽如何封装2: 通过h函数来处理插槽

我们使用h函数来进行封装。
h函数如果第1个参数如果是组件,那么第三个参数就是插槽

<template><div><!-- 我们使用h函数来进行封装,h函数如果第1个参数如果是组件,那么第三个参数就是插槽 --><component :is="h(ElInput, {...$attrs,...props}, $slots)"></component></div>
</template><script setup lang="ts">
import { h } from 'vue'
// 引入 input 的所有属性
import { type InputProps, ElInput} from 'element-plus'
// 定义 props, Partial将必填属性变成可选属性
const props = defineProps<Partial<InputProps>>()
</script>
// 父组件
<template><div><MyInput class="set-width"   placeholder="请q输入内容"><!-- 在组件中使用插槽 --><template #prepend><el-select v-model="select" placeholder="Select" style="width: 115px"><el-option label="Restaurant" value="1" /><el-option label="Order No." value="2" /><el-option label="Tel" value="3" /></el-select></template><template #append>.com</template></MyInput></div>
</template><script setup lang="ts">
import MyInput from '@/components/MyInput.vue'
import { ref } from 'vue';
const select = ref('1')
</script><style lang="scss" scoped>
.set-width {margin: 100px;width: 300px;
}
</style>

02

暴露实例以及实例中的方法

我们可以通过 defineExpose 来暴露实例以及方法【常用的】
也可以通过vm.exposed来进行暴露实例以及方法
需要注意组件最初设置了v-if=false这种情况

// 子组件
<template><div><!-- 我们使用h函数来进行封装,h函数如果第1个参数如果是组件,那么第三个参数就是插槽 --><component :is="h(ElInput, {...$attrs,...props, ref: nodeRef}, $slots)"></component></div>
</template><script setup lang="ts">
import { h, getCurrentInstance } from 'vue'
// 引入 input 的所有属性
import { type InputProps, ElInput} from 'element-plus'
// 定义 props, Partial将必填属性变成可选属性
const props = defineProps<Partial<InputProps>>()
// 获取当前组件实例
const vm = getCurrentInstance()// ref可以是一个字符串,也可以是一个函数。这样父组件就可以通过ref访问这个组件的实例了
function  nodeRef(inputInstance) {// 现在我们把子组件实例给他,当组件使用了v-if=false的时候,inputInstance为null// 这里我们是把实例(实例中包含方法)暴露出去vm.exposed= inputInstance || {}// 代理对象也要做同步的更改vm.exposeProxy = inputInstance || {}
}
</script>
// 父组件
<template><div><MyInput class="set-width" v-model="msg" ref="NodeInputRef"  placeholder="请输入内容" @blur="clearHandler"><!-- 在组件中使用插槽 --><template #prepend><el-select v-model="select" placeholder="Select" style="width: 115px"><el-option label="Restaurant" value="1" /><el-option label="Order No." value="2" /><el-option label="Tel" value="3" /></el-select></template><template #append>.com</template></MyInput><el-button @click="getHandler">清空值</el-button></div>
</template><script setup lang="ts">
import MyInput from '@/components/MyInput.vue'
import { ref } from 'vue';
const select = ref('1')
const msg = ref('放假快乐')const NodeInputRef = ref(null)
// 获取实例中的方法
const getHandler = () => {NodeInputRef.value?.clear()
}const clearHandler = () => {console.log('失去焦点啦')
}
</script>

03

04

另外一种暴露方式

常见的暴露方式
defineProps({ name:xxx,age:xxx,
})
等价与下面这一种
vm.exposed= {name:xxx,age:xxx,
}

vue3 中的 props

props 是组件的自定义属性,用于从父组件向子组件传递数据。
props 不会包含继承的属性(如 class 和 style),除非显式声明。

vue3 中的 $attrs

vu3中$attrs: 包含了所有[传递]给[子组件]的非 props 属性。如:继承的属性(如 class 和 style)以及未在 props 中声明的属性。
vue3中的$attrs: 包含 style和class。$attrs包含着数据和事件。

vue3 $listeners已被删除合并到$attrs中。

在vue2中的$attrs

vu2中$attrs: 包含了所有[传递]给[子组件]的非 props 属性和style和class之外的属性。
vue2中的$attrs: 不包含 style和class

下面是详细的讲解:
在V ue2 中,attrs里面包含着上层组件传递的所有数据(除style和class)
当一个组件声明了prop时候,attrs里面包含除去prop里面的数据剩下的数据。
结合inheritAttrs:false,可以将传递下来的数据应用于其他元素,而不是根元素。

h函数封装上面的组件

有些的小伙伴说:我们是否可以使用h函数去封装上面的组件呢?

<script lang="ts">
import { defineComponent, h, getCurrentInstance } from 'vue'
import { type InputProps, ElInput } from 'element-plus'
export default  {// 组件名称name: 'MyInput',inheritAttrs: false,setup(props, { attrs, slots }) {console.log('attrs', attrs)// attrs:除去props中声明的属性。包含属性和事件const vm = getCurrentInstance()function nodeRef(inputInstance: any) {vm.exposed = inputInstance || {}vm.exposeProxy = inputInstance || {}}return () => h(ElInput, {...attrs,...props,ref: nodeRef}, slots)}
}
<template><div><MyInput class="set-width" placeholder="请输入名称" clearable v-model="name" @blur="clearHandler"></MyInput></div>
</template><script setup lang="ts">
import MyInput from '@/components/MyInput.vue'
import { ref } from 'vue';
let name = ref('')
const clearHandler = () => {console.log('失去焦点啦')name.value += 'copy'
}
</script><style lang="scss" scoped>
.set-width {margin: 100px;width: 300px;
}
</style>

05

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

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

相关文章

2025 年最新国际物流服务公司权威排行榜单发布,含海运快递跨境专线等领域最新推荐国际物流海运专线/国际物流专线/国际物流公司/国际物流一条龙公司推荐

在全球化贸易不断推进、跨境电商规模持续扩大的背景下,国际物流成为连接国内外市场的核心纽带,其服务质量直接影响商家的运营效率与客户体验。然而,当前市场上国际物流企业数量众多,服务水平参差不齐,部分企业存在…

多智能体强化学习算法(MAPPO)

多智能体强化学习算法分为 中心式和分散式 中心式的思想是考虑一个合作式的环境,直接将单智能体算法扩展,让其直接学习一个联合动作的输出,但是并不好给出单个智能体该如何进行决策。分散式是每个智能体独立学习自己…

实用指南:ubuntu开机自动挂载windows下的硬盘

实用指南:ubuntu开机自动挂载windows下的硬盘pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", &q…

《软件需求最佳实践》阅读笔记二

需求捕获是需求开发中的第一个活动,每个团队都必须提高需求捕获的有效性,要点在于计划性和科学性。 需求捕获的过程是人和人打交道的过程,需求捕获需要需求分析人员积极主动的去获取需求,是散网打鱼,而不是休闲钓…

下载免费网站模板wordpress菜单设置

RP2040 采用合宙的RP2040(板载4MB Flash)&#xff0c; 所有开发资料参考官方&#xff1a;树莓派 Pico 中文站

2025 年国内优质不锈钢厂商最新推荐排行榜:含沈阳及东三省地区水箱油罐楼梯激光切割等产品服务商不锈钢水箱/油罐/水灌/油箱/楼梯/折弯厂家推荐

当前国内不锈钢市场产品品类繁杂,从基础的板材、管材到定制化的水箱、油罐、桥梁杆等,覆盖建筑、化工、机械制造等多个领域,但供应商资质参差不齐,部分企业存在质量不稳定、交货延迟、售后缺失等问题,尤其在环保政…

假脱机技术

什么是脱机技术,脱机技术能解决什么问题 脱机技术用磁带完成 磁带的输入比织带机快得多 【脱离主机控制的进行输入输出操作】脱机技术 假脱机技术的实现原理 假脱机技术--输入输出井 又叫做SPOOLing技术,用软件的方式…

2025 顶管源头厂家最新推荐榜单:F 型混凝土 / 水泥 / 电力 / 矩形 / 市政 / 排水 / 大口径顶管优质供应商精选

随着新型城镇化与地下管网改造工程的全面推进,顶管作为地下铺设核心建材的市场需求呈爆发式增长,但行业乱象也随之凸显。部分厂家缺乏规模化生产能力,导致供货周期波动大,难以匹配大型工程的进度要求;另有企业工艺…

2025 年 AI 教育机构最新推荐排行榜:涵盖企业 AI 培训、AI + 教育、AI 教育线下机构等领域的优质机构精选

随着 AI 技术在教育领域的深度渗透,AI 教育市场涌现出大量机构,但产品同质化、技术应用不精准、服务质量参差不齐等问题凸显,给企业、学校及学习者选择优质机构带来极大困扰。为解决这一难题,帮助需求方精准找到技…

html网站 下载没有网站域名是否需要备案

一、是什么 DNS&#xff08;Domain Names System&#xff09;&#xff0c;域名系统&#xff0c;是互联网一项服务&#xff0c;是进行域名和与之相对应的 IP 地址进行转换的服务器 简单来讲&#xff0c;DNS相当于一个翻译官&#xff0c;负责将域名翻译成ip地址 IP 地址&#…

2025 年最新台车炉实力厂家榜单发布,含大型燃气 / 天然气 / 热处理 / 全纤维等类型设备最新推荐及优质企业核心优势解析

当前工业热处理领域,台车炉作为关键生产设备,其性能直接关系到制造企业的生产效率与产品质量。但市场上厂家数量繁杂,产品质量差异大,部分厂家存在技术落后、环保不达标、售后响应慢等问题,让企业选购时面临诸多困…

Kubernetes Service详解:实现服务发现与负载均衡

1. Service概念引入k8s之部署Deployment章节我们介绍RS以及Deployment,Deployment提供了pod的管理方式,以及通过副本控制器RC保证集群中pod的数量保持为指定数量。同时Deployment还提供了相关升级、回滚、更新速度、…

长尾关键词爱站深圳华强北赛格大楼晃动

647. 回文子串 题目链接/文章讲解&#xff1a;代码随想录 视频讲解&#xff1a;动态规划&#xff0c;字符串性质决定了 DP 数组的定义 | LeetCode&#xff1a;647.回文子串_哔哩哔哩_bilibili class Solution {public int countSubstrings(String s) {// 将字符串转换为字符数…

Jmeter批量调用不同值参数的CSV

需要在同一个接口,进行不同值的多次调用。 1、再添加里面 选择【配置元件】下的 【CSV Data Set Config】2、在CSV中设置文件名(包含路径),文件编码,变量名称,多个变量需要设置分隔符(分隔符看在文件中使用的分…

【一步步开发AI运动APP】十二、自定义扩展新运动项目2

之前我们为您分享了【一步步开发AI运动小程序】开发系列博文,通过该系列博文,很多开发者开发出了很多精美的AI健身、线上运动赛事、AI学生体测、美体、康复锻炼等应用场景的AI运动小程序;为了帮助开发者继续深耕AI运…

2025 年最新真石漆厂家排行榜:别墅外墙 / 专业仿砖 / 天然涂料优质厂家最新推荐指南

当前真石漆市场需求旺盛,但品牌鱼龙混杂,小作坊产品充斥市场,偷工减料导致涂层开裂、褪色等问题频发,不仅影响建筑美观,还增加消费者经济负担。行业标准执行不严、检测漏洞多,加上消费者缺乏专业选购知识,易被虚…

自学编程网站免费微信官方小程序开发工具

1 二维图像 1.1 二维曲线 plot(x, y, ls"-", lw1.5, labelNone)x, y&#xff1a;横坐标和纵坐标ls&#xff1a;颜色、点标记、线型列表&#xff0c;如 ls‘r*-’ 表示红色实线、*形点&#xff0c;ls‘g.’ 表示绿色散点lw&#xff1a;线宽度label&#xff1a;线标签…

没有网站如何做淘宝客如何做电商运营推广

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 元模型 元模型&#xff0c;是特定领域的模型&#xff0c;用于创建该领域中的模型的构建元素。典型的元模型结构可以分为四种&#xff1a;…

if 和 else 的用法

1 if 是用来判定条件是否成立 if 必须和 else 配对 当 if 的条件不成立的时候 才执行 else 的代码块 2 可以解决什么问题 可以去判断 这个东西是否连接 也可以去区分比如说 成绩的“及格” 与“不及格” 应用场景 判…