序章

モーダルは、ユーザーが読んだり操作したりする必要のあるコンテンツにユーザーの注意を向けるためのユーザーエクスペリエンスの慣習です。 これらは、ユーザーの視界に直接ある小さなコンテンツブロックの形をとる傾向があり、ページ上の残りのコンテンツを覆い隠したり隠したりする何らかの背景があります。 ユーザーがページに戻りたい場合は、モーダルを使用するか、場合によってはそれを却下する必要があります。

この記事では、Vue.jsのトランジションとスロットを使用して再利用可能なモーダルコンポーネントを作成する方法を学習します。

前提条件

このチュートリアルを完了するには、次のものが必要です。

ステップ1—プロジェクトの設定

@ vue / cli を使用して、新しいVue.jsプロジェクトを作成できます。

ターミナルウィンドウで、次のコマンドを使用します。

  1. npx @vue/cli create --default vue-modal-component-example

これは、Vue.jsプロジェクトを作成するためのデフォルト構成を使用します。

新しく作成されたプロジェクトディレクトリに移動します。

  1. cd vue-modal-component-example

プロジェクトを開始して、エラーがないことを確認します。

  1. npm run serve

Webブラウザでローカルアプリ(通常はlocalhost:8080)にアクセスすると、"Welcome to Your Vue.js App"メッセージが表示されます。

この足場を設定すると、モーダルコンポーネントの作業を開始できます。

ステップ2—モーダルコンポーネントの作成

まず、プロジェクトディレクトリ内で、src/componentsの下に新しいModal.vueファイルを作成します。

テンプレートを定義することから始めましょう。 背景シェード用のdiv、モーダルボックスとして機能するdiv、およびその構造を定義するためのいくつかの要素が必要になります。

src / components / Modal.vue
<template>
  <div class="modal-backdrop">
    <div class="modal">
      <slot name="header">
      </slot>

      <slot name="body">
      </slot>

      <slot name="footer">
      </slot>
    </div>
  </div>
</template>

小道具を使用してヘッダー、本文、フッターを提供することもできますが、スロットを使用すると柔軟性が高まります。

slot を使用すると、同じモーダルをさまざまなタイプのボディコンテンツで再利用できます。

モーダルを使用してメッセージを表示することもできますが、同じモーダルをフォームで再利用してリクエストを送信することもできます。

通常、プロップはコンポーネントを構築するのに十分ですが、プロップを介してHTMLを提供するには、v-htmlを使用してレンダリングする必要があります。これにより、XSS攻撃が発生する可能性があります。

ここでは、名前付きスロットを使用して、同じコンポーネントで複数のスロットを使用できるようにしています。

名前付きスロットを定義すると、元のスロットの代わりに、その名前で識別したものがすべてレンダリングされます。 プレースホルダーと考えてください。 プレースホルダーと同様に、スロットには、何も提供されていない場合にレンダリングされるデフォルトのコンテンツを含めることもできます。

提供されるコンテンツは<slot>タグに置き換わるため、セクションに必要なクラスがあることを保証するには、各スロットをラップする必要があります。

スロット、ラッパー要素、および初期CSSにいくつかのデフォルトを設定して、基本的なモーダルのように見せましょう。

テンプレートの上に、モーダルを閉じるためのコンポーネント名とメソッドを追加します。

src / components / Modal.vue
<script>
  export default {
    name: 'Modal',
    methods: {
      close() {
        this.$emit('close');
      },
    },
  };
</script>

次に、テンプレートを変更してスロットをラップし、デフォルト値を提供し、モーダルを閉じるためのボタンも表示します。

src / components / Modal.vue
<template>
  <div class="modal-backdrop">
    <div class="modal">
      <header class="modal-header">
        <slot name="header">
          This is the default title!
        </slot>
        <button
          type="button"
          class="btn-close"
          @click="close"
        >
          x
        </button>
      </header>

      <section class="modal-body">
        <slot name="body">
          This is the default body!
        </slot>
       </section>

      <footer class="modal-footer">
        <slot name="footer">
          This is the default footer!
        </slot>
        <button
          type="button"
          class="btn-green"
          @click="close"
        >
          Close Modal
        </button>
      </footer>
    </div>
  </div>
</template>

次に、テンプレートの下に、コンポーネントのスタイルを追加します。

src / components / Modal.vue
<style>
  .modal-backdrop {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    background-color: rgba(0, 0, 0, 0.3);
    display: flex;
    justify-content: center;
    align-items: center;
  }

  .modal {
    background: #FFFFFF;
    box-shadow: 2px 2px 20px 1px;
    overflow-x: auto;
    display: flex;
    flex-direction: column;
  }

  .modal-header,
  .modal-footer {
    padding: 15px;
    display: flex;
  }

  .modal-header {
    position: relative;
    border-bottom: 1px solid #eeeeee;
    color: #4AAE9B;
    justify-content: space-between;
  }

  .modal-footer {
    border-top: 1px solid #eeeeee;
    flex-direction: column;
    justify-content: flex-end;
  }

  .modal-body {
    position: relative;
    padding: 20px 10px;
  }

  .btn-close {
    position: absolute;
    top: 0;
    right: 0;
    border: none;
    font-size: 20px;
    padding: 10px;
    cursor: pointer;
    font-weight: bold;
    color: #4AAE9B;
    background: transparent;
  }

  .btn-green {
    color: white;
    background: #4AAE9B;
    border: 1px solid #4AAE9B;
    border-radius: 2px;
  }
</style>

これらすべての要素を組み合わせて、モーダルコンポーネントを完成させます。 この新しいコンポーネントをApp.vueにインポートして、動作を観察できます。

App.vueを変更してテンプレートを変更し、showModalcloseModal、およびisModalVisibleを追加します。

src / App.vue
<template>
  <div id="app">
    <button
      type="button"
      class="btn"
      @click="showModal"
    >
      Open Modal!
    </button>

    <Modal
      v-show="isModalVisible"
      @close="closeModal"
    />
  </div>
</template>

<script>
  import modal from './components/Modal.vue';

  export default {
    name: 'App',
    components: {
      Modal,
    },
    data() {
      return {
        isModalVisible: false,
      };
    },
    methods: {
      showModal() {
        this.isModalVisible = true;
      },
      closeModal() {
        this.isModalVisible = false;
      }
    }
  };
</script>

このコードは、Modalコンポーネントをインポートし、 OpenModalボタンを表示して操作します。

注: App.jsファイルでは、オプションでslotsを参照し、デフォルトのコンテンツを置き換えることができます。

src / App.js
<Modal
  v-show="isModalVisible"
  @close="closeModal"
>
  <template v-slot:header>
    This is a new modal header.
  </template>

  <template v-slot:body>
    This is a new modal body.
  </template>

  <template v-slot:footer>
    This is a new modal footer.
  </template>
</Modal>

Webブラウザーでアプリケーションを表示し、モーダルを開いたり閉じたりして、モーダルが期待どおりに動作することを確認します。

ステップ3—トランジションを追加する

トランジションを使用すると、スムーズに開閉するように見せることができます。

Vueには、transitionと呼ばれるラッパーコンポーネントが用意されており、出入りするためのトランジションを追加できます。 このラッパーコンポーネントは、任意の要素またはコンポーネントに使用でき、CSSフックとJavaScriptフックの両方を許可します。

transitionでラップされたコンポーネントまたは要素が挿入または削除されるたびに、Vueは指定された要素にCSS遷移があるかどうかを確認し、適切なタイミングでそれらを追加または削除します。 JavaScriptフックについても同じことが言えますが、この場合はCSSのみを使用します。

要素が追加または削除されると、6つのクラスが入退場遷移に適用されます。 それらのそれぞれには、トランジションの名前が接頭辞として付けられます。

まず、トランジションラッパーコンポーネントをモーダルに追加することから始めましょう。

src / components / Modal.vue
<template>
  <transition name="modal-fade">
    <div class="modal-backdrop">
      <div class="modal">
        ...
      </div>
    </div>
  </transition>
</template>

次に、適用されたクラスを使用して、不透明度がゆっくりとフェードするトランジションを追加しましょう。

src / components / Modal.vue
<style>
  ...

  .modal-fade-enter,
  .modal-fade-leave-to {
    opacity: 0;
  }

  .modal-fade-enter-active,
  .modal-fade-leave-active {
    transition: opacity .5s ease;
  }
</style>

最初、モーダルはopacityプロパティ値0で非表示になります。

モーダルが開くと、.modal-fade-enter-activeクラスが適用され、opacityプロパティのCSS遷移が、easeアニメーションタイミングで.5秒にわたって適用されます。働き。

モーダルを離れるとき、それは逆を行います。 modal-fade-leave-activeクラスが適用され、モーダルがフェードアウトします。

Webブラウザーでアプリケーションを表示し、モーダルがフェードインおよびフェードアウトすることを確認します。

ステップ4—アクセシビリティの追加

ARIA属性を使用してモーダルコンポーネントにアクセスできるようにする必要があります。

role="dialog"を追加すると、補助ソフトウェアがコンポーネントを他のユーザーインターフェイスから分離されたアプリケーションダイアログとして識別するのに役立ちます。

また、aria-labelledbyおよびaria-describedby属性で適切にラベル付けする必要があります。

そして、aria-label属性を閉じるボタンに追加します。

src / components / Modal.vue
<template>
  <transition name="modal-fade">
    <div class="modal-backdrop">
      <div class="modal"
        role="dialog"
        aria-labelledby="modalTitle"
        aria-describedby="modalDescription"
      >
        <header
          class="modal-header"
          id="modalTitle"
        >
          <slot name="header">
            This is the default title!
          </slot>
          <button
            type="button"
            class="btn-close"
            @click="close"
            aria-label="Close modal"
          >
            x
          </button>
        </header>

        <section
          class="modal-body"
          id="modalDescription"
        >
          <slot name="body">
            This is the default body!
          </slot>
        </section>

        <footer class="modal-footer">
          <slot name="footer">
            This is the default footer!
          </slot>
          <button
            type="button"
            class="btn-green"
            @click="close"
            aria-label="Close modal"
          >
            Close Modal
          </button>
        </footer>
      </div>
    </div>
  </transition>
</template>

モーダルコンポーネントの最終バージョンは、次のようになります。

src / components / Modal.vue
<script>
  export default {
    name: 'Modal',
    methods: {
      close() {
        this.$emit('close');
      },
    },
  };
</script>

<template>
  <transition name="modal-fade">
    <div class="modal-backdrop">
      <div class="modal"
        role="dialog"
        aria-labelledby="modalTitle"
        aria-describedby="modalDescription"
      >
        <header
          class="modal-header"
          id="modalTitle"
        >
          <slot name="header">
            This is the default tile!
          </slot>
          <button
            type="button"
            class="btn-close"
            @click="close"
            aria-label="Close modal"
          >
            x
          </button>
        </header>

        <section
          class="modal-body"
          id="modalDescription"
        >
          <slot name="body">
            This is the default body!
          </slot>
        </section>

        <footer class="modal-footer">
          <slot name="footer">
            This is the default footer!
          </slot>
          <button
            type="button"
            class="btn-green"
            @click="close"
            aria-label="Close modal"
          >
            Close me!
          </button>
        </footer>
      </div>
    </div>
  </transition>
</template>

<style>
  .modal-backdrop {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    background-color: rgba(0, 0, 0, 0.3);
    display: flex;
    justify-content: center;
    align-items: center;
  }

  .modal {
    background: #FFFFFF;
    box-shadow: 2px 2px 20px 1px;
    overflow-x: auto;
    display: flex;
    flex-direction: column;
  }

  .modal-header,
  .modal-footer {
    padding: 15px;
    display: flex;
  }

  .modal-header {
    position: relative;
    border-bottom: 1px solid #eeeeee;
    color: #4AAE9B;
    justify-content: space-between;
  }

  .modal-footer {
    border-top: 1px solid #eeeeee;
    flex-direction: column;
  }

  .modal-body {
    position: relative;
    padding: 20px 10px;
  }

  .btn-close {
    position: absolute;
    top: 0;
    right: 0;
    border: none;
    font-size: 20px;
    padding: 10px;
    cursor: pointer;
    font-weight: bold;
    color: #4AAE9B;
    background: transparent;
  }

  .btn-green {
    color: white;
    background: #4AAE9B;
    border: 1px solid #4AAE9B;
    border-radius: 2px;
  }

  .modal-fade-enter,
  .modal-fade-leave-to {
    opacity: 0;
  }

  .modal-fade-enter-active,
  .modal-fade-leave-active {
    transition: opacity .5s ease;
  }
</style>

これは、アクセシビリティとトランジションを備えたモーダルコンポーネントの基礎です。

結論

この記事では、Vue.jsを使用してモーダルコンポーネントを構築しました。

slotsを使用してコンポーネントを再利用できるようにし、transitionsを使用してユーザーエクスペリエンスを向上させ、ARIA属性を使用してコンポーネントをよりアクセスしやすくしました。

Vue.jsの詳細については、Vue.jsトピックページで演習とプログラミングプロジェクトを確認してください。