Pull to refresh

Vue.js и как его понять

Reading time 8 min
Views 47K
В своей работе, мне относительно недавно пришлось столкнуться с фреймворком Vue.js, т.к. до этого, я занимался в основном backend разработкой, пришлось со многим разбираться и многое было сложновато понять, особенно, когда раньше использовал только jQuery. В рамках данной статьи, я хочу помочь своему читателю разобраться с теми проблемами в понимании, с которыми столкнулся я. Конечно проблемы на этапе изучения чего-то нового у всех возникают разные, но и не мало тех, у кого они будут похожи, именно на это и будет направлена данная статья.

Я не буду проводить сравнение данного фреймворка с другими, думаю, что по этому поводу в интернете информации хватает, попытаемся разобраться именно с Vue.js и с “чем его едят?!”. В данном контексте будут рассматриваться примеры для сборки с помощью webpack или подобным системам. Примеры компонентного взаимодействия будут на примере однофайловых компонентов, поскольку они немного проще в понимании. Однако, принципы взаимодействия однофайловых и многофайловых компонентов ничем особо не отличаются.

Рассматриваемые аспекты


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

Итак, первое с чем приходится столкнуться новичкам и испытать определенные сложности — это не jQuery, и работает он иначе. Vue предоставляет реактивные связки своих переменных внутри компонентов и при взаимодействии с другими компонентами, что открывает существенно новые возможности. Да на jQuery это все можно организовать тоже, но более “толстым” кодом и кучей обработчиков, в которых можно запутаться. Если разобраться с Vue, на нем все это делается гораздо проще.

Сразу дам небольшой совет: “Не нужно пытаться провести аналогии написанного с jQuery!”, чем больше будет попыток провести аналогию, тем больше будет путаницы и непонимания.

Области видимости переменных


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

В любом компоненте Vue имеется набор данных называемых “props”. Это объект содержащий в себе те данные, которые могут быть определены при вызове компонента или иметь значение по умолчанию.

Пример объявления свойств компонента:

/**------**/
props: {
   uuid: {
       type: String,
       default: '',
   },
},
/**------**/

В данном примере, мы указываем, что в нашем компоненте есть некий uuid, который является строкой и по умолчанию он является пустой строкой.

Кроме этого, в компоненте содержится объект data{}, который выполняет взаимодействие нашего компонента, с какими-либо другими, которые мы можем использовать в своем. В Vue является нормальной практикой, когда один компонент, может в себе совмещать несколько других, для их объединения. data, часто объявляется как функция, такую практику вы встретите наиболее часто на форумах и сообществах, обсуждающих реализацию на Vue

/**------**/
data() {
   return {
       dialog: false,
       indeterminate: false,
       loading: false,
       notifications: false,
       sound: true,
       widgets: false,
   }
},
/**------**/

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

Кроме этого, в общем объекте компонента задаются методы (функции), для работы с этими переменными и событиями внутри компонента. В зависимости от того, где они вызываются, они должны располагаться в определенных объектах. Более подробно, про них, вы можете ознакомиться в официальной документации, там вопросов вроде бы не возникает. Мы же говорим об области видимости. Поэтому рассмотрим пример:

<template>
   <div id="inspire">
      <v-dialog v-model="alert" max-width="290">
         <v-toolbar
            color="primary"
            >
            <v-toolbar-title>Внимание</v-toolbar-title>
            <v-spacer></v-spacer>
            <div class="dialog-close-button" @click="alert=false">
               <i class="fas fa-times"></i>
            </div>
         </v-toolbar>
         <v-card>
            <v-card-text>{{ alertMessage }}</v-card-text>
         </v-card>
      </v-dialog>
   </div>
</template>

В данном примере, мы в своем компоненте создаем шаблон, в котором вызываем компонент Vuetify dialog

Для работы с ним, на понадобится модель alert, которая будет указывать на то открыто ли это окно сейчас или закрыто (соответственно true или false), а так же переменная alertMessage — которая будет в себе нести сообщение об ошибке или предупреждении. Каждому свойству, например color или max-width мы можем задать переменные, которые должны находиться в объекте data(){}, и с помощью своих методов изменять их. Но для простоты ограничимся двумя. Итак для управления этими свойствами, мы должны правильно распределить объекты внутри скрипта компонента.

<script>
    export default {
        data() {
            return {

                /**------------**/
                alert: false,
                alertMessage: 'У вас нет прав на это действие',
            }
        },
        methods: {
            deleteObject() {

                axios.delete(‘http: //example.com/’)
                        .then(response => {

                          /** ------- **/

                        })
                        .catch(error => {
                            this.alert = true;
                            this.alertMessage = “Что - то пошло не так”;
                        });

                    },

            },
            /**----------**/
</script>

На данном примере видно, что у нас есть некий метод deleteObject(), заданный в объекте methods, который делает запрос на удаление чего-то на сайте example.com, каким то образом обрабатывает ответ, а в случае провала выбрасывает исключение, в котором, уже мы вызываем наш компонент диалог, присваивая переменной alert значение true и присваиваем сообщение, которое будет выведено в шаблоне. Теперь обратите внимание, что в шаблоне, мы обращаемся к переменным в дате напрямую, просто указывая их название, а в методах, через объект this. Все методы, где бы они не были заданы, если они работают с data, они используют эти переменные через this. Если один метод, должен вызывать какой-то другой, определенный в объекте methods, он тоже вызывается через this.methodName().

Также обратите внимание на обработчик события клика в шаблоне:

<div class="dialog-close-button" @click="alert=false"><!--/**------**/ !--></div>

Здесь можно без метода изменить значение переменной alert в data, и поскольку она реактивно связана с моделью — компонент сразу отреагирует на ее изменение.

В данном случае, тем кто привык работать с классическими объектами можно запутаться, потому что связь выглядит немного нелогичной. Но на самом деле, никакой магии здесь нет. Когда мы вызываем экземпляр класса Vue и подключаем туда компоненты, он их интерпретирует через собственные объекты внутри js-фреймворка, именно поэтому у него образуется некое подобие собственной области видимости.

Передача данных между компонентами


Часто из нашего компонента, мы должны управлять состоянием других компонентов, вызванных внутри нашего. Как я уже писал выше, для этого существует объект `props`, а передача осуществляется путем присвоения этого значения, либо с помощью нашей переменной в data либо сразу присвоением значения этому свойству.

В нашем же примере, который я использовал выше уже это есть, для удобства, я продублирую его снова, и постараюсь объяснить:

<template>
   <div id="inspire">
      <v-dialog v-model="alert" max-width="290">
         <v-toolbar
            color="primary"
            >
            <v-toolbar-title>Внимание</v-toolbar-title>
            <v-spacer></v-spacer>
            <div class="dialog-close-button" @click="alert=false">
               <i class="fas fa-times"></i>
            </div>
         </v-toolbar>
         <v-card>
            <v-card-text>{{ alertMessage }}</v-card-text>
         </v-card>
      </v-dialog>
   </div>
</template>

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

<v-toolbar
           color="primary"
   >, <!-- /**------**/ !-->

В котором объявлено свойство color. Именно это свойство должно быть задано внутри скриптов компонента <v-toolbar>. В данном примере, мы присвоили ему определенное значение. Но мы его можем менять. Если нам требуется его динамически изменять, мы можем забиндить слежение этого свойства за нашей переменной, тогда в шаблон немного изменится:

 <v-toolbar
           :color="toolbarColor"
   >,<!-- /**------**/ !-->

В объекте data, мы должны объявить эту переменную, тогда мы сможем ее изменять методами нашего компонента, указанными в объекте methods:

<script>
    export default {
        data() {
            return {
                /*------*/
                toolbarColor: ’primary’,
            }
        },
        /** --- **/
</script>

Теперь мы можем объявить метод, и изменять переменную toolbarColor внутри него, используя конструкцию this.toolbarColor = “Значение”, и компонент <v-toolbar> будет на нее реагировать.

Таким образом, мы можем передавать значения в дочерние компоненты.

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

Есть еще один хороший способ, использование библиотеки Vuex, которая создает некое хранилище для общих переменных, для управления состоянием приложения. На ней я тоже не буду подробно останавливаться, потому что, если вы поймете логику взаимодействия переменных внутри методов компонента и других компонентов, разобраться с Vuex, не должно составить труда. Кроме того, у них есть хорошая русскоязычная документация.

Для работы с Vuex, я прошу обратить особое внимание на то, как она правильно устанавливается, и что для доступа к данным, вам как минимум нужно использовать Мутации и Геттеры. Про них советую прочитать наиболее подробно. Я сначала пытался бегло понять суть и приступить к программированию, но столкнулся с множеством непонятных мне, на тот момент, проблем. Поэтому этим разделам уделите особое внимание.

Я обращу ваше внимание на саму систему взаимодействия. Она немного отличается от стандартного взаимодействия внутри Vue. Это как раз то, что я сначала упустил, а потом потратил много времени, чтобы разобраться. Возьму пример из официальной документации:

const store = new Vuex.Store({
  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    doneTodos: state => {
      return state.todos.filter(todo => todo.done)
    }
  }
})

Здесь, мы объявляем сам store и getters методы для него. Обратите внимание, что метод внутри getters задан не совсем стандартно, но еще более нестандартно его использование в своем компоненте. В нашем компоненте, если мы хотим использовать переменную из store, мы должны вызвать ее с помощью новых переменных, и метод будем вызывать не как метод, а как свойство объекта store

this.$store.getters.doneTodos; 

И никаких скобок, поскольку это метод, который вернет готовый объект, он и вызывается как просто свойство объекта getters внутри $store.

С мутациями немножкуо проще, там сразу написано, что нужно использовать comit('methodName', ПЕРЕДАВАЕМЫЕ_В_МЕТОД_ПЕРЕМЕННЫЕ).

Более подробно про мутации здесь.

Заключение


Мы познакомились с областью видимости переменных внутри компонентов, узнали способы обмена данными между компонентами, отсюда уже должно сложиться общее понимание о взаимодействии компонентов друг с другом в Vue.js. От себя скажу, что система достаточно гибкая, и уже существует множество готовых компонентов и библиотек, расширяющих возможность Vue. Каждый желающий может присоединиться к развитию этой системы и облегчать жизнь другим разработчикам. Компонентная система позволяет легче обслуживать код, соединять готовые компоненты внутри других, и не дублировать код, что приближает нас к способом “красивой” разработки. Новичкам желаю терпения и успеха, в познании новых для себя областей.

P.S.


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

Ссылки:


Русскоязычная документация по фреймворку Vue.js
Русскоязычная документация по библиотеке Vuex
Англоязычная документация по Vuetify
Русскоязычная документация по Vuetify
Tags:
Hubs:
+12
Comments 15
Comments Comments 15

Articles