[ Element plus源码笔记二(button组件1) | 青训营笔记]

246 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 五 天

一、button组件结构

文件路径(packages\components\button)

捕获.JPG

_tests_文件夹是装着button.test.tsx,是用来针对button组件进行测试的

style文件夹是组件的样式

index.ts主要负责把组件导出(export)出去

src则是装载主要核心代码的文件夹

捕获.JPG

button.ts和instance.ts主要定义了几个组件全局会用到的类型

二、button.vue

文件路径(packages\components\button\src\button.vue)

1.第一部分:命名空间(详情参考element plus文档:element-plus.gitee.io/zh-CN/compo…

用法:<el-button type="info" round></el-button>

ns.b()的效果就是"el-button" ns.b('my')就是"el-button-my"

<template>
  <button
    ref="_ref"
    :class="[
      ns.b(),
      ns.m(_type),
      ns.m(_size),
      ns.is('disabled', _disabled),
      ns.is('loading', loading),
      ns.is('plain', plain),
      ns.is('round', round),
      ns.is('circle', circle),
      ns.is('text', text),
      ns.is('link', link),
      ns.is('has-bg', bg),
    ]"
    :aria-disabled="_disabled || loading"
    :disabled="_disabled || loading"
    :autofocus="autofocus"
    :type="nativeType"
    :style="buttonStyle"
    @click="handleClick"
  >
  ///...
  </button>
</template>

<script lang="ts" setup>
import { useNamespace } from '@element-plus/hooks'
//...

const ns = useNamespace('button')
//...

首先先看位于'@element-plus/hooks'的{ useNamespace } element plus采用的是“BEM命名”,BEM是Block(块)、Element(元素)、Modifier(修饰符)的简写,是一种组件化的 CSS 命名方法和规范

BEM命名规则

  • 块名称为其元素和修饰符定义了命名空间。
  • 块名称与元素名称之间用双连字符--分隔。
  • 块名称与修饰符或元素与修饰符之间用双下划线__分隔。
  • 命名一般使用小写字母。
  • 单词之间可以使用-分隔。

_bem的作用就是像这个模板字符串:

${namespace}-${block}-${blockSuffix}?__${element}?--${modifier}?

然后让下面的buesNamespace的b(),e()等等去填充

//blockSuffix默认设为空,如果传入了值就对应填入blockSuffix。_bem()填入对应的值
  const b = (blockSuffix = '') =>
    _bem(namespace.value, block, blockSuffix, '', '')

其他的都大同小异

is()的作用就是填入组件不是组件必须的属性,合成效果就是is-disable等等。一般这类属性默认是不添加的,会用作特殊的情形。使用上就是直接 <el-button type="primary" loading>Loading</el-button>,其中的loading属性就是用is()去实现的。而像是

Tips:uesGlobalConfig的是使用了getCurrentInstance()获取当前组件的实例,主要为了下面的namespace.value,获取到组件实例的命名空间,像是element plus所用的"el-"

import { useGlobalConfig } from '../use-global-config'

export const defaultNamespace = 'el'
const statePrefix = 'is-'

const _bem = (
  namespace: string,
  block: string,
  blockSuffix: string,
  element: string,
  modifier: string
) => {
  let cls = `${namespace}-${block}`
  if (blockSuffix) {
    cls += `-${blockSuffix}`
  }
  if (element) {
    cls += `__${element}`
  }
  if (modifier) {
    cls += `--${modifier}`
  }
  return cls
}

export const useNamespace = (block: string) => {
  const namespace = useGlobalConfig('namespace', defaultNamespace)
  const b = (blockSuffix = '') =>
    _bem(namespace.value, block, blockSuffix, '', '')
  const e = (element?: string) =>
    element ? _bem(namespace.value, block, '', element, '') : ''
  const m = (modifier?: string) =>
    modifier ? _bem(namespace.value, block, '', '', modifier) : ''
  const be = (blockSuffix?: string, element?: string) =>
    blockSuffix && element
      ? _bem(namespace.value, block, blockSuffix, element, '')
      : ''
  const em = (element?: string, modifier?: string) =>
    element && modifier
      ? _bem(namespace.value, block, '', element, modifier)
      : ''
  const bm = (blockSuffix?: string, modifier?: string) =>
    blockSuffix && modifier
      ? _bem(namespace.value, block, blockSuffix, '', modifier)
      : ''
  const bem = (blockSuffix?: string, element?: string, modifier?: string) =>
    blockSuffix && element && modifier
      ? _bem(namespace.value, block, blockSuffix, element, modifier)
      : ''
  const is: {
    (name: string, state: boolean | undefined): string
    (name: string): string
  } = (name: string, ...args: [boolean | undefined] | []) => {
    const state = args.length >= 1 ? args[0]! : true
    return name && state ? `${statePrefix}${name}` : ''
  }
//...

  return {
    namespace,
    b,
    e,
    m,
    be,
    em,
    bm,
    bem,
    is,
    // css
  }
}

export type UseNamespaceReturn = ReturnType<typeof useNamespace>

以上就是关于button组件以及绝大部分组件使用的命名空间的原理,详细的用法可以去使用element plus去体会然后结合源码再去细看,可以去细看一下如何获取组件实例的相关值,is()是怎么实现的,为什么这么写。还有相关的类型是怎么定义的,ts的内容本篇文章也没有详细展开,element plus作为实现组件库必看的源码库之一,还是有非常多的编程思想可以去学习和效仿。