vueコンポーネントに内部スタイルを書く方法


Vue:scopedスタイルとCSS Moduleの比較
  • 前言
  • Scopedスタイル
  • モジュール式CSS
  • まとめ
  • 前言
    先日違う町で時間を感じました.今日の朝、文章を読んで@西楼聴雨翻訳から分かち合いました.
    本文はここから~
    近代的なWeb開発の中で、CSSはまだ完璧ではないことは意外ではないはずだ.
    現在のプロジェクトは通常かなり複雑ですが、cssスタイルは生まれながらにしてグローバルなので、最後にはスタイルの衝突が発生しやすいです.スタイルが互いに覆われているか、下の考慮されていない要素に暗黙的にカスケードされています.
    CSSの存在を軽減する主な痛点において,我々が一般的に用いている解はBEM(Block Element Modifier)法論の導入である.しかし、これは私たちの大きな問題のほんの一部を解決するしかありません.
    幸いなことに、コミュニティはこれらの問題を処理するためにいくつかのソリューションを開発しました.CSS Modules、Styled Components、Glamorous、JSSを聞いたことがあるかもしれませんが、これらは多くの流行のツールの中の少数にすぎません.もしあなたがこの話題に興味があれば、この投稿を見ることができます.作者のIndrek LasnはCSS-in-JSの思想について非常に詳しく説明しました.
    vue-cliによって作成された各Vue.jsアプリケーションには、Scoped CSSとCSS Modules(モジュール式CSS)の2つの優れたソリューションが内蔵されています.2つの案にはそれぞれメリットとデメリットがあるので、次はどの案があなたのケースでもっと適用されるかをよく見てみましょう.
    Scopedスタイル
    スタイルラベルにscopedプロパティを追加するだけでscopedスタイルを有効にできます.
    <template>
       <button class=”button” />
    </template>
    <style scoped>
       .button {
          color: red;
       }
    </style>

    これにより、私たちのスタイルはこのコンポーネントの要素にのみ適用されます.これはPostCSSによって実現され、上のコードを次のように変換します.
    <style>
      .button[data-v-f61kqi1] {
        color: red;
      }
    </style>
    <button class=”button” data-v-f61kqi1></button>

    ご覧のように、プロセス全体が何もする必要がなく、scopedスタイルの効果が得られます.
    ビュー内のコンポーネントの幅を調整する必要があると仮定すると、通常のように、このコンポーネントに追加のclassを追加してスタイルを設定することができます.
    <template>
      <BasePanel class=”pricing-panel”>
        content  </BasePanel>
    </template>
    <style scoped>
      .pricing-panel {
        width: 300px;
        margin-bottom: 30px;
      }
    </style>

    変換後:
    <style>
      .base-panel[data-v-d17eko1] {
        ...
      }
      .pricing-panel[data-v-b52c41] {
        width: 300px;
        margin-bottom: 30px;
      }
    </style>
    <div class=”base-panel pricing-panel” data-v-d17eko1 data-v-b52c41>
      content</div>

    今回も同じで、何もする必要がなく、レイアウトを徹底的にコントロールすることができます.
    ただし、このプロパティには、サブコンポーネントのルート要素にクラスがこの親コンポーネントで定義されている場合、この親コンポーネントのスタイルがサブコンポーネントに漏れるという欠陥があります.この問題をよりよく理解するには、このCodeSandboxの例を参照してください.
    サブコンポーネントの深層構造にスタイルを設定する必要がある場合もあります.この方法は推奨されず、避けるべきですが.簡単にするために、親コンポーネントがBasePanelのタイトルにスタイルを設定すると仮定します.scopedスタイルでは、>>コネクタ(または/deep/)を使用して実装できます.
    <style scoped>
      .pricing-panel >>> .title {
        font-size: 24px;
      }
    </style>

    変換後:
    .pricing-panel[data-v-b52c41] .title {
      font-size: 24px;
    }

    とても簡単ですね.しかし、私たちはコンポーネントのパッケージ効果を失ったことを忘れないでください.このコンポーネント内のすべてtitleクラスのスタイルは、孫ノードであっても、これらのスタイルに染まります.
    モジュール式CSS
    モジュール式CSSの流行はReactコミュニティに由来し,コミュニティの迅速な採用を得た.
    Vue.jsはさらに、その強大で簡便な特性にvue-cliによる開箱即用のサポートを加えて、それを別の高さに発展させた.
    では、どのように使用するかを見てみましょう.
    <style module>
      .button {
        color: red
      }
    </style>

    今回はscopedプロパティではなくmoduleを使用します.これは、vue-template-compilerとvue-cliのwebpack構成がこの部分にどのような対応するloaderを採用するかを教え、次のようなCSSを生成することに等しい.
    .ComponentName__button__2Kxy {
      color: red;
    }

    その特殊な点とscopedスタイルとは異なる点は、作成したすべてのクラスがこのコンポーネントの$styleオブジェクトで取得できることです.したがって、このクラスを適用するには、次のようにclassバインドする必要があります.
    <template>
      <button :class="$style.button" />
    </template>
    <style module>
      .button {
        color: red
      }
    </style>

    このコードは、次のHTMLおよび関連するスタイルを生成します.
    <style>
      .ComponentName__button__2Kxy {
        color: red;
      }
    </style>
    <button class=”ComponentName__button__2Kxy”></button>

    その最初の利点は、HMTLでこの要素を表示すると、どのコンポーネントに属しているかをすぐに知ることができます.2つ目のメリットは、すべてが明示的になり、私たちは徹底的な制御権を持っています.奇妙な現象はもうありません.scopedスタイルのように普通のラベルにもdata属性を付けるのとは異なり、これらの普通のラベルは変換後も最初の姿です.
    scopedスタイルの2番目の例を比較して、そのコンポーネントにスタイルを設定する方法を見てみましょう.
    <template>
      <BasePanel :class="$style['pricing-panel']">
        content  </BasePanel>
    </template>
    <style module>
      .pricing-panel {
        width: 300px;
        margin-bottom: 30px;
      }
    </style>

    変換後:
    <style>
      .BasePanel__d17eko1 {
        /* some styles */
      }
      .ComponentName__pricing-panel__a81Kj {
        width: 300px;
        margin-bottom: 30px;
      }
    </style>
    <div class="BasePanel__d17eko1 ComponentName__pricing-panel__a81Kj">
      content</div>

    意外なことに、私たちが期待していた結果と同じです.さらに、すべてのCSSクラスは$styleオブジェクトで取得できるため、propsでこれらのクラスを任意の希望の深さに渡すことができます.これにより、サブコンポーネント内の任意の場所でこれらのクラスを使用することが極めて容易になります.
    <template>
      <BasePanel
        title="Lorem ipsum"
        :titleClass="$style.title"
      >
        Content  </BasePanel>
    </template>

    モジュール式CSSとJSは相互運用性に優れており、これはCSSクラスに限らない.また、exportキーワードを使用して、$styleオブジェクトに他のものをエクスポートすることもできます.
    たとえば、CSSで色変数を定義しながらコンポーネントを使用するためにエクスポートできるグラフを開発する必要があることを想像してみてください.
    <template>
      <div>{{ $style.primaryColor }}</div> <!-- #B4DC47 -->
    </template>
    <style module lang="scss">
      $primary-color: #B4DC47;
    
      :export {
        primaryColor: $primary-color
      }
    </style>

    モジュール式CSSの概念について、私はここでただその毛皮について話しただけで、それは実際には広くて、あなたがその完全な規範を見てもっと理解することをお勧めします.
    まとめ
    実は両方の案は非常に簡単で使いやすく、ある程度同じ問題を解決しています.では、どちらを選ぶべきですか.
    scopedスタイルの使用は余分な知識を必要とせず、快適な感じがします.その限界は、その使用が簡単な理由でもある.小型から中型への応用をサポートします.
    より大きなアプリケーションやより複雑なシーンでは、このときCSSの運用について、より明示的で、より多くの制御権を持つことを望んでいます.テンプレートに$styleを大量に使用すると、それほど「セクシー」ではないように見えますが、より安全で柔軟になります.そのため、私たちはわずかな代価を払うだけです.もう1つの利点は、色値、スタイルブレークポイントなど、定義した変数をJSで取得できることです.これにより、複数のファイルで同期を手動で維持する必要がなくなります.
    本文の訳者について:@西楼聴雨原文:https://juejin.im/post/5b9556446fb9a05d1b2e3613作者:@Will Ockelmann-Wagner原文:https://blog.carbonfive.com/2018/08/13/a-proposal-elixir-style-modules-in-javascript/