L
L
lodbrock2020-01-02 18:13:45
Vue.js
lodbrock, 2020-01-02 18:13:45

How to add a class without $style.class_name in Vue?

Hello. Can you tell me if it's possible to add a class like this:

<template>
  <div>
    <div :class="test1">test1</div>
    <div :class="test2">test2</div>
  </div>
</template>

<script>

export default {
  name: 'Test'
}
</script>

<style module>
  .test1 {
    color: red;
  }
  .test2 {
    color: green;
  }
</style>

instead of this:
<template>
  <div>
    <div :class="$style.test1">test1</div>
    <div :class="$style.test2">test2</div>
  </div>
</template>

<script>

export default {
  name: 'Test'
}
</script>

<style module>
  .test1 {
    color: red;
  }
  .test2 {
    color: green;
  }
</style>

And so that the class names remain modular:
5e0e07f27cdc4662271183.png

Answer the question

In order to leave comments, you need to log in

2 answer(s)
D
Dmitry Belyaev, 2020-01-03
@lodbrock

Modular CSS is not a feature of vue, it's a feature of the css-loader + vue-loader bundle for webpack. The role of css-loader here is to replace the class names (as well as the names of keyframes and other internal things, but not the names of tags and not id) with a hash of the file path and the original class name, as well as providing an object with a mapping of the original class name in its associated hash. And the role of vue-loader is to add a mixin with a beforeCreate hook that passes the mapping object to this.$style
From the css-loader documentation, you can learn that any selector or part of it can be wrapped in a :global() construct so that the specified class names are not renamed.

style[scoped]
Yes, I got acquainted with this, but then there will be no modularity in classes
This thing works at the level of the vue compiler itself and it gives modularity by adding an attribute of the form v-1234567 (where 1234567 is a hash of the contents of the .vue file) to all tags and adding an attribute selector. This really solves the problem, leaving the original classes and working even on tag names, but at the cost of slower attribute selectors.
Why it was impossible to solve this problem by adding an additional class, as it was done in svelte, for example, from which Evan Yu almost completely stole the design... This is known only to Evan himself, who, however, very often single-handedly makes decisions that are not the most optimal in terms of performance when he does not know how do okay.
Another solution would be to code a little. The template fragment specified in the question
<template>
  <div>
    <div :class="test1">test1</div>
    <div :class="test2">test2</div>
  </div>
</template>
will look for fields with the keys test1 and test2 in this, which means that they can be moved there in the beforeCreate hook from this.$style, like this:
const mixin = {
  beforeCreate() {
    const applyClassNames = () => Object.keys(this.$style).forEach(className => {
      this[className] = this.$style[className];
    });
    if(!this.$style) {
      // наш миксин может оказаться раньше миксина лоадера
      Object.defineProperty(this, '$style', {
        enumerable: true,
        configurable: true,
        get() {},
        set: $style => {
          Object.defineProperty(this, '$style', {
            enumerable: true,
            configurable: true,
            writable: true,
            value: $style
          };
          applyClassNames();
        }
      });
      return;
    }
    applyClassNames();
  }
};
export default {
  mixins: [mixin],
  // ...
};
True, the minus of the approach is that all class names will be directly in the component's this, which is fraught with conflicts.

L
lodbrock, 2020-01-03
@lodbrock

I also found two more solutions, I don’t know how correct they are, maybe someone will tell you, but maybe it will come in handy for someone.
1) vue.config.js config code:

module.exports = {
  configureWebpack: {
    resolve: {
      modules: ['src', 'node_modules'],
    },
  },
  css: {
    requireModuleExtension: false,
    loaderOptions: {
      css: {
        modules: {
          localIdentName: '[path]-[local]-[hash:4]'
        },
      }
    }
  }
}

Component code:
<template>
  <div :class="qqq">test1</div>
</template>

<script>
import styles from './styles.css'

export default {
  name: 'Test',
  data: function () {
    return {
      ...styles
    }
  },
}
</script>

The class name in the end:
2) The vue.config.js config remains the same, but you need to install this Vue CSS Modules package .
Component code:
<template>
  <div styleName="qqq">test1</div>
</template>

<script>
import CSSModules from 'vue-css-modules'
import styles from './styles.css'

export default {
  name: 'Test',
  mixins: [CSSModules(styles)],
}
</script>

Class name:
5e0f216e9ae54699224484.png

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question