这是我参与「第五届青训营 」伴学笔记创作活动的第 五 天
一、button组件结构
文件路径(packages\components\button)
_tests_文件夹是装着button.test.tsx,是用来针对button组件进行测试的
style文件夹是组件的样式
index.ts主要负责把组件导出(export)出去
src则是装载主要核心代码的文件夹
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作为实现组件库必看的源码库之一,还是有非常多的编程思想可以去学习和效仿。