基于Vue3组件封装的技巧分享

news2024/11/18 21:43:46

本文在Vue3的基础上针对一些常见UI组件库组件进行二次封装,旨在追求更好的个性化,更灵活的拓展,提供一些个人的思路见解,如有不妥之处,敬请指出。核心知识点$attrs,$slots

  1. 需求

    需求背景

    日常开发中,我们经常会使用一些UI组件库诸如and design vueelement plus等辅助开发,提升效率。有时我们需要进行个性化封装,以满 足在项目中大量使用的需求。

    错误示范

    基于a-modal封装一个自定义Modal组件:修改modal样式按钮样式每次关闭后销毁渲染到指定元素上等等,后续项目的弹窗全部基于该自定义组件。
<template>
    <div ref="myModal" class="custom-modal"></div>
    <a-modal
        v-model:visible="visible"
        centered
        destroyOnClose
        :getContainer="() => $refs.myModal"
        @ok="handleOk"
        @cancel="handleCancel"
        :style="{ width: '560px', ...style }"
        :cancelText="cancelText"
        :okText="okText"
    >
        <!-- 以上皆为该组件的默认属性 -->
        <slot></slot>
    </a-modal>
</template>

<script setup>
const props = defineProps({
    title: {
        type: String,
        default: "",
    },
    style: {
        type: Object,
        default: () => ({}),
    },
    cancelText: {
        type: String,
        default: "取消",
    },
    okText: {
        type: String,
        default: "确定",
    },
});
const emits = defineEmits(["handleOk", "handleCancel"]);
const visible = ref(false);

const handleOk = () => {
    emits("handleOk");
};
const handleCancel = () => {
    emits("handleCancel");
};
defineExpose({ visible });
</script>

<style lang="less" scoped>
.custom-modal {
    :deep(.ant-modal) {
        //省略几百行样式代码
    }
}
</style>

代码封装完成,于是乎我们便能在项目中应用带有项目风格的弹窗

<CustomModal ref="xxxModal" title="xxx" @ok="onXxx" @cancel="onXxx" >content</CustomModal>
  1. $attrs

    问题来了:一切看起来都挺正常。直到有一天同事说:我想要去掉右上角的关闭按钮,能改成自定义的吗
    简单,直接加!
<!-- 省略不相关代码 -->
<a-modal :closable="closable"></a-modal>
<script setup>
const props = defineProps({
    //...
    closable:{
        type: Boolean,
        default: false
    }
});
</script>

另一位同事说:我不想让它是居中的,能改成自定义的吗,还有一位同事说…

思考:这样的情况多了,就有点难顶。每次一有新的需求,我就得改这个组件,导致这个组件代码越来越冗余。那么是否有一种方式能够将传进来的属性自动绑定给a-modal呢,有,那儿就是attrs
在这里插入图片描述

注意:
1.vue提供了$attrs这么一个属性用于接收父组件传递下来的属性,$attrs不包括已经写入props的值
2.如果父组件传递了style,class,那么这这些值不仅会存在于$attrs,还会默认绑定至根元素上。这一点需要注意

<modalTest :footer="null" :centered="false" :zIndex="999" />
//此时的$attrs
{ "footer": null, "centered": false, "zIndex": 999 }

有了这个组件实例,结合v-bind我们就可以这么写

<a-modal
    v-model:visible="visible"
    centered
    destroyOnClose
    :getContainer="() => $refs.myModal"
    :style="{ width: '560px', ...style }"
    v-bind="$attrs"
>
 <!---->
</a-modal>

这样一来,我们就可以使用a-modal提供的任意属性和方法了

  1. $slots

    问题来了:插槽怎么办,例如a-modal就提供了许多插槽,是不是要用哪个就先在自定义组件上写好呢?
    错误示例
<a-modal>
    <!-- default -->
    <slot></slot>

    <!-- title -->
    <template #title>
<slot name="title">{{ title }}</slot>
    </template>

    <!-- other -->
</a-modal>

弊端就像之前的,如果该原生提供了许多插槽,当有需要时岂不是频繁去修改自定义组件添加相应的插槽,其实利用$slots可以解决这个问题
在这里插入图片描述
官网的这段话简明扼要的说出的插槽的原理,我们所传递的插槽最终都是变成

{
    'slotName':fn(...args)  //fn返回一个虚拟DOM
    'defautl': fn(...args) //默认插槽
}

也就是我们传什么插槽进来,$slots就有什么值那么我们可以遍历$slots中的值,有什么插槽我们便动态绑定什么插槽

<a-modal>
    <template v-for="(_val, name) in $slots" #[name]="options">
        <slot :name="name" v-bind="options || {}"> </slot>
    </template>
</a-modal>

#[name]="options",我们可以拿到原生a-modalname这个插槽中传递来的一些状态options,并绑定在<slot>上。详情请查看官网:作用域插槽

这样一来,我们原生a-modal怎么使用插槽,自定义组件就怎么使用插槽

<CustomModal>
    <template #title="{arg1, arg2}">
        content
    </template>
</CustomModal>

至此,封装的代码如下

<template>
    <div ref="myModal" class="custom-modal"></div>
    <a-modal
        v-model:visible="visible"
        centered
        :getContainer="() => $refs.myModal"
        :style="{ width: '560px'}"
        destroyOnClose
        v-bind="$attrs"
    >
        <template v-for="(_val, name) in $slots" #[name]="ops">
            <slot :name="name" v-bind="ops || {}"> </slot>
        </template>
    </a-modal>
</template>

<script setup>
const visible = ref(false);
defineExpose({ visible });
</script>

<style lang="less" scoped>
.custom-modal {
    //style
}
</style>

还有许多优化的空间,例如当前父组件显隐该Modal需使用ref的方式访问visible。在vue3中也可以参考官网的做法这样子写

<template>
    <div ref="myModal" class="custom-modal"></div>
    <a-modal
        :visible="visible"
        //....
        v-bind="$attrs"
    >
          <!-- ...  -->
    </a-modal>
</template>

<script setup>
defineProps(['visible'])
const emit = defineEmits(); // 不用写"update:visible",vue会自动加上
watch(
    () => props.visible,
    (newVal) => emit("update:visible", newVal);
);
</script>

那么使用这个控制这个组件的显示隐藏就方便许多了

<CustomModal v-model:visible="visible"></CustomModal>

本文中的封装方式是基于vue3来进行实现,不局限在什么UI组件身上。如果使用的是vue2,情况稍有不同,请自行了解。

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

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

相关文章

PHP判断微信或QQ访问

PHP判断微信或QQ访问 若是微信或者QQ打开&#xff0c;提示图会覆盖网页&#xff0c;但网页功能仍在运行&#xff01; <meta name"viewport" content"initial-scale1, maximum-scale1, user-scalableno, widthdevice-width"><style> .top-gui…

leetcode第169题:多数元素

给定一个大小为 n 的数组 nums &#xff0c;返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的&#xff0c;并且给定的数组总是存在多数元素。 示例 1&#xff1a; 输入&#xff1a;nums [3,2,3] 输出&#xff1a;3 示例 …

OpenHarmony(鸿蒙南向)——平台驱动开发【ADC】

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 鸿蒙&#xff08;OpenHarmony&#xff09;南向开发保姆级知识点汇总~ 持续更新中…… 概述 功能简介 ADC&#xff08;Analog to Digital Converter&…

LOGO设计新革命:5款AI工具让你秒变设计大师(必藏)

大家好&#xff0c;我是Shelly&#xff0c;一个专注于输出AI工具和科技前沿内容的AI应用教练&#xff0c;体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具&#xff0c;拥抱AI时代的到来。 你是否曾因设计一个既独特又专业的LOGO而感…

JUC高并发编程2:Lock接口

1 synchronized 1.1 synchronized关键字回顾 synchronized 是 Java 中的一个关键字&#xff0c;用于实现线程间的同步。它提供了一种简单而有效的方式来控制对共享资源的访问&#xff0c;从而避免多个线程同时访问同一资源时可能出现的竞态条件&#xff08;race condition&am…

【Linux网络 —— 网络基础概念】

Linux网络 —— 网络基础概念 计算机网络背景网络发展 初始协议协议分层协议分层的好处 OSI七层模型TCP/IP五层(或四层)模型 再识协议为什么要有TCP/IP协议&#xff1f;什么是TCP/IP协议&#xff1f;TCP/IP协议与操作系统的关系所以究竟什么是协议&#xff1f; 网络传输基本流程…

【openwrt】 libubox组件——ustream

文章目录 ustream 核心数据结构struct ustreamstruct ustream_buf_liststruct ustream_bufstruct ustream_fd ustream 核心APIustream_fd_initustream_uloop_cbustream_fd_read_pendingustream_fill_read ustream_write_pendingustream_writeustream_fd_write ustream 应用示例…

Python画笔案例-059 绘制甩曲彩点动图

1、绘制甩曲彩点动图 通过 python 的turtle 库绘制 甩曲彩点动图,如下图: 2、实现代码 绘制甩曲彩点动图,以下为实现代码: """甩曲彩点动图.py """ import time import turtlecs = [red,orange,

CVPT: Cross-Attention help Visual Prompt Tuning adapt visual task

论文汇总 当前的问题 图1:在VTAB-1k基准测试上&#xff0c;使用预训练的ViT-B/16模型&#xff0c;VPT和我们的CVPT之间的性能和Flops比较。我们将提示的数量分别设置为1、10、20、50,100,150,200。 如图1所示&#xff0c;当给出大量提示时&#xff0c;VPT显示了性能的显著下降…

串口问题汇总:串口发送乱码,重定义使用printf ,输出顺序出错,缓存区思想,串口项目应用

1.c51使用串口出现顺序被覆盖的情况&#xff0c;也就是输出time 最后输出的却是te 这是因为你没有等待上一个数据发送就开始发送下一个数据就会导致数据篡位 2.c51想使用串口重定义使用printf 首先c51是自带stdio.h不需要像32那样点击 include lib选项&#xff0c;你直接改…

力扣958:判断二叉树是否为完全二叉树

给你一棵二叉树的根节点 root &#xff0c;请你判断这棵树是否是一棵 完全二叉树 。 在一棵 完全二叉树 中&#xff0c;除了最后一层外&#xff0c;所有层都被完全填满&#xff0c;并且最后一层中的所有节点都尽可能靠左。最后一层&#xff08;第 h 层&#xff09;中可以包含 …

体制内打工人收藏!5款AI写作工具,助你变成单位笔杆子~

对于初入体制内职场的新手或是日常任务繁重、难以抽身撰写文件的同事们&#xff0c;别再让加班的夜晚成为常态&#xff01;现在&#xff0c;就让我揭秘几个高效公文写作宝库&#xff0c;它们能助你迅速掌握公文写作的精髓&#xff0c;海量素材信手拈来&#xff0c;更有快速成文…

Elasticsearch、ik分词器、elasticsearch-head、Kibana的认识与安装

文章目录 elasticsearch安装elasticsearchIK中文分词器elasticsearch-headkibana elasticsearch Elasticsearch是一个基于Lucene的搜索服务器&#xff0c;也是属于NoSQL阵营的数据库。它提供了一个分布式多用户能力的全文搜索引擎&#xff0c;基于RESTful web接口提供给我们操…

2025年SEO策略:如何优化您的知识库?

如今很多人在遇到问题时都会求助于谷歌。谷歌已经成为提供解决方案不可或缺的工具。作为全球搜索引擎的巨头&#xff0c;拥有大量用户流量。这就是为什么确保您的产品和服务在谷歌搜索结果中排名靠前是至关重要的&#xff0c;如果您想获得更多的客户&#xff0c;SEO是一个非常关…

打造你的专属主题-VitePress保姆级教程

本篇为vitepress系列教程&#xff0c;在开始前&#xff0c;若还不了解vitepress的小伙伴可以看一下以往文章&#xff1a; 不敲一行代码&#xff01;助你快速搭建属于自己的官网博客&#xff01;-VitePress保姆级教程 文章目录 VitePress主题配置准备自定义主题配置标题配置图标…

如何用AI实现自动更新文章?(全自动更新网站)

AI的诞生确实给我们的生活和工作都带来了很大的改变&#xff0c;从我自身来讲&#xff0c;也渐渐习惯了遇到事情先问问AI&#xff0c;不管是翻译、专业性问题、PPT制作、总结写作这些&#xff0c;确实帮我迅速理清了思路&#xff0c;也可以有很多内容的借鉴。 作为一个业余爱好…

滑动窗口算法第一弹(长度最小的子数组,无重复字符的最长子串 最大连续1的个数III)

目录 前言 1. 长度最小的子数组 &#xff08;1&#xff09;题目及示例 &#xff08;2&#xff09;暴力解法 &#xff08;3&#xff09;优化 2. 无重复字符的最长子串 &#xff08;1&#xff09;题目及示例 &#xff08;2&#xff09;暴力解法 &#xff08;3&#xff…

深度学习:卷积神经网络CNN

目录 一、什么是卷积&#xff1f; 二、卷积神经网络的组成 1. 卷积层 2. 池化层 3. 激活函数 4. 全连接层 三、卷积神经网络的构造 四、代码实现 1.数据预处理 2.创建卷积神经网络 3.创建训练集和测试集函数 4.创建损失函数和优化器并进行训练 一、什么是卷积&…

Kivy,一个上天入地的 Python 库

大家好&#xff01;我是炒青椒不放辣&#xff0c;关注我&#xff0c;收看每期的编程干货。 一个简单的库&#xff0c;也许能够开启我们的智慧之门&#xff0c; 一个普通的方法&#xff0c;也许能在危急时刻挽救我们于水深火热&#xff0c; 一个新颖的思维方式&#xff0c;也许能…

USB 电缆中的信号线 DP、DM 的缩写由来

经常在一些芯片的规格书中看到 USB 的信号对是以 DP 和 DM 命名&#xff1a; 我在想&#xff0c;这些规格书是不是写错了&#xff0c;把 N 写成 M 了&#xff1f;DM 中的 M 到底是什么的缩写&#xff1f; 于是我找了一些资料&#xff0c;终于在《Universal Serial Bus Cables …