Поиск по сайту:

Как создать модальный компонент с помощью Vue.js


Введение

Модальные окна — это соглашение о пользовательском интерфейсе, чтобы направить внимание пользователя на фрагмент контента, который ему нужно прочитать или с которым нужно взаимодействовать. Они, как правило, принимают форму небольших блоков контента непосредственно в поле зрения пользователя с каким-то фоном, либо затемняющим, либо скрывающим остальную часть контента на странице. Если пользователь хочет вернуться на страницу, он должен задействовать модальное окно или, возможно, закрыть его.

В этой статье вы узнаете, как создать повторно используемый модальный компонент, используя переходы и слоты в Vue.js.

Предпосылки

Для выполнения этого урока вам понадобятся:

  • Node.js установлен локально, что можно сделать, следуя инструкциям по установке Node.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

Если вы откроете локальное приложение (обычно по адресу localhost:8080) в веб-браузере, вы увидите сообщение Добро пожаловать в ваше приложение Vue.js.

Установив эти строительные леса, вы можете начать работу над модальным компонентом.

Шаг 2 — Создание модального компонента

Сначала внутри каталога проекта создайте новый файл Modal.vue в разделе src/components.

Начнем с определения шаблона. Вам понадобится div для тени фона, div для действия в качестве модального поля и некоторые элементы для определения его структуры:

<template>
  <div class="modal-backdrop">
    <div class="modal">
      <slot name="header">
      </slot>

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

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

Вы можете использовать props для создания заголовка, тела и нижнего колонтитула, но использование слотов обеспечит большую гибкость.

Использование слотов позволяет повторно использовать одно и то же модальное окно с различными типами содержимого тела.

Вы можете использовать модальное окно для отображения сообщения, но вы можете повторно использовать одно и то же модальное окно с формой для отправки запроса.

Хотя реквизитов обычно достаточно для создания компонента, предоставление HTML через реквизит потребует от нас использования v-html для его рендеринга, что может привести к XSS-атакам.

Здесь вы используете именованные слоты, чтобы разрешить использование более одного слота в одном компоненте.

Когда вы определяете именованный слот, все, что вы идентифицируете с этим именем, будет отображаться вместо исходного слота. Думайте об этом как о заполнителе. Как и заполнитель, слот также может иметь содержимое по умолчанию, которое будет отображаться, если оно не предоставлено.

Поскольку предоставленный контент заменяет тег <slot>, чтобы гарантировать, что разделы имеют нужные классы, вам нужно будет обернуть каждый слот.

Давайте установим некоторые значения по умолчанию для слотов, элементов-оболочек и начального CSS, чтобы он выглядел как базовый модальный.

Над шаблоном добавьте имя компонента и способ закрытия модала:

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

Затем измените шаблон, чтобы обернуть слоты, указать значения по умолчанию, а также отобразить кнопки для закрытия модального окна:

<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>

Далее под шаблоном добавляем стили для компонента:

<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, чтобы изменить шаблон и добавить showModal, closeModal и isModalVisible:

<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 и отображает кнопку Open Modal для взаимодействия.

Примечание. В файле App.js вы можете дополнительно указать slots и заменить содержимое по умолчанию:

<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>

Просмотрите приложение в своем веб-браузере и убедитесь, что модальное окно ведет себя должным образом, открывая и закрывая его.

Шаг 3 — Добавление переходов

Вы можете сделать его открытие и закрытие более плавным, используя переход.

Vue предоставляет компонент-оболочку под названием transition, который позволяет добавлять переходы для входа и выхода. Этот компонент-оболочку можно использовать для любого элемента или компонента, и они допускают перехваты как CSS, так и JavaScript.

Каждый раз, когда компонент или элемент, заключенный в transition, вставляется или удаляется, Vue проверяет, есть ли у данного элемента переходы CSS, и добавляет или удаляет их в нужное время. То же самое верно и для хуков JavaScript, но в этом случае вы будете использовать только CSS.

Когда элемент добавляется или удаляется, для переходов ввода и вывода применяются шесть классов. Перед каждым из них будет стоять название перехода.

Во-первых, давайте начнем с добавления компонента-оболочки перехода в модальное окно:

<template>
  <transition name="modal-fade">
    <div class="modal-backdrop">
      <div class="modal">
        ...
      </div>
    </div>
  </transition>
</template>

Теперь давайте добавим переход для медленного исчезновения непрозрачности с помощью примененных классов:

<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, а переход CSS для свойства opacity будет применен поверх .5 секунд с функцией синхронизации анимации ease.

При выходе из модального режима он будет делать обратное. Будет применен класс modal-fade-leave-active, и модальное окно исчезнет.

Просмотрите приложение в своем веб-браузере и убедитесь, что модальное окно появляется и исчезает.

Шаг 4 — Добавление специальных возможностей

Вы захотите сделать свой модальный компонент доступным с помощью атрибутов ARIA.

Добавление role=dialog поможет вспомогательному программному обеспечению идентифицировать компонент как диалоговое окно приложения, отделенное от остальной части пользовательского интерфейса.

Вам также потребуется правильно пометить его атрибутами aria-labelledby и aria-describedby.

И добавьте атрибуты aria-label к кнопкам закрытия.

<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>

Окончательная версия модального компонента теперь должна выглядеть так:

<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, где вы найдете упражнения и проекты по программированию.