記一次bem命名規範使用優化方案

二哈哈哈哈發表於2019-03-09

背景

在公司專案中,我們一直class名稱遵循bem規範,但是在使用中,也發現了一些不方便的地方

  • class名稱比較長,寫起來比較麻煩,一個dialog文字位置的樣式需要寫成ns-dialog__title--center
  • 在使用多個class時候需要拼字串,特別是如果存在條件判斷的樣式,還需要進行if判斷 下圖是螞蟻金服 ant design 框架的一段樣式處理,雖然進行了包裝處理,但是還是稍顯麻煩
    記一次bem命名規範使用優化方案

解決方案

為了簡化bem規範的使用複雜度,我借鑑了幾個框架的方法,打造了一款比較簡單易用的外掛庫css-bem(github.com/snowzijun/c…)。

在這個外掛庫中,為了更符合常用的元件庫樣式的命名,在bem規範基礎上,我又新增了一個名稱空間(namespace)概念,變成了nbem,如京東taro-ui框架輸入框的樣式at-input__overlay--hidden,atnamespace,inputblock,overlayelement,hiddenmodifier

安裝
    npm install css-bem
    import cssBem from 'css-bem'
複製程式碼
基本用法(以react開發Button元件為例)
 import cssBem from 'css-bem'
 // 宣告 namespace 與 block
 const nbem = cssBem('zj','button')
 // 元件
 export default class Button extends React.Component{
     static propTypes={
         type:PropTypes.string,
         plain:PropTypes.bool,
         disabled: PropTypes.bool
     }
     render(){
        const {type,plain,disabled} = this.props
         return (
            <button className={nbem([type,{disabled,plain}])}>
                <span className={nbem('text')}>按鈕文字</span>
            </button>
         )
     }
 }
 // 頁面
 export default class Page extends React.Component{
     
     render(){
        // 設定按鈕 type為primary,plain為false disabled為true
         return <Button type='primary' plain={false} disabled></Button>
     }
 }
 // 渲染結果
 <button class='zj-button zj-button--primary zj-button--disabled'>
    <span class='zj-button__text'>按鈕文字</span>
 </button>
複製程式碼
api說明
// namespace可省略不寫 如 cssBem('button')
const nbem = cssBem('zj','button')

nbem() // zj-button
nbem('text') // zj-button__text
nbem(['primary']) // zj-button zj-button--primary
nbem({disabled:true,plain:false}) // zj-button zj-button--disabled
nbem(['primary',{disabled:true}]) // zj-button zj-button--primary zj-button--disabled
nbem('text',['large',{show:true}]) // zj-button__text zj-button__text--large zj-button__text--show
複製程式碼
React 高階元件
// 使用裝飾器
import {injectBem} from 'css-bem'

@injectBem('zj','button')
export default class Button extends React.Component{
    render(){
        const {type,plain,disabled} = this.props
        const { classnames } = this
        return <button className={classnames([type,{disabled,plain}])}>
                <span className={classnames('text')}>按鈕文字</span>
            </button>
    }
}

//使用高階元件
class Button extends React.Component{
    // 內容與裝飾器一直
}
export default injectBem('zj','button')(Button)
複製程式碼
Vue mixins
import {vueMixin} from 'css-bem'
export default{
    mixins:[vueMixin('zj','button')]
}

<template>
  <button :class="classnames([type,{disabled,plain}])">
                <span :class="classnames('text')">按鈕文字</span>
            </button>
</template>
複製程式碼
其他說明
 // 不使用namespace與block
 import {flatten} from 'css-bem'
 flatten('header',['header__text',{
     'header__icon--show':false,
     'header--dark':true
 }])
 /**輸出
    'header header__text header--dark'
 */
 
複製程式碼

相關文章