浅读一下element-plus源码 -- ElButton

写在前面

终于开始阅读element-plus的源码啦,不知道能坚持多久,希望自己继续加油啦,此篇是对我自己来说觉得有帮助的地方,如果知识点太过简单,见谅嘞。 源码对我觉得最有用的地方的话就是在:

  • 使用type限制String类型的使用,分为编译时和运行时
  • 使用provide/inject依赖注入实现统一化管理

一. 源码

克隆的是dev这个分支,最新的那个好多文件,让人害怕哈哈哈

js 复制代码
<template>
  <button
    :class="[
      'el-button',
      type ? 'el-button--' + type : '',
      buttonSize ? 'el-button--' + buttonSize : '',
      {
        'is-disabled': buttonDisabled,
        'is-loading': loading,
        'is-plain': plain,
        'is-round': round,
        'is-circle': circle
      }
    ]"
    :disabled="buttonDisabled || loading"
    :autofocus="autofocus"
    :type="nativeType"
    @click="handleClick"
  >
    <i v-if="loading" class="el-icon-loading"></i>
    <i v-if="icon && !loading" :class="icon"></i>
    <span v-if="$slots.default"><slot></slot></span>
  </button>
</template>

<script lang='ts'>
import { computed, inject, defineComponent } from 'vue'
import { useGlobalConfig } from '@element-plus/utils/util'
import { isValidComponentSize } from '@element-plus/utils/validators'
import { elFormKey, elFormItemKey } from '@element-plus/form'

import type { PropType } from 'vue'
import type { ElFormContext, ElFormItemContext } from '@element-plus/form'

type IButtonType = PropType<'primary' | 'success' | 'warning' | 'danger' | 'info' | 'text' | 'default'>
type IButtonNativeType = PropType<'button' | 'submit' | 'reset'>

interface IButtonProps {
  type: string
  size: string
  icon: string
  nativeType: string
  loading: boolean
  disabled: boolean
  plain: boolean
  autofocus: boolean
  round: boolean
  circle: boolean
}

type EmitFn = (evt: Event) => void

export default defineComponent({
  name: 'ElButton',

  props: {
    type: {
      type: String as IButtonType,
      default: 'default',
      validator: (val: string) => {
        return [
          'default',
          'primary',
          'success',
          'warning',
          'info',
          'danger',
          'text',
        ].includes(val)
      },
    },
    size: {
      type: String as PropType<ComponentSize>,
      validator: isValidComponentSize,
    },
    icon: {
      type: String,
      default: '',
    },
    nativeType: {
      type: String as IButtonNativeType,
      default: 'button',
      validator: (val: string) => {
        return ['button', 'submit', 'reset'].includes(val)
      },
    },
    loading: Boolean,
    disabled: Boolean,
    plain: Boolean,
    autofocus: Boolean,
    round: Boolean,
    circle: Boolean,
  },

  emits: ['click'],

  setup(props, ctx) {
    const $ELEMENT = useGlobalConfig()

    const elForm = inject(elFormKey, {} as ElFormContext)
    const elFormItem = inject(elFormItemKey, {} as ElFormItemContext)

    const buttonSize = computed(() => {
      return props.size || elFormItem.size || $ELEMENT.size
    })
    const buttonDisabled = computed(() => {
      return props.disabled || elForm.disabled
    })

    //methods
    const handleClick = evt => {
      ctx.emit('click', evt)
    }

    return {
      buttonSize,
      buttonDisabled,
      handleClick,
    }
  },
})
</script>

文档是最新版的,所以还有一些属性上面的代码中是没有的

文档介绍在这里:element-plus.org/zh-CN/compo...

很简单的一个组件,props,自定义事件,外加使用provide/inject实现按钮大小随表单或者全局配置大小改变而变化

二、有收获的地方

  1. 自定义type类型加断言实现字符串类型数据编译时验证,validator验证实现运行时验证
js 复制代码
...
type IButtonType = PropType<'primary'|'success'|'warning'|'danger'|'text'|'default'>
...
props: {
    type: {
      type: String as IButtonType,
      default: 'default',
      validator: (val: string) => {
        return [
          'default',
          'primary',
          'success',
          'warning',
          'info',
          'danger',
          'text',
        ].includes(val)
      },
    },
    ...
}
  • 对于String as IButtonType这,如果写的字符串不是IButtonType类型,那么编译器会报错(可以运行)
  • 而对于validator来说,如果只写了这个的情况下,那么当写的字符串不是IButtonType类型时,编译器不会报错,当运行后会有警告

自我感觉来看,第一种方式会更好些,非常明显的提示,而且会有代码提示,而第二种写完了才知道,还需要去看validator的情况才知道为啥错了,然后个人觉得两种都用有些多余,只用自定义type的类型就非常好了

  1. 使用provide/inject依赖注入实现统一化管理
js 复制代码
import { useGlobalConfig } from '@element-plus/utils/util'
import { elFormKey, elFormItemKey } from '@element-plus/form'
...
const $ELEMENT = useGlobalConfig()

const elForm = inject(elFormKey, {} as ElFormContext)
const elFormItem = inject(elFormItemKey, {} as ElFormItemContext)

const buttonSize = computed(() => {
  return props.size || elFormItem.size || $ELEMENT.size
})
const buttonDisabled = computed(() => {
  return props.disabled || elForm.disabled
})

这里通过依赖注入的方式实现了让按钮在没有设置大小的情况下遵循表单的大小(若有,不然就是全局配置的大小),以及设置按钮是否可用

因此这里可以看出我们在使用ElButton时,表单的大小和是否禁用状态是会影响ElButton状态的,当然ElButton它有自己的想法那就没办法啦。

这里关于provide/inject的使用推荐:juejin.cn/post/684490...

自我感觉关于页面主题切换这个功能用这个来写就非常不错,不过平时开发也确实不多,还是大佬说的用于组件开发比较合适。

三. 对开发的帮助

  1. 如果想要写的组件是固定类型值类型的字符串,那就设置定义一个type
  2. 使用开源组件的时候,注意祖宗组件对子组件的影响,可能源码里使用了provide/inject,不要到时候一脸懵逼
相关推荐
Mr Xu_17 小时前
告别冗长 switch-case:Vue 项目中基于映射表的优雅路由数据匹配方案
前端·javascript·vue.js
前端摸鱼匠17 小时前
Vue 3 的toRefs保持响应性:讲解toRefs在解构响应式对象时的作用
前端·javascript·vue.js·前端框架·ecmascript
未来之窗软件服务19 小时前
未来之窗昭和仙君(六十五)Vue与跨地区多部门开发—东方仙盟练气
前端·javascript·vue.js·仙盟创梦ide·东方仙盟·昭和仙君
phltxy20 小时前
Vue 核心特性实战指南:指令、样式绑定、计算属性与侦听器
前端·javascript·vue.js
Byron070721 小时前
Vue 中使用 Tiptap 富文本编辑器的完整指南
前端·javascript·vue.js
Byron07071 天前
从 0 到 1 搭建 Vue 前端工程化体系:提效、提质、降本实战落地
前端·javascript·vue.js
zhengfei6111 天前
【AI平台】- 基于大模型的知识库与知识图谱智能体开发平台
vue.js·语言模型·langchain·知识图谱·多分类
徐小夕@趣谈前端1 天前
Web文档的“Office时刻“:jitword共建版2.0发布!让浏览器变成本地生产力
前端·数据结构·vue.js·算法·开源·编辑器·es6
董世昌411 天前
深度解析浅拷贝与深拷贝:底层逻辑、实现方式及实战避坑
前端·javascript·vue.js
扶苏10021 天前
vue使用event.dataTransfer实现A容器数据拖拽复制到到B容器
前端·vue.js·chrome