LoginSignup
4
3

More than 1 year has passed since last update.

Atomic Designを採用したnuxtで親から子コンポーネントのスタイルを使い分ける

Last updated at Posted at 2019-05-25

対象

  • nuxtないしVueをつかっている
  • Atomic Designを使ってコンポーネントを分けたアプリをつくっている(Atominc Designに限らなくてもコンポーネントの共通化をしている)
  • styleはscopedにしていて、コンポーネントを超えてcssを使い回していない
  • Scssをつかっている(使っていない場合はcssをネストさせなければよいだけですが)

やること

背景

  • アプリの中で使うbuttonやlabelを共通化したい
  • アプリ内ではbuttonやlabelの見た目はいくつかのパターンしかない
  • しかし、横幅とかは使う場所によってまちまちである

やりたいこと

  • 見た目のパターンはそのコンポーネントの中に定義して、親コンポーネントからどのパターンかを指定したい
    • 同じスタイルを何度も書きたくはないため
  • 横幅などは親コンポーネントからその都度値を指定したい
    • 微妙に変わる部分は子コンポーネントにいちいち定義していると限りがないため

この記事でやってみること(つまり具体例)

  • MyButtonというコンポーネントをつくる
  • MyButtonは通常の見た目と、強調したい見た目を親から選んで指定する
  • 通常、強調のどちらでも影付きボタンにできる
  • MyButtonのwidthは親から直接指定する

やり方

  • Vueが用意しているクラスとスタイルのバインディングをつかう
  • htmlのセレクタに対して、:class=:style=と属性を付与することで、クラスや個別のスタイルをバインディングできる

通常と強調を使い分ける

こんな感じのコンポーネントを作る

MyButton.vue
<template>
  <!-- propsで受け取ったtypeをクラスにバインディングする -->
  <button class="MyButton" :class="type">
    <slot />
  </button>
</template>

<script>
export default {
  props: {
    // 適用したいスタイルを文字列のporpとして親から受け取る
    type: {
      type: String,
      default: ''
    }
  }
}
</script>

<style lang="scss" scoped>
.MyButton {
  <!-- 見た目のパターンをネスとしたクラスで定義する -->
  &._normal {
    background-color: white;
    border: solid 1px black;
  }

  &._strong {
    background-color: red;
    border: solid 1px black;
  }

  &._shadow {
    box-shadow: 0px 3px 6px 0px black;
  }
}
</style>

親からはこのように使用する

Parent.vue
<template>
  <div>
    <!-- 適用したいクラスを文字列で指定する -->
    <my-button class="_nomal">
      通常ボタン
    </my-button>
    <my-button class="_strong">
      強調ボタン
    </my-button>
    <!-- クラスを二つ指定する時はスペースで区切る -->
    <my-button class="_nomal _shadow">
      影付き通常ボタン
    </my-button>
  </div>
</template>

横幅を指定する

先ほどのコンポーネントに:style属性を書き加える

MyButton.vue
<template>
  <!-- propsで受け取ったwidthの値をwidthスタイルにバインディングする -->
  <button class="MyButton" :class="type" :style="{ width: width }">
    <slot />
  </button>
</template>

<script>
export default {
  props: {
    type: {
      type: String,
      default: ''
    },
    // 適用したいスタイルの値を文字列のporpとして親から受け取る
    width: {
      type: String,
      default: ''
    }
  }
}
</script>

<style lang="scss" scoped>
.MyButton {
  <!-- こちらはそのまま -->
  &._normal {
    background-color: white;
    border: solid 1px black;
  }

  &._strong {
    background-color: red;
    border: solid 1px black;
  }

  &._shadow {
    box-shadow: 0px 3px 6px 0px black;
  }
}
</style>

親からはこのように使用する

Parent.vue
<template>
  <div>
    <!-- 適用したい横幅の値を単位付きの文字列で指定する -->
    <my-button class="_nomal" width="100px">
      通常ボタン
    </my-button>
    <!-- 単位を自由に指定できる -->
    <my-button class="_strong" width="10%">
      強調ボタン
    </my-button>
  </div>
</template>
  • :style="{ width: width }"は、{ width: width }の左側にスタイルを書いて、右側に値を書く (要するに:style="{ width: 10px }"ということ)
  • 複数のスタイルを指定したいときには:style="{ width: hoge, height: fuga }"のようにカンマで区切ればOK

まとめ

クラスとスタイルのバインディングをうまく使って抽象的なコンポーネントを作れれば、その後が楽!

Twitterもやってるので、よければフォローお願いします。
https://twitter.com/ObataGenta

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3