Frontend: Приложение Vue с использованием паттерна Vuex в проекте Gemosystem

Терминология и описание

Если мы говорим о разработке приложения на Vue.js, то web-страница представляет собой взаимодействующие между собой компоненты. Компонент - переиспользуемый экземпляр Vue, имеющий название (https://ru.vuejs.org/v2/guide/components.html). Это специальная абстракция, позволяющая собрать приложение из небольших кусочков, представляющих из себя древовидную структуру. Любой компонент можно переиспользовать (в том числе, рекурсивно).

Поскольку в нашем проекте встречаются компоненты различного назначения, следует уточнить терминологию:
1. Компоненты, выделенные отдельно внутри каталога gemosystem/frontend/components для удобства последующего переиспользования. Их имеют ввиду, когда говорят "компоненты". Среди них есть "чистые" компоненты, начинающиеся с "Base..." (см. "Именование базовых компонентов").
3. Компоненты, созданные для отрисовки тех или иных страниц, или частей страниц. Называются views, "вьюхи" (gemosystem/frontend/views)
4. Компоненты, созданные для управление состоянием приложения: gemosystem/frontend/store. Их имеют ввиду, когда говорят о Vuex, хранилище, мутациях и экшенах.

Vuex

Vuex - паттерн общего хранилища состояний приложения. Обычно состоит из 3-х базовых категорий: Actions, Mutations и States (https://vuex.vuejs.org/ru/).

Важно следить за соблюдением этого принципа, не пытаться обратиться и поменять свойства компонента или содержимое страницы "грязным" способом, обращаясь напрямую к DOM или используя другие JS-фреймворки.

Frontend: Приложение Vue с использованием паттерна Vuex в проекте Gemosystem

SPA

Принято решение (начало 2018г) о плавном переносе всего функционала ГС на архитектуру SPA (PHP бэк + Vue.js фронт). На момент принятия решения в проекте уже использовались компоненты Vue.js (как предварительно собранный webpack-ом скрипт, так и подгрузка vue.js как внешнего скрипта). Весь этот код подлежит рефакторингу, переносу функционала в виде новых компонентов SPA-приложения. Его структура и функционал вне рамок этой статьи.

Vue.js Code style

При разработке и ревью предлагается следовать официальным рекомендациям от разработчиков Vue.js https://ru.vuejs.org/v2/style-guide/article/1

Структура приложения

https://github.com/vuejs/vuex/tree/dev/examples
https://itnext.io/how-to-structure-a-vue-js-project-29e4ddc1aeeb

/frontend   // корневой каталог для фронта.
   /components   // каталог для компонентов. Тут хранятся только файлы *.vue (как правило, однофайловые). 
      /src           // для случая, когда компонент оказывается большим, он дробится на html-, js- и scss-составляющие, которые помещаются сюда в подкаталог с соответствующим названием
         /TheMainLayout  // каталог содержит встраиваемые в TheMainLayout.vue файлы
            script.js        // js-составляющая, всегда имеет название script.js
            style.scss       // scss-составляющая, всегда имеет название style.scss
            template.html    // html-составляющая, всегда имеет название template.html
      /User      // группа логически связанных компонентов объединяется в один подкаталог
         /src       // внутри группы компонентов так же может присутствовать каталог src для компонентов, требующих разделения на составляющие. Принцип расположения файлов идентичен указанному выше.
         Info.vue
         NameLabel.vue
         Photo.vue
      BaseAlert.vue  // однофайловый "чистый" компонент (подробнее о том, что это в статье "Именование базовых компонентов" у официалов)
      BaseAvatar.vue
      SideBar.vue
      TheMainLayout.vue // компонент, всегда присутствующий в единственном экземпляре на странице 
   /resource     // каталог ресурсов, созданных и поддерживаемых вне фреймворка Vue
      /Bootstrap     // корпоративный стиль для Bootstrap 4
         /Theme
            /Main
               bootstrap.scss
   /store        // каталог для модулей, описывающих хранилища состояний
      Auth.js        // дополнительный модуль хранилища состояний
      Main.js        // основное хранилище состояний, в котором подключаются дополнительные модули
   /views        // Файлы представлений. Обычно соотносятся со страницами приложения. 
      /shift         // каталог представлений бизнес-модуля (в данном случае - кассовая смена)
         /open          // логическая часть модуля (открытие кассовой смены)
            CurrentWorkshift.vue   // отдельная страница (текущая кассовая смена)
   Api.js        // компонент для взаимодействия с Api. 
   App.js        // главный файл (точка входа) приложения, в котором происходит монтирование в DOM
   AppConfig.js  // настройки приложения
   Routes.js     // динамический роутинг. Определяет зависимость адресной строки браузера и загружаемых модулей.
/www     // домашний каталог веб-сервера
   /Resource     // ресурсы, доступные для загрузки браузером
      /App          // базовый каталог для сборки всех модулей приложения
         Shift.js    // файл сборки. Генерируется автоматически сборщиком webpack.

Куда помещать новый компонент при разработке функционала?

Если ваш функционал может стать частью SPA-приложения (web-страница была или будет целиком создана на Vue.js в рамках описанной здесь архитектуры), то компонент следует создавать и помещать в проект согласно логике, описанной в этой статье.

Если вы стремитесь добавить новый функционал рядом со старым кодом, заставить Vue.js взаимодействовать с jQuery или другим кодом на странице - имейте ввиду, что ваш код в последствии будет переписан вместе с переносом всей логики в новый модуль SPA-приложения. В этом случае, размещайте Vue-компонент рядом с вашим PHP-сервисом, добавляйте его в Webpack для сборки отдельным файлом, который потом подгрузите в старый код (пример: gemosystem/src/Report/Service/Detail).

Структура Vue-компонента

Обычно компонент состоит из 3 частей

  1. html - шаблон, начинается с тега <template>
  2. javascript - логика, взаимодействие с другими компонентами, инициирование процессов на основе событий, представлена в виде js-модуля с указанием export-ов.
  3. style - стиль компонента, для корневых элементов допускается использовать внешний css-файл; стили для вложенных компонентов указываются в теге style с указанием параметра scoped.

Эти части рекомендуется располагать в одном файле, однако при большом количестве кода стоит разбить файл на 3 с соответствующими расширениями, и поместить их в каталог ./src/{ComponentName}/.
Также Code Style требует придерживаться всегда одинакового порядка указания этих трех частей, поэтому мы всегда указываем в порядке template - script - style.

Мы в команде также стремимся придерживаться правила делать комментарии в верхней части Vue-файла о назначении компонента и (не обязательно) его явных зависимостях (к примеру, от геттеров хранилища, или от событий другого компонента)

Html

Заключен в обрамляющий тэг <template> и должен иметь только один корневой элемент. 
Подробнее https://ru.vuejs.org/v2/guide/syntax.html

<template>
    <div class="recount-form">
       <!-- Официальный Code Style допускает наименования и в CamelCase, но предлагает использовать kebab-case, если он используется всегда. Мы за единообразие, 
поэтому у нас принято указывать в шаблонах Vue-компоненты так, как показано ниже -->
       <other-component 
          :prop-1="{a:'1', b:'2'}" 
          @explode="method1" 
       ></other-component>
       <!-- Вот так именовать плохо: официалы запрещают использовать аббревиатуры, а мы - CamelCase -->
       <SPComponent></SPComponent>
       <!-- Тоже плохо: комплексное условие в v-if следует вынести в отдельное вычисляемое свойство -->
       <x-report v-if="loading === false && state !== CLOSED && printerState === SUCCESS"></x-report>
       <!-- Смешивать сокращенные и полные директивы - плохо, для единообразия используем директивы с префиксом "v-" -->
       <report :short-directive="value" v-on:full-directive="onEvent"></report>
    </div>
</template>

Javascript

Обращаем внимание на порядок опций копонента.

'use strict';

import './OtherComponent.vue'; // импорт нужных компонентов/модулей и пр.
import ...;

// рекомендуется соблюдать порядок опций компонента

export default {
   // глобальные опции
   name: 'Abc',

   // зависимости
   components: {
      // дочерние компоненты (требуется их импорт)
      OtherComponent, ...
   },

   // интерфейс компонента
   props: {
      // входные параметры, требуется всегда указывать их тип и по возможности валидировать
      id: {
         type: String,
         default: 'alert-message'
      },
      ...
   },

   // локальное состояние
   data: function() {
      // приватные свойства, используемые внутри компонента, представлены в виде функции
      return {
         ...
      }
   },
   computed: {
      // вычисляемые свойства
      ... 
   }

   // события
   mounted: function() {
     // метод, срабатывающий при монтировании компонента (своего рода, конструктор)
     ...
   },
   destroyed: function() {
     ...
   },

   // нереактивные свойства
   methods:  {
      // методы компонента
      method1: function() {
         this.$emit('some event', {someData:{...}}); // инициирование события и передача его родителю (так делать с осторожностью, лучше общаться через хранилище)
      }
   },

   // отрисовка
   template: '&lt;pre&gt;&lt;/pre&gt;'
}

Style

Можно использовать как обычный CSS, так и SASS (https://sass-scss.ru/).

В первом случае:

<style scoped>
.component .class p {
   color: #cba034;
}
</style>

Во втором случае:

<style lang="scss" scoped>
.component {
   .class {
       p {
           color: #cba034;
       }
   }
}
</style>

Кроме того, у нас используется Bootstrap 4 с помощью импорта npm-пакета (достаточно сделать это 1 раз в приложении, чтобы получить стили фреймворка)

import bootstrap from 'bootstrap';

Так же можно подключить файл с темой на основе корпоративного стиля (или любой другой вспомогательный файл стилей) следующими способами:

<!-- Предпочтительный вариант -->
<style type="text/scss" lang="scss" src="frontend/resource/Bootstrap/Theme/Main/bootstrap.scss"></style>

<!-- Обычный CSS -->
<link rel="stylesheet" href="/Resource/Bootstrap/Theme/Main/bootstrap.theme.css" />

<!-- Внутри блока с SCSS-кодом -->
<style lang="scss">
@import 'frontend/resource/Bootstrap/Theme/Main/bootstrap.scss';
</style>

<!-- Внутри блока с JS-кодом -->
<script>
import 'frontend/resource/Bootstrap/Theme/Main/bootstrap.scss';
</script>

 


22.12.2010 09:06

Комментарии

Комментариев пока нет.


Copyrights © 2007 - 2026 YaPro.Ru