组件设计之BEM法则
原文:https://github.com/kuitos/kuitos.github.io/issues/30
更多精彩文章:https://github.com/kuitos/kuitos.github.io/issues/
BEM定义
Block Element Modifier is a methodology, that helps you to achieve reusable components and code sharing in the front-end
BEM概念
原义:一个css编写规范
**B(block): 独立的页面及逻辑单元,我们通常意义上的component
E(element): 块中的组成部分,不能脱离块单独存在
M(modifier): 修饰符,可修饰块或元素**
它提出来一种命名规范:
block__element--modifier
example:
<div class="header header--blink">
<div class="header__title header__title--red-border">title</div>
</div>
这段html表达的意思是:一个header组件(block),其中包括了一个title元素(element),同时header块具备闪烁(blink)特性,title元素具备红边框特性。
但是我们今天要讲的并不是这个
BEM的这种命名方式看似美妙,但实则是与标准相悖的解决方案(后面讲)。所以我不会推荐这种css规范,我想说的是从BEM这种思路,我们可以将它作为我们组件粒度划分的方法论。
从BEM划分策略看页面:
Block是一个完整独立的逻辑单元,是一个概念完备的组件,它包含完整的逻辑单元(js),模版(template)及样式(css)
Element是Block的组成部分,Block是它的宿主,Element无法脱离宿主存在
Modifier是块/元素的修饰符
以一个tab列表组件为例:
我们的目录结构应该这样去组织
代码可能这样去写
// tabset
app.directive('tabset', function(){
return {
restrict:'E',
templateUrl:'tab-set.html',
scope:{
tabs:'='
}
};
});
<!-- tab-set.html -->
<div ng-repeat="tab in tabs track by $index">
<tab info="tab"></tab>
</div>
<div class="tab-border"></div>
// tab
app.directive('tab', function(){
return {
restrict:'E',
require:'^tabset',
templateUrl:'tab.html',
scope:{
tab:'=info'
}
};
});
<!-- tab.html -->
<div>
<span ng-bind="tab.title"></span>
</div>
调用时这么去用
<tabset tabs="tabs"></tabset>
app.controller('ctrl', ctrl);
ctrl.$inject = ['$scope'];
function ctrl($scope){
$scope.tabs = [{title:'tab1'}, {title:'tab2'}];
}
Tab组件作为TabSet的一部分是没办法独立存在的,它必须依托于TabSet才有意义。
对调用者而言,暴露给它的是TabSet组件,TabSet才是一个Block(组件),Tab是一个Element。
在components这一层,我们能看到的都是一个个完整的Block,而且每个Block都是独立存在不会互相依赖的平级关系。
总结来讲就是
组件与组件之间的关系,是组合,不是依赖
如果你在components层级发现了存在相互依赖的两个组件,赶紧重新想想你的组件规划是不是有问题
我们可以将 ‘组件之间的关系是组合而不是依赖’ 作为我们开发设计组件的guideline,基于此,我们需要确立的思想就是,在现如今的web开发模式下,我们更应该采用 面向组件(COP) 的方式开发组件而不是以前流行的 面向对象(OOP) 的方式(以ExtJs为代表),组件之间更多的是组合关系,继承的场景在组件开发领域很少而且大多时候可以用其他方式实现(组合或者修饰符的方式)。
拓展章节:
[web语义化标准解读]()
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。