Skip to content

Commit ad21073

Browse files
author
dddssw
committed
组件库
1 parent 853b25f commit ad21073

File tree

1 file changed

+258
-0
lines changed

1 file changed

+258
-0
lines changed

configure/component.md

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
---
2+
outline: deep
3+
layout: doc
4+
---
5+
6+
ui组件库的特点
7+
* 可重用性,提高开发效率
8+
* 一致性,设计风格一致
9+
* 易用性,组件经过设计和测试,具有良好的用户体验
10+
* 定制性,允许开发人员按照自己的需求和设计风格进行定制
11+
12+
## 目录结构
13+
1. Element Plus 的根目录
14+
15+
.circleci:用于 Circle CI 自动化部署的配置文件。
16+
.github:存放 GitHub 的配置文件,如 issue、PR 模板等。
17+
.husky:用于 Git 钩子的配置。
18+
.vscode:为 VSCode 提供的配置文件。
19+
docs:使用 VitePress 生成的文档配置。
20+
internal:内部工具和脚本。
21+
play:测试项目。
22+
scripts:构建脚本。
23+
typings:类型定义文件。
24+
packages:核心目录,包含所有功能包 。
25+
26+
2. packages 目录结构
27+
packages 是 Element Plus 的核心目录,包含多个功能包,每个包都具有清晰的结构。以下是主要包的结构和功能:
28+
29+
2.1 components
30+
功能:存放所有 UI 组件的源码。
31+
2.2 utils
32+
2.3 theme-chalk
33+
提供组件的样式文件(SCSS)。
34+
2.4 element-plus
35+
对外暴露的包,是组件库的统一出口。导出所有组件和功能。
36+
index.ts:入口文件,用于集中注册组件。
37+
2.5 hooks
38+
存放自定义 hook 函数。
39+
2.7 directives
40+
2.8 test-utils
41+
功能:测试工具和辅助函数。
42+
2.9 constants
43+
功能:存放公用常量。
44+
45+
3.组件 目录结构
46+
3.1 src包含.vue,style文件
47+
3.2 index.ts 访问组件的入口文件
48+
## 使用monorepo构建
49+
适用于大型项目,和具有多个相互依赖部分的application
50+
51+
搭建好目录之后,他们都变成了独立的包.要使他们可以相互调用,需要在根目录下按照依赖即可
52+
53+
例如 `pnpm i @template/components@workspace:* -w`
54+
55+
## 如何实现完整引入
56+
```js
57+
import ElementPlus from 'element-plus'
58+
59+
const app = createApp(App)
60+
app.use(ElementPlus)
61+
```
62+
packages下的element-plus是组件库的统一出口
63+
64+
ElementPlus是一个插件,他实际上是一个包含install的对象
65+
66+
他是这么生成的
67+
68+
```js
69+
//packages/element-plus
70+
makeInstaller([...Components])
71+
export const makeInstaller = (components: Plugin[] = []) => {
72+
const install = (app: App, options?: ConfigProviderContext) => {//这里实现了第一个install方法
73+
if (app[INSTALLED_KEY]) return
74+
75+
app[INSTALLED_KEY] = true
76+
components.forEach((c) => app.use(c))//这里会用到下面注入的install
77+
78+
if (options) provideGlobalConfig(options, app, true)
79+
}
80+
81+
return {
82+
version,
83+
install,
84+
}
85+
}
86+
87+
//packages/components/*
88+
//对于每个组件,导出的时候使用withInstall方法处理一下,作用是注入一个install方法,返回这个组件而已
89+
export const ElAffix: SFCWithInstall<typeof Affix> = withInstall(Affix)
90+
export const withInstall = <T, E extends Record<string, any>>(
91+
main: T,
92+
extra?: E
93+
) => {
94+
;(main as SFCWithInstall<T>).install = (app): void => {
95+
for (const comp of [main, ...Object.values(extra ?? {})]) {
96+
app.component(comp.name, comp)
97+
}
98+
}
99+
100+
if (extra) {
101+
for (const [key, comp] of Object.entries(extra)) {
102+
;(main as any)[key] = comp
103+
}
104+
}
105+
return main as SFCWithInstall<T> & E
106+
}
107+
```
108+
## 实现按需手动导入
109+
因为每个组件都被导出了,所有只需要`export * from '@element-plus/components'`即可,就可以被引用了
110+
111+
样式>>>>>>>>>wait
112+
113+
## 实现按需自动加载
114+
只需要添加两个插件`unplugin-vue-componentsunplugin-auto-import`
115+
一个负责自动扫描和注册vue组件,包括流行ui库以及src/components的所有组件
116+
117+
另一个负责导入流行库的api
118+
119+
## css
120+
使用的是BEM命名规则,组件用-连接,元素用__连接,类型用--连接,状态用is-xx表示
121+
122+
编写组件时,如果都是手写类名,写法繁琐,可以把BEM命名规则封装风函数,动态生成类名
123+
124+
```js
125+
export const defaultNamespace = 'el'
126+
const statePrefix = 'is-'
127+
128+
export const useGetDerivedNamespace = (//这个函数可以更改命名空间方便二次开发
129+
namespaceOverrides?: Ref<string | undefined>
130+
) => {
131+
const derivedNamespace =
132+
namespaceOverrides ||
133+
(getCurrentInstance()
134+
? inject(namespaceContextKey, ref(defaultNamespace))
135+
: ref(defaultNamespace))
136+
const namespace = computed(() => {
137+
return unref(derivedNamespace) || defaultNamespace
138+
})
139+
return namespace
140+
}
141+
142+
const _bem = (
143+
namespace: string,
144+
block: string,
145+
blockSuffix: string,
146+
element: string,
147+
modifier: string
148+
) => {
149+
let cls = `${namespace}-${block}`
150+
if (blockSuffix) {
151+
cls += `-${blockSuffix}`
152+
}
153+
if (element) {
154+
cls += `__${element}`
155+
}
156+
if (modifier) {
157+
cls += `--${modifier}`
158+
}
159+
return cls
160+
}
161+
162+
export const useNamespace = (
163+
block: string,
164+
namespaceOverrides?: Ref<string | undefined>
165+
) => {
166+
const namespace = useGetDerivedNamespace(namespaceOverrides)
167+
const b = (blockSuffix = '') =>
168+
_bem(namespace.value, block, blockSuffix, '', '')
169+
const e = (element?: string) =>
170+
element ? _bem(namespace.value, block, '', element, '') : ''
171+
const m = (modifier?: string) =>
172+
modifier ? _bem(namespace.value, block, '', '', modifier) : ''
173+
const be = (blockSuffix?: string, element?: string) =>
174+
blockSuffix && element
175+
? _bem(namespace.value, block, blockSuffix, element, '')
176+
: ''
177+
const em = (element?: string, modifier?: string) =>
178+
element && modifier
179+
? _bem(namespace.value, block, '', element, modifier)
180+
: ''
181+
const bm = (blockSuffix?: string, modifier?: string) =>
182+
blockSuffix && modifier
183+
? _bem(namespace.value, block, blockSuffix, '', modifier)
184+
: ''
185+
const bem = (blockSuffix?: string, element?: string, modifier?: string) =>
186+
blockSuffix && element && modifier
187+
? _bem(namespace.value, block, blockSuffix, element, modifier)
188+
: ''
189+
const is: {
190+
(name: string, state: boolean | undefined): string
191+
(name: string): string
192+
} = (name: string, ...args: [boolean | undefined] | []) => {
193+
const state = args.length >= 1 ? args[0]! : true
194+
return name && state ? `${statePrefix}${name}` : ''
195+
}
196+
197+
// for css var
198+
// --el-xxx: value;
199+
const cssVar = (object: Record<string, string>) => {
200+
const styles: Record<string, string> = {}
201+
for (const key in object) {
202+
if (object[key]) {
203+
styles[`--${namespace.value}-${key}`] = object[key]
204+
}
205+
}
206+
return styles
207+
}
208+
// with block
209+
const cssVarBlock = (object: Record<string, string>) => {
210+
const styles: Record<string, string> = {}
211+
for (const key in object) {
212+
if (object[key]) {
213+
styles[`--${namespace.value}-${block}-${key}`] = object[key]
214+
}
215+
}
216+
return styles
217+
}
218+
219+
const cssVarName = (name: string) => `--${namespace.value}-${name}`
220+
const cssVarBlockName = (name: string) =>
221+
`--${namespace.value}-${block}-${name}`
222+
223+
return {
224+
namespace,
225+
b,
226+
e,
227+
m,
228+
be,
229+
em,
230+
bm,
231+
bem,
232+
is,
233+
// css
234+
cssVar,
235+
cssVarName,
236+
cssVarBlock,
237+
cssVarBlockName,
238+
}
239+
}
240+
```
241+
```js
242+
//拿affix组件举例
243+
import { useNamespace } from '@element-plus/hooks'
244+
const ns = useNamespace('affix')
245+
<div ref="root" :class="ns.b()" :style="rootStyle"></div>
246+
```
247+
248+
### :root
249+
:root 主要用于​​定义全局 CSS 变量,通过var读取全局属性
250+
```css
251+
:root {
252+
--ep-c-bg-row: #f9fafc;
253+
}
254+
.row-bg {
255+
padding: 10px 0;
256+
background-color: var(--ep-c-bg-row);
257+
}
258+
```

0 commit comments

Comments
 (0)