Giter VIP home page Giter VIP logo

vue-bem's Introduction

โš ๏ธ Not maintained anymore, since the performance turned out to be not better than vue-bem-cn, which I would still recommend instead.


@verstaerker/vue-bem

Adds a directive and (optional) mixin to your Vue.js project to create BEM class names.

This Plugin was inspired by vue-bem-cn and vue-bem.

Table of Contents

Comparison

@verstaerker/vue-bem vue-bem-cn vue-bem (Vue 1)
Info
  • Automatic class creation for block, element, modifier
  • Component name or custom property used as block name
  • Dynamic modifiers
  • Allows Boolean, Number and String values as modifiers
  • Prevents re-calculation of classes if modifiers did not change
  • Cache for String replacements
  • Only updates modifier classes on re-calculation
  • Automatic class creation for block, element, modifier and mixin
  • Component name or custom property used as block name
  • Dynamic element name
  • Dynamic modifiers
  • Dynamic mixins
  • Allows Boolean, Number and String values for modifiers
  • Automatic class creation for block, element, modifier
Limitations
  • Static element name
  • Mixins must be defined with class attribute
  • Modifiers must be defined as computed property to allow "caching"
  • No caching
  • Recalculates on each component update
  • Updates all BEM classes when re-calculating
  • Deprecated
  • Static element and modifiers

How to use

Directive

The vue-bem directive is used as any other Vue.js directive.

v-bem<:element><.static-modifiers>="<modifiers>"

All parts are optional. If you only use v-bem you will still get the block class though.

Mixin

The mixin adds a $bem (or as configured) method to the extended component which you can use to create BEM classes from within JavaScript.

render(h) {
  const className = this.$bem(<element> [, <modifiers>]);
}

Modifiers and static modifiers

You can define two types of modifiers: dynamic and static. The dynamic ones can be given as value object to the directive (e.g. v-bem="{ status: 'error' } [note, that it is better practice to define a computed for modifiers to allow conditional updates]). Static ones can be defined as directive modifiers (e.g. v-bem.column-right). The advantage of static modifiers is the fact, that they will only be defined once when the component is rendered. Dynamic modifiers will overwrite static modifiers with the same (initial) name.

Attributes

Element (String)

The element name which will be concatenated with the block name using the element delimiter as glue.

Modifier (Object)

The to be applied modifiers which will be concatenated with the block or element name using the modifier delimiter as glue.

A value can be given to each modifier (which will be concatenated using the value delimiter as glue):

  • Type String and Number will be added as a value to the modifier class
  • Type Boolean will add/remove the modifier and not add a value to the modifier

Install

To install the npm package run

npm i @verstaerker/vue-bem --save

Directive

The directive is delivered as a Vue plugin. You can install it as any other plugin:

import Vue from 'vue';
import vueBem from '@verstaerker/vue-bem';

Vue.use(vueBem);

new Vue(/* ... */);

Mixin

To use the mixin you MUST install the plugin first. Then you can use the mixin as any other Vue mixin (locally or globally). It is recommended to use the mixin locally when needed.

// component.vue
import { bemMixin } from '@verstaerker/vue-bem'

export default {
  mixins: [bemMixin],
  render(h) {
    const className = this.$bem('element');
    
    // ...
  }
}

Settings

// Defaults
{
  namespace: '',
  blockSource: 'name'
  method: '$bem'
  hyphenate: {
    blockAndElement: false,
    modifier: true,
  },
  delimiters: {
    element: '__',
    modifier: '--',
    value: '-',
  }
}

namespace (String)

default: ''

Can be used to add a static namespace to the beginning of every class. Must include the delimiter.

blockSource (String)

default: name

Defines the component property which will be used to create the BEM block name. name will also be used as fallback in case the given blockSource is not available.

method (String)

default: $bem

Defines the name of the bem method when used as mixin.

hyphenate (Boolean|Object)

default: { blockAndElement: false, modifier: true }

Allows to enable auto hyphenating of block, element and modifiers. Mixins are never touched. By default hyphenating is only applied to modifiers to allow the use of camelCase key names for the modifier Object. It is recommended to write block and element already in kebab case if you prepare so because it removes the conversion step. Hyphenation for modifiers will apply for static and dynamic modifiers.

delimiters (Object)

default: { element: '__', modifier: '--', value: '-', }

Allows to define custom delimiters between block, element and modifier.

delimiters.element (String)

delimiters.modifier (String)

delimiters.value (String)

Examples

The following examples show how to create block, element and modifier classes. You can combine the directive with static or dynamic class bindings.

Directive

Only block

<div v-bem></div>

<!-- will become -->
<div class="block"></div>

Only element

<div v-bem:element></div>

<!-- will become -->
<div class="block__element"></div>

With static modifier(s)

Note: There is no limit to the number of modifiers.

<div v-bem.columnRight></div> 

<!-- will become -->
<div class="block block--column-right"></div>

With dynamic modifier(s)

Note: There is no limit to the number of modifiers.

<!-- `modifiers` is a computed value returning `{ color: 'red' }` -->
<div v-bem="modifiers"></div> 

<!-- will become -->
<div class="block block--color-red"></div>

With static and dynamic modifier(s)

Note: There is no limit to the number of modifiers.

<!-- `modifiers` is a computed value returning `{ color: 'red' }` -->
<div v-bem.columnRight="modifiers"></div> 

<!-- will become -->
<div class="block block--column-right block--color-red"></div>

All together

<!-- `modifiers` is a computed value returning `{ visible: true }` -->
<div v-bem:element="modifiers"></div>

<!-- will become -->
<div class="block__element block__element--visible"></div>

Mixin

Only block

render(h) {
  const className = this.$bem(); // 'block'
}

With modifier(s)

render(h) {
  const className = this.$bem('element'); // 'block__element'
}

Only element

Note: There is no limit to the number of modifiers.

computed: {
  modifiers() {
    return {
      color: this.$props.color
    }
  }
},
render(h) {
  const className = this.$bem(this.modifiers); // 'block block--color-red'
}

All together

computed: {
  modifiers() {
    return {
      visible: this.$props.visible
    }
  }
},
render(h) {
  const className = this.$bem('element', this.modifiers); // 'block__element block__element--visible'
}

Dependencies

This Vue.js plugin/mixin has no 3rd party dependencies.

License

MIT

vue-bem's People

Contributors

patric-eberle avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

nettsentrisk

vue-bem's Issues

Support passing string as dynamic modifier

It's now not possible to create modifiers that are simply based on a dynamic value, since the property name of the passed object is always used as the modifier prefix.

<div v-bem="modifier"></div>

If modifier is a string with the value "mod", the resulting HTML should be:

<div class="block block--mod"></div>

Now it will handle a string value as an object and produce:

<div class="block block--0-m block--1-o block--2-d"></div>

Nuxt support

Hello,
I have looked into basic Nuxt.JS support, and it is quite possible with minor non-breaking changes.
So, it is possible to create a totally similar SSR-friendly directive, using the vue-bem directive's inserted function, but with vnode instead of el argument.

The changes should be made in the addClass function:

function addClass(el, className) {
  if (!el.classList) { // detect SRR, as virtual DOM node in SSR does not have el.classList
    let vnode = el
    if (vnode.data.staticClass) {
      vnode.data.staticClass += ` ${className}`
    } else {
      vnode.data.staticClass = `${className}`
    } 
  } else { 
    //...normal addClass function when no SSR is detected...
  }
}

Another change should be made in the getBEM function, just to check if binding has the modifiers property:

if (!binding.modifiers) { // the binding metadata in SSR does not have the 'modifiers' property
  binding.modifiers = {}
}

Just like that, we can register the SSR directive in nuxt.config.js:

const bemOptions = {
  // bem options
}
const { inserted } = directive(bemOptions)

module.exports = {
  //...other nuxt config...
  render: {
    bundleRenderer: {
      directives: {
        bem: function(vnode, binding) { inserted(vnode, binding, vnode) }
      }
   }
}

Fallback to `name` if blockSource attribute is not defined on component

Great plugin, thanks!

It would be great if the plugin was provided with a blockSource property, but then that property was not found on the component, that it would automatically fallback to the default name property.

Is there already a good way to do this when installing the plugin globally?

Add static modifiers as modifiers

Static modifiers (e.g. --desktop) could be defined as directive modifiers instead of the directive value. This way they would only have to be calculated once, since they never change.

e.g.

<div v-bem:element.static-modifier="dynamicModifiers"></div>

Directive performance issues

Unfortunately I have to admit, that additional test showed that, while my internal code performed faster, the overall rendering time eventually is higher (we are talking about higher two digit milliseconds here). As I currently see it this is due the fact how Vue handles directives. So far I was not able to get it down to the speed that the vue-bem-cn plugin offers...

I actually wanted to also post some testing results, but I was not able to make an extensive comparison yet.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.