Vue3从0到1组件开发-基础组件:Button

2,769 阅读3分钟

这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战

基础组件: Button

前言

从这里开始,系列就正式进入到组件开发了,按照前文关于组件分类的描述,我们将从基础组件开始,一步步搭建起一个项目组件库

在系列的最后,将阐述如何从项目中抽出组件,打包成一个独立的组件库。

基础组件当中,最常用也最不起眼的当属ButtonMask这些常常作为绿叶的组件了。

而本系列既然是从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差别不大。