CSS 架构
结构
bash
│ ├── ui
│ │ ├── public
│ │ ├── packages(最后把要打包的文件都放到这里面)
│ │ ├── command
│ │ ├── lib (打包后生成的)
│ │ ├── vite.config.ts
│ │ ├── package.json
│ │ ├── packages
│ │ │ ├── chooseButton
│ │ │ ├── hooks
│ │ │ ├── utils
│ │ │ ├── styles
│ │ │ ├── index.ts
│ │ │ ├── vue.d.ts
│ │ ├── src
│ │ │ ├── hooks
│ │ │ ├── styles
│ │ │ │ ├── index.scss
│ │ │ │ ├── chooseButton
│ │ │ │ │ ├── index.scss命名规范
- css 命名规范遵循
BEM规范
BEM 是 Block(块)、Element(元素)、Modifier(修饰符) 的缩写。它是一种由 Yandex 团队提出的 CSS 命名方法论。
遵循 BEM 规范的主要目的是:通过创建清晰、严格关联的命名规则,使代码更具可读性、可复用性,并避免样式冲突。
Block(块)
定义:块是一个独立的实体,它本身具有意义,而且是页面结构的抽象组件。
特点:
可以嵌套(例如,一个“头部”块里可能包含一个“Logo”块)。
不依赖于页面上的其他块或元素(即你把它放在页面的任何位置,它的外观和行为都应该是一样的)。
命名:使用类名,通常是一个单词或短语。
- 示例:
.card,.menu,.btn,.header
Element(元素)
定义:元素是块的组成部分,它没有独立的含义,且在语义上与块相关联。
特点:
依赖于块(不能脱离块单独使用)。
命名:块名 + 双下划线 __ + 元素名。
- 示例:
.card__title,.menu__item,.btn__text,.header__logo
Modifier(修饰符)
定义:修饰符用于改变块或元素的外观、行为或状态。
特点:
它是可选的。
命名:块名/元素名 + 双连字符 -- + 修饰符名。
- 示例:
.card--featured,.menu--vertical,.btn--disabled,.header--dark
命名规则图解
假设我们要写一个搜索框组件
- Block: .search-form (搜索表单块)
- Element: .search-form__input (输入框元素)
- Element: .search-form__button (按钮元素)
- Modifier: .search-form--theme-dark (深色主题修饰符)
创建生成class文件
- hooks/usernamespace/index.ts
ts
// 默认的命名空间
export const defaultNamespace = "Y";
/*
* 通过bem的方法生成所有的命名规则
*/
const _bem = (
namespace: string,
block: string,
element?: string,
modifierAttr?: string,
modifierValue?: string,
): string => {
// block
let classname = `${namespace}-${block}`; // 结果Y-Buton
// element
element && (classname += `__${element}`); // 结果Y-Button__icon
// modifier
modifierAttr && (classname += `--${modifierAttr}`); // 结果Y-Button--disabled
// modifierValue
modifierValue && (classname += `_${modifierValue}`); // 结果Y-Button--disabled_disabled
return classname;
};
export const useNamespace = (block: string) => {
// 默认
const namespace = defaultNamespace;
// block
const b = () => _bem(namespace, block);
// element
const e = (element: string | undefined) =>
element ? _bem(namespace, block, element) : "";
// modifier
const m = (
modifierAttr: string | undefined,
modifierValue?: string | undefined,
) =>
modifierAttr ? _bem(namespace, block, "", modifierAttr, modifierValue) : "";
// is
const is = (name: string, state: boolean) => {
return name && state ? `is-${name}` : "";
};
return {
is,
namespace,
b,
e,
m,
};
};使用
vue
<template>
<div>
<button
:class="[
ns.b(),
ns.m(props.type),
ns.m('size', props.size),
ns.is('round', props.round),
ns.is('disabled', props.disabled),
ns.is('text', props.text),
ns.is('link', props.link),
ns.is('block', props.block),
ns.is('border', props.border),
ns.is('circle', props.circle),
]"
:disabled="disabled"
@click="handleClick"
>
<span>测试1</span>
</button>
</div>
</template>
<script setup lang="ts">
import { onMounted } from "vue";
import { useButton, useNamespace } from "../../../hooks/index";
const props = defineProps({
type: {
type: String,
default: "",
},
text: {
type: Boolean,
default: false,
},
round: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
link: {
type: Boolean,
default: false,
},
block: {
type: Boolean,
default: false,
},
border: {
type: Boolean,
default: false,
},
size: {
type: String,
default: "", // 小small,中 就不用写 大large
},
circle: {
type: Boolean,
default: false,
},
});
const ns = useNamespace("button");
console.log("useNameSpace", ns.b());
const { handleClick } = useButton();
onMounted(() => {
console.log("按钮组件挂载");
});
</script>