從element-ui源碼來(lái)看BEM實(shí)現(xiàn)

以前看過(guò)一些CSS的編碼規(guī)范驳癌,也照著規(guī)范編寫代碼娄琉,但是還是覺(jué)得自己的CSS編碼風(fēng)格不是很好融击,在平時(shí)開發(fā)中使用各個(gè)知名的組件庫(kù)的時(shí)候筑公,發(fā)現(xiàn)現(xiàn)在挺多組件庫(kù)都是BEM的命名風(fēng)格了,于是找了比較知名的element餓了么前端的組件庫(kù)的源碼砚嘴,想從看餓了么組件庫(kù)的代碼入手十酣,學(xué)習(xí)學(xué)習(xí)大廠的的CSS BEM規(guī)范代碼的書寫風(fēng)格。

BEM代表“塊(block)际长,元素(element)耸采,修飾符(modifier)”,開發(fā)組件的過(guò)程中經(jīng)常使用這三個(gè)實(shí)體工育,而在選擇器中虾宇,這三個(gè)實(shí)體由以下符號(hào)來(lái)表示擴(kuò)展關(guān)系:

-  中劃線:僅作為連字符使用,表示某個(gè)塊或者某個(gè)子元素的多單詞之間的連接記號(hào)如绸。
__ 雙下劃線:雙下劃線用來(lái)連接塊和塊的子元素嘱朽。
_  單下劃線:?jiǎn)蜗聞澗€用來(lái)描述一個(gè)塊或者塊的子元素的一種狀態(tài)。

type-block__element_modifier

以上的描述是從騰訊的前端規(guī)范庫(kù)中找到的怔接,簡(jiǎn)單的來(lái)說(shuō)理解了塊搪泳、元素、修飾符三個(gè)分類之后扼脐,就能大致理解BEM代碼是什么樣的結(jié)構(gòu)了岸军,可是了解結(jié)構(gòu)是一方面,如何寫好代碼又是另一方面瓦侮。我在element組件庫(kù)中的mixins.scss文件中找到了想要的答案艰赞。

接下來(lái)我要講的就是如何利用sass,編寫具有可讀性和可維護(hù)性的BEM規(guī)則的css代碼肚吏。

首先來(lái)看sass代碼中對(duì)于block的定義:

$namespace: 'el';
$element-separator: '__';
$modifier-separator: '--';
$state-prefix: 'is-';


@mixin b($block) {
  $B: $namespace+'-'+$block !global;

  .#{$B} {
    @content;
  }
}

為了方便大家理解代碼方妖,我現(xiàn)在開頭貼上配置文件中定義的變量,而這時(shí)就能很清楚的看到block的生成就是基于BEM規(guī)范中罚攀,塊是設(shè)計(jì)或布局的一部分党觅,具有唯一地意義雌澄,利用命名空間el加上中劃線,以及傳入的block的名字仔役,構(gòu)建出block的樣式掷伙,例如alert組件,在渲染完成后是el-alert又兵,體現(xiàn)出它的唯一性任柜。而在塊的內(nèi)部,再來(lái)編寫跟這個(gè)塊關(guān)聯(lián)的其他樣式代碼沛厨。

塊的構(gòu)建非常的簡(jiǎn)單宙地,接下來(lái)來(lái)看稍微有點(diǎn)復(fù)雜的元素的定義:

@mixin e($element) {
  $E: $element !global;
  $selector: &;
  $currentSelector: "";
  @each $unit in $element {
    $currentSelector: #{$currentSelector + "." + $B + $element-separator + $unit + ","};
  }

  @if hitAllSpecialNestRule($selector) {
    @at-root {
      #{$selector} {
        #{$currentSelector} {
          @content;
        }
      }
    }
  } @else {
    @at-root {
      #{$currentSelector} {
        @content;
      }
    }
  }
}

元素選擇器的實(shí)現(xiàn)中,我們應(yīng)該把關(guān)注點(diǎn)放在if和eles分支上逆皮,為什么會(huì)出現(xiàn)hitAllSpecialNestRule函數(shù)判斷的分支宅粥,原因是在修飾符或者其他mixin中嵌套一個(gè)元素element,會(huì)出現(xiàn)修飾符在前电谣,而元素在后的編譯結(jié)果秽梅,所以我們用hitAllSpecialNestRule函數(shù)來(lái)判斷是否存在特殊的嵌套,如果存在的話剿牺,將我們的元素字符串寫在前面企垦,而修飾符放在后面,如果不存在晒来,則原樣輸出钞诡。

hitAllSpecialNestRule的實(shí)現(xiàn)則在下面的代碼中:

@function selectorToString($selector) {
  $selector: inspect($selector);
  $selector: str-slice($selector, 2, -2);
  @return $selector;
}

@function containsModifier($selector) {
  $selector: selectorToString($selector);

  @if str-index($selector, $modifier-separator) {
    @return true;
  } @else {
    @return false;
  }
}

@function containWhenFlag($selector) {
  $selector: selectorToString($selector);

  @if str-index($selector, '.' + $state-prefix) {
    @return true
  } @else {
    @return false
  }
}

@function containPseudoClass($selector) {
  $selector: selectorToString($selector);

  @if str-index($selector, ':') {
    @return true
  } @else {
    @return false
  }
}

@function hitAllSpecialNestRule($selector) {

  @return containsModifier($selector) or containWhenFlag($selector) or containPseudoClass($selector);
}

第一個(gè)函數(shù)selectorToString,就是將我們的選擇器轉(zhuǎn)換成一個(gè)字符串湃崩,而接下來(lái)的三個(gè)函數(shù)荧降,分別判斷了是否存在修飾符、flag例如(.isCenter)攒读、偽類的情況朵诫。最后綜合在一起返回結(jié)果,避免嵌套薄扁。

最后則是modifier修飾符的實(shí)現(xiàn)了拗窃,代碼如下:

@mixin m($modifier) {
  $selector: &;
  $currentSelector: "";
  @each $unit in $modifier {
    $currentSelector: #{$currentSelector + & + $modifier-separator + $unit + ","};
  }

  @at-root {
    #{$currentSelector} {
      @content;
    }
  }
}

在看懂的元素的實(shí)現(xiàn)之后,修飾符的實(shí)現(xiàn)就是一目了然的了泌辫。利用剛剛介紹的函數(shù),以及塊九默、元素震放、修飾符的實(shí)現(xiàn)代碼,在sass中已經(jīng)能非常高效率并且優(yōu)雅的基于BEM規(guī)范的代碼了驼修。

貼一段示例代碼殿遂,如何利用上面的代碼編寫B(tài)EM規(guī)范的css代碼:

@import "mixins/mixins";
@import "common/var";

@include b(test) {
    width: 100%;
    background-color: $--color-white;

    @include when(center) {
        justify-content: center;
    }

    @include m(success) {
        background-color: $--color-black;
        font-size: 12px;

        .lix-test__description {
            color: $--color-white;
        }
    }

    @include m(warning) {
        background-color: $--color-black;
        font-size: 12px;

        .lix-test__description {
            color: $--color-white;
        }
    }

    @include e(content) {
        display: table-cell;
        padding: 0 8px;
    }

    @include e(title) {
        font-size: 8px;
        line-height: 10px;
        
        @include when(bold) {
            font-weight: bold;
        }
    }
}

.lix-test-fade-enter,
.lix-test-fade-leave-active {
    opacity: 0;
}

編譯之后的樣子:

.lix-test {
  width: 100%;
  background-color: #fff; }
  .lix-test.is-center {
    justify-content: center; }
  .lix-test--success {
    background-color: #000;
    font-size: 12px; }
    .lix-test--success .lix-test__description {
      color: #fff; }
  .lix-test--warning {
    background-color: #000;
    font-size: 12px; }
    .lix-test--warning .lix-test__description {
      color: #fff; }
  .lix-test__content {
    display: table-cell;
    padding: 0 8px; }
  .lix-test__title {
    font-size: 8px;
    line-height: 10px; }
    .lix-test__title.is-bold {
      font-weight: bold; }

.lix-test-fade-enter,
.lix-test-fade-leave-active {
  opacity: 0; }

瞧見了么诈铛,合理的利用b、m墨礁、e的mixin就可以風(fēng)格良好的css代碼了幢竹。上面的所有代碼都在這里哦,有需要的可以直接看完整代碼學(xué)習(xí)恩静。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末焕毫,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子驶乾,更是在濱河造成了極大的恐慌邑飒,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件级乐,死亡現(xiàn)場(chǎng)離奇詭異疙咸,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)风科,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門撒轮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人贼穆,你說(shuō)我怎么就攤上這事题山。” “怎么了扮惦?”我有些...
    開封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵臀蛛,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我崖蜜,道長(zhǎng)浊仆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任豫领,我火速辦了婚禮抡柿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘等恐。我一直安慰自己洲劣,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開白布课蔬。 她就那樣靜靜地躺著囱稽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪二跋。 梳的紋絲不亂的頭發(fā)上战惊,一...
    開封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音扎即,去河邊找鬼吞获。 笑死况凉,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的各拷。 我是一名探鬼主播刁绒,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼烤黍!你這毒婦竟也來(lái)了知市?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蚊荣,失蹤者是張志新(化名)和其女友劉穎初狰,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體互例,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡奢入,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了媳叨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腥光。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖糊秆,靈堂內(nèi)的尸體忽然破棺而出武福,到底是詐尸還是另有隱情,我是刑警寧澤痘番,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布熏纯,位于F島的核電站叁执,受9級(jí)特大地震影響藕坯,放射性物質(zhì)發(fā)生泄漏隆夯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一昂芜、第九天 我趴在偏房一處隱蔽的房頂上張望莹规。 院中可真熱鬧,春花似錦泌神、人聲如沸良漱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)母市。三九已至,卻和暖如春损趋,著一層夾襖步出監(jiān)牢的瞬間窒篱,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留墙杯,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓括荡,卻偏偏與公主長(zhǎng)得像高镐,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子畸冲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 問(wèn)答題47 /72 常見瀏覽器兼容性問(wèn)題與解決方案嫉髓? 參考答案 (1)瀏覽器兼容問(wèn)題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 13,754評(píng)論 1 92
  • BEM 基于組件方式的web開發(fā)方法,基本思想是將用戶界面分成獨(dú)立的模塊邑闲。 Block(塊) 通常指模塊算行,組件 B...
    xwwawj閱讀 937評(píng)論 0 2
  • CSS是一門15分鐘就能入門,但是卻需要很長(zhǎng)很長(zhǎng)的時(shí)間才能掌握好的語(yǔ)言苫耸。它有著它自身的一些復(fù)雜性與局限性州邢。其中非常...
    AlienZHOU閱讀 1,699評(píng)論 0 8
  • 在猶豫要不要把中間再畫一下?
    M有如果閱讀 492評(píng)論 3 24
  • 電視劇《陳二狗的妖孽人生》講的是底層農(nóng)民陳二狗闖入上海這座大都市飛黃騰達(dá)的故事,其過(guò)程帶有一定的偶然性∠油剩現(xiàn)實(shí)生活中...
    麥子愛上稻草人閱讀 497評(píng)論 2 3