Skip to content

Instantly share code, notes, and snippets.

@AndersSchmidtHansen
Last active March 23, 2020 17:00
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AndersSchmidtHansen/024cf71fec08835481d2 to your computer and use it in GitHub Desktop.
Save AndersSchmidtHansen/024cf71fec08835481d2 to your computer and use it in GitHub Desktop.
Vue BEM Directive - A vue.js directive for automatic BEM class generation when creating components. A very rough example can be found here: https://jsfiddle.net/at1h1z1z/6/
/*
|--------------------------------------------------------------------------
| Vue BEM Directive
|--------------------------------------------------------------------------
|
| If you find yourself writing a lot of long, tedious CSS class names in
| order to be consistent with the BEM naming convention, then try this
| directive. It automagically does all the heavy lifting based on
| the component's name found in $options.name.
|
| It can produce BEM classes similar to those Harry Roberts advocate in
| this article: http://bit.ly/1R3nlNG
|
| With that said, if you write this:
| <div v-bem:,premium v-bem:o-media.block>
| <img src="" alt="" v-bem:photo v-bem:o-media,img.block v-bem:c-avatar.block />
| <p v-bem:bio v-bem:o-media,body,large.block>...</p>
| </div>
|
| It produces:
| <div class="o-media c-user c-user--premium">
| <img src="" alt="" class="o-media__img c-user__photo c-avatar">
| <p class="o-media__body c-user__bio">...</p>
| </div>
|
| A different example with a more tedious component name like
| 'congratulations-card':
| <div v-bem>
| <section v-bem:content>
| <div v-bem:title>{{ title }}</div>
| <p v-bem:message>{{ message }}</p>
| </section>
| <footer v-bem:footer>
| <slot name="footer"></slot>
| </footer>
| </div>
|
| Produces:
| <div class="c-congratulations-card">
| <section class="c-congratulations-card__content">
| <div class="c-congratulations-card__title"></div>
| <p class="c-congratulations-card__message"></p>
| </section>
| <footer class="c-congratulations-card__footer"></footer>
| </div>
|
*/
Vue.directive('bem', {
bind: function() {
var _namespace = ' ' + ( (this.modifiers.block) ? '' : 'c-' )
var _block = _namespace + this.vm.$options.name
var _element = ''
var _modifier = ''
var _elementPrefix = '__'
var _modifierPrefix = '--'
if (this.arg) {
var _bem = this.arg.split(',')
var _element = (_bem[0]) ? _elementPrefix + _bem[0] : ''
var _modifier = (_bem[1]) ? _modifierPrefix + _bem[1] : ''
if ( this.modifiers.block ) {
_block = _namespace + _bem[0]
_element = _elementPrefix + _bem[1]
_modifier = _modifierPrefix + _bem[2]
if ( _bem[1] ) {
this.el.className += _block + _element
} else {
this.el.className += _block
}
if ( _bem[2] ) {
this.el.className += _block + _element + _modifier
}
} else {
if (_element) {
this.el.className += _block + _element
} else {
this.el.className += _block
}
if (_modifier) {
this.el.className += _block + _element + _modifier
}
}
} else { this.el.className += _block }
}
})
@rafegoldberg
Copy link

rafegoldberg commented Jun 19, 2018

@AndersSchmidtHansen this is great; haven't tested it out, but useful just to read thru the logic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment