Приветствую! Поговорим о Vue.js? Эта статья будет наиболее подходящей для людей уже знакомых с React. Также в этой статье я не буду пытаться быть объективным, а всего-навсего поделюсь своими впечатлениями и мыслями от достаточно молодого и прогрессивного фреймворка Vue после достаточного длительного использования React в качестве основного инструмента. Еще мы с вами посмотрим как может выглядеть совершенно простое Todos приложение на Vue, познакомившись с некоторыми его основами.

Для начала давайте посмотрим на динамику развития фреймворка, взятого из соответствующего исследования о популярности front-end инструментов:



Вышеприведенный график построен с использованием возможностей проекта NPM Trends. Здесь показано изменение количества загрузок соответствующих пакетов с течением времени. В частности, на нашем графике представлены данные за 6 месяцев 2020 года. Тут хорошо видно то, что React, по исследуемому показателю, значительно обходит конкурентов. А количество загрузок Vue, с другой стороны, постепенно растёт и сейчас находится в районе полутора миллионов.

Это неспроста, ведь Vue в качестве основных преимуществ располагает высокой скоростью, низким порогом вхождения и, что меня больше всего привлекает, лаконичной и приятной структурой. React — это мощный и замечательный инструмент, однако вы вряд ли сможете найти хотя бы 2 одинаково структурированных проекта на этом фреймворке. Да, разработчик способен довольно гибко определять архитектуру и подходы к написанию приложений, но всегда ли это хорошо? Наш сегодняшний герой позволит вам не допускать путаниц и каких-то проблем с тем, когда вы, например, садитесь на новый проект. Давайте посмотрим на Vue в деле. Я буду представлять уже готовый код приложения с пояснениями. Как установить фреймворк и создать приложение вы можете узнать из официальной документации.

<template>
  <div id="app">
    <h1>To do list</h1>
    <AddTodo v-on="add"/>
    <hr />
    <select v-model="filter">
      <option value="all">All</option>
      <option value="done">Done</option>
      <option value="todo">Todo</option>
    </select>
    <p v-if="!filterTodos.length">No todo!</p>
    <TodoList 
      v-else-if="filterTodos.length"
      v-bind:todos="filterTodos" 
      @remove="remove"
    />
  </div>
</template>

<script>
import TodoList from '@/components/TodoList'
import AddTodo from '@/components/AddTodo'
export default {
  data() {
    return {
      todos: [],
      filter: 'all'
    }
  },
  mounted() {
    fetch("https://jsonplaceholder.typicode.com/todos?_limit=5")
      .then(response => response.json())
      .then(json => this.todos = json)
  },
  components: {
    TodoList,
    AddTodo,
  },
  methods: {
    remove(id) {
      this.todos = this.todos.filter(item => item.id !== id)
    },
    add(newTodo) {
      this.todos.push(newTodo)
    }
  },
  computed: {
    filterTodos() {
      if (this.filter === 'all') {
        return this.todos
      }
      if (this.filter === 'done') {
        return this.todos.filter(item => item.completed)
      }
      if (this.filter === 'todo') {
        return this.todos.filter(item => !item.completed)
      }
      return []
    }
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
select {
  padding: 5px;
  margin: 5px 5px 20px 5px;
}
</style>

Перед вами самый “верхний” компонент приложения App.vue, на его примере мы и рассмотрим основные особенности работы.

Сразу замечаем эту самую структуру, о которой так много поговорили в самом начале. В каждой компоненте есть 3 секции, секция с html шаблоном, секция с логикой компоненты в теге script и в самом низу секция со стилями для нашей компоненты. К слову, обязательной является только первая, т.е. компонент может представлять собой просто html шаблон. Также важно отметить то, что в теге template должен быть 1 дочерний элемент.

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

Как и в React, сначала мы импортируем все необходимые нам компоненты и регистрируем их в поле components. Ничего особенного.

Заметили метод data() который возвращает нам todos и filter. И да, как вы могли догадаться это стейт нашей компоненты, вновь ничего особенного и сложного, но будет интересно как мы с ним будем взаимодействовать.

<template>
  <li>
    <span v-bind:class="{ done: todo.completed }">
      <input 
        v-bind:checked="todo.completed"
        type="checkbox"
        v-on:change="todo.completed = !todo.completed"
      />
      <strong>{{ index + 1 }}</strong>
      {{ todo.title | upper }}
    </span>
    <button class='rm' v-on:click="$emit('remove', todo.id)">×</button>
  </li>
</template>

<script>
export default {
  props: {
    todo: {
      type: Object,
      required: true
    },
    index: Number
  },
  filters: {
    upper(value) {
      return value.toUpperCase()
    }
  },
}
</script>

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

<template>
  <div>
    <ul>
      <TodoItem 
        v-for="(todo, index) of todos" 
        v-bind:key="todo.id" 
        v-bind:index="index"
        v-bind:todo="todo"
        v-on:remove="remove"
      />
    </ul>
  </div>
</template>

<script>
import TodoItem from '@/components/TodoItem'
export default {
  props: ['todos'],
  components: {
    TodoItem
  },
  methods: {
    remove(id) {
      this.$emit('remove', id)
    }
  }
}
</script>

Вы можете делать как вам понравится.

Вернемся к App.

Далее метод mounted() — это равносильно уже знакомому нам из React componentDidMount, т.е. в данном случае при рендере компоненты у нас выполняется запрос на https://jsonplaceholder, а результат запроса мы записываем в стейт с помощью обычного оператора присваивания:

this.todos = json

Да, именно там мы меняем стейт в Vue, удобно правда?

Поле methods — то место, где мы объявляем все наши методы, которые мы хотим использовать в дальнейшем.

Более интересная фишка фреймворка — computed. Это вычисляемые свойства компоненты, в которой мы можем обработать переменные нашего стейта и использовать эти данные как сами переменные. В данном случае мы обрабатываем массив наших todos по с помощью filter переменной, из select (см template секцию), чтобы показывать либо те задачи, которые мы выполнили, либо те, что только предстоит выполнить, либо все сразу.
Кстати о переменной filter, как она меняется в зависимости от выбранного option? В React мы бы сделали стейт и контролируемый элемент, но это вам не React. v-model атрибут в select-те берет это все на себя и делает под капотом. Все, теперь изменяя опцию в селекте, мы меняем наш стейт, круто, правда?

Посмотрим на еще несколько основных атрибутов, которые нам предлагает использовать Vue.

v-on — позволяет нам отловить события элемента и обработать их, в данном случае это наше событие на добавление у компонента AddTodo, но мы можем также ловить и классические события, например клик по кнопке. Также для сокращения мы можем использовать знак собаки, как например @remove.

v-if и v-else-if — механизм того, как мы можем показывать компонент в зависимости от указанного условия.

v-bind — один из самых важных атрибутов, он позволяет “зарегистрировать” какое-либо свойство для компонента, например, объявить класс или передать пропсы. Выше вы можете увидеть много случаев использования этого атрибута.

Вы также могли заметить интересный момент:

v-for="(todo, index) of todos" — это всего-навсего знакомый нам .map для массива todos, но на Vue лад.

Я постарался максимально кратко показать основные принципы работы Vue, настоятельно рекомендую скачать и посмотреть на полный код приложения.

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

Всегда полезно отвлечься от уже приевшегося инструмента и пощупать что-то новое, я надеюсь эта статья помогла вам в этом.

Не бойтесь пробовать что-то новое, развивайтесь и помните, что лучший инструмент — это не тот, что дает хорошую структуру приложению, быстрее или занимает топ по скачиваниям, а тот, что позволяет именно вам получать максимальное удовольствие от работы, благо сейчас зная хотя бы 1 из популярных фреймворком для front-end разработки — вы уже не пропадете.

Успехов!