Bem设计
前置概念
BEM,全称Block Element Modifier,是一种前端编码规范,由Yandex团队提出,主要用于命名HTML和CSS中的类和选择器。BEM的核心思想是将页面拆分成一个个独立的富有语义的块(blocks),以提升开发效率并有利于代码复用。
在具体的命名规则中,BEM包括三部分:块(block)、元素(element)、修饰符(modifier)。其中,“-”仅作为连字符使用,用于连接块或子元素的多单词。这种命名方式旨在提供一种一致的方式来组织和命名代码,使其易于理解、扩展和维护。
此外,BEM也是一种保证CSS样式不冲突的方法。通过使用组件名、元素名和修饰器名来命名元素,可以避免样式与外部组件的冲突。总体来说,BEM规范对于提高代码质量、降低维护成本以及增强团队协作有着显著的作用。
createBem介绍
但每次都要长长的class类名又相对麻烦,修饰符上的书写也不是那么的方便。因此,createBem就应声而出。createBem是css 类名 bem 规范的构造函数。目的是为了解决如下问题:
- 手动拼接 BEM 类名容易出错(如忘记
__或--)。
- 动态类名管理复杂(如条件修饰符
{ active: isActive })。 - 减少重复代码,提高可维护性。
调用示例
在js中使用:
const bem = createBem("v-button"); // 生成构造函数,命名空间为 button
bem(); // 'v-button' - 返回前缀+命名空间
bem("icon"); // 'v-button__icon' - 子元素
bem(":disabled"); // 'v-button--disabled' - 冒号代表修饰符
bem({ primary: true }); // 'v-button v-button--primary' - 对象类型代表可选修饰符
bem({ primary: true, focus: true, plain: false }); // 'v-button v-button--primary v-button--focus' - 多个可选修饰符
bem('name', { primary: true }) // v-button__name v-button__name--primary
在vue中使用:
<template>
<div :class="bem()">
<div :class="bem('title')">
title
</div>
<div :class="bem('name', { active: divActive })">
content
</div>
</div>
</template>
<script setup>
const bem = createBem('x-div')
const divActive = ref(true)
setTimeout(() => {
divActive.value = false
}, 2000);
</script>
<style lang="less">
.x-div {
&__title {
color: red;
}
&__name {
color: yellow;
&--active {
background: blue;
}
}
}
</style>
// 编译结果
<template>
<div class="x-div">
<div class="x-div__title">
title
</div>
<div class="x-div__name x-div__name--active">
content
</div>
</div>
</template>
核心代码
const createBem = (name) => {
const basicName = name || ''
const bemFunc = (...rest) => {
if(!rest.length) return basicName
return rest.reduce((pre, ele) => {
if(typeof ele === 'object') {
pre = handleObject(pre, ele)
} else {
pre = handleString(pre, ele)
}
return pre
}, basicName)
}
const handleObject = (pre, obj) => {
let ret = pre
Object.keys(obj).forEach(k => {
if(obj[k]) {
ret += ` ${pre}--${k}`
// 对象的拼接是修饰符,需要叠加前面的块和元素
}
})
return ret
}
const handleString = (pre, str) => {
let ret = pre
// 约定俗称 : 来代表修饰符
if(str.startsWith(':')) {
ret += `--${str.slice(1)}`
} else {
ret += `__${str}`
}
return ret
}
return bemFunc
}
总结
BEM 是一种流行的 CSS 命名方法论,主要用于大型项目,帮助开发者编写可维护、可扩展的样式代码。通过函数式编程,将 BEM 规范封装为简洁的 API,解决了 CSS 类名动态管理的问题,适合追求结构化和可维护性的前端项目。