vue3基础组件开发-button(按钮组件)
前言
使用了vue3有很长一段时间了,写了很多的基础组件在自己使用,整理一下(尽量使用最简单的方式实现),当做对自己知识的梳理。
tips:button组件可以说是,几乎每个前端必定会写的组件之一,所以本篇更多的是对思路的梳理。
技术栈
vue3 + tailwindcss + ts
页面开发
-
html结构
<-- 按钮主体 --> <button> <-- 左边logo --> <i></i> <slot> {{ title }} </slot> <-- 右边logo --> <i></i> </button>
一个button的组件的页面开发可以说就到这里了,剩下的无非就是调整button的样式了
逻辑开发
-
根据type类型决定button的样式
- 我们使用组件库的时候经常会看到这样的用法,通过在组件上传一个字符串控制button的样式
<el-button type="primary">Primary</el-button>
- 实现上面功能的主要逻辑如下:
- 通过props获取到type的值
- 建立一个map对象
- 在map里面存对应type数据
- 通过计算属性获取到map返回的值
- 通过动态class插入
interface Props { type?: string } const props = withDefaults(defineProps<Props>(), { type: '', }) const colorMap = new Map() .set('', '') .set('default', 'border') .set('primary', 'border bg-[#409EFF]') .set('success', 'border bg-[#67C23A]') .set('info', 'border bg-[#909399]') .set('warning', 'border bg-[#E6A23C]') .set('danger', 'border bg-[#F56C6C]') const typeColor = computed(() => colorMap.get(props.type))
- 我们使用组件库的时候经常会看到这样的用法,通过在组件上传一个字符串控制button的样式
-
自定义样式
在大多中小公司的前端研发中,整个设计没有形成整体化;或者说是,在上层(老板)的干预下,设计体系今天抄一下这个,明天抄一下那个;所以,类似很多组件库中流行的预设模板之类的方式行不通。
举个例子:比如说我固定了圆角是4px,或者设置了大中小三个样式,4px、8px、12px,但是设计不按照这样的圆角去设计,搞个5px、2px或者其它圆角。
这样的情况,通常的处理方式是,通过覆盖css的方式去实现,比如说我用了element组件库,那么我就覆盖element组件,在vue中可能还会经常用到css深度选择器区覆盖。
当然,随着技术的发展,组件库通常有覆盖样式的方案,比如说,通过一个 $xxx 的变量去改变整个的颜色之类的东西。但是,有一个问题是,你必须要用这个组件库,或者说你还要学习如何去配置。
那么,在vue3中,可以用另外一种方式去覆盖样式,也就是透传 Attributes 来实现。毕竟,在中国,组件库最少几十个,但是流行的前端开发框架就两个,一个vue,一个react,因为上手难度的原因,在中小公司,你接触到的基本都是vue。
透传 Attributes使用如下,以本篇文章的button按钮为例:
- 子组件本身不设置过多的预设样式模板
- 在父组件中引入子组件
- 直接在被引入的子组件身上写class样式
- 如下图所示,直接写的样式,会透传到子组件身上,并且同样的样式会覆盖子组件(根据css的渲染顺序)
-
显示icon
- 我们平常封装组件的木的是为了什么呢?是为了复用,所以在现在vue3的技术中,如果没有设计各种给按钮加icon的需求,那么可以说,在使用透传之后,可以不必要封装button组件;大多数的设计师的设计里,你封装了css,用的时候还是要再写一遍css。
- 所以,button组件在我的理解中,更多的是封装各种icon用的;因为,封装了,确实能够少写很多的 i 标签。
- 具体思路是:
- 在button中间放个插槽
- 两边各放一个i标签
- 给props传参加上两个参数,left和right
- 给i标签加上判断,哪个有值就显示哪个
- 中间的插槽是为了,你自定义标签使用
- 整个方案结合iconfont最佳食用
<template> <button :class="typeColor"> <i v-if="props.left"></i> <slot> 按钮 </slot> <i v-if="props.right"></i> </button> </template> <script setup lang="ts"> interface Props { type?: string left?: string right?: string } const props = withDefaults(defineProps<Props>(), { type: '', left: '', right: '', }) const colorMap = new Map() .set('', '') .set('default', 'border') .set('primary', 'border bg-[#409EFF]') .set('success', 'border bg-[#67C23A]') .set('info', 'border bg-[#909399]') .set('warning', 'border bg-[#E6A23C]') .set('danger', 'border bg-[#F56C6C]') const typeColor = computed(() => colorMap.get(props.type)) </script>
尾声
很多人认为重复写组件是造轮子,确实,市面上有很多非常成熟非常好的组件库提供使用。但是,我想说的是,前端最快的成长路径就是造轮子,造轮子从组件库开始。而且,你不知道你会遇到什么设计或者产品,你会发现,市面上没有哪一个的组件库是完全合用的,还是需要二次开发(这也是为啥网上很多二次封装xxx组件的文章很多的原因之一),或者自己写组件。
水平有限,如有错漏之处,欢迎大佬指正。
转载自:https://juejin.cn/post/7205567237239210044