这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战
基础组件: Button
前言
从这里开始,系列就正式进入到组件开发了,按照前文关于组件分类的描述,我们将从
基础组件开始,一步步搭建起一个项目组件库在系列的最后,将阐述如何从项目中抽出组件,打包成一个独立的组件库。
基础组件当中,最常用也最不起眼的当属Button、Mask这些常常作为绿叶的组件了。
而本系列既然是从0到1去写,那么自然先从简单的开始,红花艳不艳,就看绿叶靓不靓了。
那么为什么从Button开始,而不从看起来更简单的Mask开始呢?
自然是有原因的?
待明日更新了Mask的文章,就知道Mask这个组件的思考点了。
从文件夹开始
如何打包组件库这一步放在最后来讲,作为到1的结尾。整个文章的开发背景是基于项目中的,但是也需要为最后的打包做好准备。
文件结构如下,
root/src
|
|-components
|
|-Button
|
|-button.vue // 主体文件,因为使用setup-script方法书写,没有name属性,文件名即name,慎重命名
|-index.js // 导出
布局代码
因为样式的东西比较随心,可以自由发挥,所以在文中,将更注重功能的Vue3语法以及组件功能芝士点的分享。
前面提过,结构部分会使用pug来完成,但其本质和html差别不大,特色部分会做讲解。
<template lang="pug">
<!-- 使用pug语法必须加这句,否则会报错 -->
block content
button(
class="yx-btn"
:class="className"
:disbaled="isDisabled" // 是否禁用
)
span(
v-if="loading"
class="yx-load" // 不需要loading可无视
)
span(
class="yx-btn-content"
:style="style"
)
i( // icon部分 可以不要,和下面的span是平级,请注意
v-if="icon !== ''"
:class="icon"
)
span(v-if="$slots.default") // 展示传递的内容部分
slot
</template>
结构部分如上,是我的个人写法,实践时,都可以按照个人的需求和想法去完成这一部分。
说说需要注意的几个点:
1、我们使用中一般有实心、线性、圆角、圆、有无图标等可能,通过属性控制
2、主题图标,如常见的success、warning、danger等类型
3、尺寸,当然这个是样式的范畴,不多考虑
4、是否禁用不多说,也简单
逻辑部分
按钮的逻辑部分不多,主要判断是否需要显示指定类型的样式、是否显示图标。
<script setup>
import { computed, defineProps, toRefs } from "@vue/runtime-core";
const props = defineProps({ // 定义props
type: { // 控制按钮主题
type: String,
default: 'default',
validator: value => [
'success',
'primary',
'warning',
'info',
'danger',
'default',
'text'
].includes(value)
},
size: { // 控制按钮尺寸,默认md middle 中等
type: String,
default: 'md',
validator: value => ['lg','sm','md'].includes(value)
},
icon: String, // 是否显示图标
plain: Boolean, // 线性
round: Boolean, // 圆角
clrcle: Boolean, // 圆
block: Boolean, // 块级按钮,display: block; 独占整行
disabled: Boolean, // 禁用
loading: Boolean // loading
})
// 根据用户的type值添加对应的类名,自定义即可,不用强求
const useClass = ({props, loading}) => {
return computed( () => {
return [
props.type && `yx-btn-${props.type}`,
props.size !== '' || props.size ? `yx-btn-${props.size}` : '',
{
'is-plain': props.plain,
'is-round': props.round,
'is-circle': props.circle,
'is-block': props.block,
disabled: props.disabled
},
loading.value && 'yx-btn-loading'
]
})
}
const isDisabled = computed(() => { props.loading || props.disabled })
const { loading, icon} = toRefs(props);
const className = useClass({
props,
loading,
icon
})
// 给loading用的, 根据需求可选部分。
const style = computed(() => {
return props.loading ? {opacity: '0', transform: 'scale(2.2)'} : {};
})
</script>
逻辑部分就是这样了, 最简单的按钮可以没有任何逻辑,但是那样就可以直接用button标签了。
而这个按钮组件基本也就就是常规的部分和一些样式的定制。 其本身没有过多的深入到Vue3的一些功能。
不过既然是从0开始,肯定是从简单的开始慢慢深入了。
小伙伴们自己开发组件时,在组件本身的逻辑这一块基本都是很主观的部分,后面对于一些没什么逻辑要求的组件都会省略这一部分,只分享一些比较有特色的功能。
导出组件
import ele from './button.vue'
// ele.name: 组件名
// 因为这里是用setup-script 没有name属性,所以默认以文件名做name,但是可以自定义。
ele.install = function(app){ // 这里的app参数在引入组件时自动调用install 传入Vue实例作为参数
app.component(ele.name, ele);
app.component('yxButton', ele); // 两者二选一, 自定义组件名写法
}
export default ele;
写完这里,就可以在main.js或者需要的界面中通过import yxButton from '@/src/components/button/index'导入使用了。
是有点麻烦,目前还只是一只刚出生的组件,最后的最后我们将会搞定打包组件库,就可以如其他开源组件库一样按需引入了。
写在最后
本文的组件是最最最简单的Button的,主要的部分在于最后的把组件导出挂载在Vue实例上。整体和Vue2差别不大。