组件设计之BEM法则

@kuitos 2015-11-26 08:51:48发表于 kuitos/kuitos.github.io 前端架构

组件设计之BEM法则

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划分策略看页面:
a

  1. Block是一个完整独立的逻辑单元,是一个概念完备的组件,它包含完整的逻辑单元(js),模版(template)及样式(css)
  2. Element是Block的组成部分,Block是它的宿主,Element无法脱离宿主存在
  3. 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为代表),组件之间更多的是组合关系,继承的场景在组件开发领域很少而且大多时候可以用其他方式实现(组合或者修饰符的方式)。

拓展章节:

  1. web语义化标准解读