Единая система диалоговых окон на vue-cli при помощи vuex и vue-router

—

от автора

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

Концепция

Вся система будет работать довольно просто, для отображения нужного нам диалогового окна надо будет всего лишь изменить один query параметр в адресной строке браузера, для примера назовем этот параметр ‘dialog’. Соответственно для закрытия окна надо будет только убрать параметр dialog.

Само окно будет состоять из четырех блоков:

  1. ‘Dialog-control-panel’ в нем будут располагаться кнопки управления

  2. “Dialog-content” в этой области будут динамически появляться vue компоненты с нужным нам контентом

  3. “Dialog-left-btn” и “Dialog-right-btn” кнопки которые можно вызывать по мере надобности, нужны для переключения контента

Начало работы

Создадим нужные нам компоненты:

  1. “TheDialog.vue” — главный компонент в котором будет все происходить

  2. “DialogAbout.vue” и “DialogContacts.vue” — компоненты с контентом для нашего диалогового окна

Необходимое в vuex

В папке проекта “store” создадим еще одну директорию “dialog”, в ней уже на понадобятся 3 файла “state.js”, “mutations.js” и “index.js”.

Как уже стало понятно, файл “state.js” нужен нам для хранения состояний диалогового окна, в нем я пропишу несколько объектов с полями active и to.

Если в active стоит значение “true”, то данный элемент будет отображаться в диалоговом окне.

Свойство to должно хранить в себе ссылку или же пустую строку.

export default function () {   return {     leftBtn: {       active: false,       to: "",     },     rightBtn: {       active: false,       to: "",     },     downloadBtn: {       active: false,       to: "",     },     backBtn: {       active: false,       to: "",     },   }; } 

Файл “mutations.js” содержит в себе мутации для изменения состояний нашего диалогового окна.

export function changeStatusLeftBtn(state, active = false, to = "") {   state.leftBtn = { active, to }; }   export function changeStatusRightBtn(state, active = false, to = "") {   state.rightBtn = { active, to }; }  export function changeStatusDownloadBtn(state, active = false, to = "") {   state.downloadBtn = { active, to }; }   export function changeStatusBackBtn(state, active = false, to = "") {   state.backBtn = { active, to }; } 

“index.js”  нам нужен для соединения всех файлов в один модуль

import state from './state' import * as mutations from './mutations'   export default {   state,   mutations, } 

После данных манипуляций мы можем добавить модуль dialog в store.

import dialog from "./dialog";     const Store = createStore({     modules: {       dialog,     },   }); 

Наконец мы подошли к главному компоненту “TheDialog.vue”

Разметка

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

<template>   <div class="dialog-bg">     <div class="dialog-control-panel">       <div class="panel">         <div class="btn" v-ripple v-if="backBtn.active">           <q-icon name="eva-arrow-back-outline" />         </div>       </div>         <div class="panel">         <div class="btn" v-ripple v-if="downloadBtn.active">           <q-icon name="eva-cloud-download-outline" />         </div>           <div class="btn" v-ripple>           <q-icon name="eva-close-outline" />         </div>       </div>     </div>       <div class="btn right" v-ripple v-if="rightBtn.active">       <q-icon name="eva-arrow-ios-forward-outline" />     </div>       <div class="btn left" v-ripple v-if="leftBtn.active">       <q-icon name="eva-arrow-ios-back-outline" />     </div>       <div class="dialog-content">       <component :is="requiredModule" />     </div>   </div> </template>

Логика

<script> import DialogAbout from "components/dialog/DialogAbout"; import DialogContacts from "components/dialog/DialogContacts"; import { defineComponent, computed } from "vue"; import { useRoute } from "vue-router"; import { useStore } from "vuex";   export default defineComponent({   name: "TheDialog",     setup() {     const $store = useStore();     const $route = useRoute();       const requiredModule = computed(() => {       const dialog = $route.query.dialog;         if (dialog === "about") return DialogAbout;       if (dialog === "contacts") return DialogContacts;         return false;     });       const backBtn = $store.state.dialog.backBtn;     const downloadBtn = $store.state.dialog.downloadBtn;     const leftBtn = $store.state.dialog.leftBtn;     const rightBtn = $store.state.dialog.rightBtn;       return {       requiredModule,       backBtn,       downloadBtn,       leftBtn,       rightBtn,     };   }, }); </script> 

Здесь нет ничего сложного, просто из функции setup мы возвращаем нужные нам состояния для отображения кнопок и результат computed функции.

Добавим немного стилей

<style lang="scss" scoped> .dialog-bg {   width: 100%;   min-height: 100vh;   background-color: rgba(30, 30, 30, 0.9);   position: fixed;   left: 0;   top: 0;   z-index: 10;   padding: 100px 0;     .btn {     width: 80px;     height: 80px;     color: rgba(255, 255, 255, 0.637);     font-size: 1.8rem;     display: flex;     justify-content: center;     align-items: center;     cursor: pointer;     position: relative;     transition: background-color 0.2s;       &:hover {       background-color: rgba(0, 0, 0, 0.2);     }   }     .dialog-control-panel {     width: 100%;     display: flex;     justify-content: space-between;     position: fixed;     top: 0;     left: 0;       .panel {       display: flex;     }   }     .right,   .left {     position: fixed;     height: calc(100vh - 160px);     top: 80px;   }     .right {     right: 0;   }     .left {     left: 0;   }     .dialog-content {     max-width: 732px;     margin: auto;   } } </style> 

Результат

Все! Наше диалоговое окно готово.


ссылка на оригинал статьи https://habr.com/ru/articles/593407/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *