takeda_san’s blog

KotlinとVRを頑張っていく方向。

Vue.js+TypeScriptでもscopedなcssを書きたい

きっかけ

TypeScriptを勉強し始めたので、どうせなら今書いているVue.jsのアプリで使いたい。
時代はTypeScriptだ。イェッヘッヘ
と思って、やりだしたのですがコンポーネントのstyleをscopedな感じで書きたいときに大変困った。

素のVue.jsというか.vueファイルだとsytleタグにscopedを付与するだけで、localなスコープのcss定義になる。

<style scoped>
.button-color{
  color: red;
}
</style>

だけど、.tsファイルの場合どこに書けばよいんだ?

import Vue from 'vue';
import Component from 'vue-class-component';

@Component({
    template: `
<button class="button-color">こんにちは!こんにちは!</button>
    `,
  })
export default class OtherComponent extends Vue {
}

書くとこなくない?
というわけで、書き方を考えてみた。

別ファイルimport作戦

とりあえずcssファイルを別で作ってimportしていたが、これlocalじゃなくてglobalに全体へ適用されるみたいでつらい。

import Vue from 'vue';
import Component from 'vue-class-component';
import './HelloComponent.scss';

@Component({
    template: `
<button class="button-color">こんにちは!こんにちは!</button>
    `,
  })
export default class HelloComponent extends Vue {
}

もし、importしてlocalなスコープであれば、ほかのボタンに同じclassを指定してもスタイルが当たらないはず。

.button-color {
    color: red;
    margin: 5px;
}

残念ながらcssファイルをインポートしてない、上のおはようボタンコンポーネントにもスタイルが当たってる。
f:id:takeda_san:20181110150402p:plain

css modulesを使おう

css moduleでは、localとglobalの定義を分けて書けるらしい。
そのcssファイルをtsの方で読み込むと、ちゃんとlocalなスコープになった。

classをバインドして、requireで読み込んだcssのクラス名を指定する。
scopedで定義していた時より、ちょっと面倒かな…

GitHub - css-modules/css-modules: Documentation about css-modules

import Vue from 'vue';
import Component from 'vue-class-component';

@Component({
    template: `
<button :class="template.style['button-color']">こんにちは!こんにちは!</button>
    `,
  })
export default class HelloComponent extends Vue {
    private template = {
        style: require('./HelloComponent.scss'),
    };
}

localで囲んであげるとlocalスコープになる。

:local {
    .button-color {
        color: red;
        margin: 5px;
    }
}

f:id:takeda_san:20181110152950p:plain

素敵。
css modulesだと、同じcssファイルにglobalな定義とlocalの定義を両方書けるので .vueで書いていたscoped指定よりは、書き方が柔軟なのは良いことかなと思いました。

プロジェクトまるごとはこちら。
github.com