Перейти к содержимому

1. Что такое Vue 3

Представь, что ты хочешь сделать страницу интерактивной. Без фреймворка — это DOM-манипуляции, querySelector, addEventListener, ручное обновление HTML. Скучно и многословно. Vue говорит: «Опиши, как должен выглядеть интерфейс при каждом состоянии данных — я сам разберусь с обновлением DOM». Вот и вся магия! ✨


«Прогрессивный» означает — используй столько, сколько нужно:

<!-- Уровень 1: просто скрипт в HTML — без сборщика! -->
<div id="app">
<h1>{{ title }}</h1>
<button @click="count++">Кликов: {{ count }}</button>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
Vue.createApp({
data() {
return { title: 'Мой счётчик', count: 0 }
}
}).mount('#app')
</script>
Окно терминала
npm create vue@latest my-spa
Окно терминала
# Уровень 3: Full-stack SSR с Nuxt 3
npx nuxi init my-nuxt-app

Один фреймворк — три уровня применения. Растёшь вместе с проектом!


Vue 3 написан как монорепо из отдельных пакетов:

@vue/reactivity — система реактивности (ref, reactive, computed, watch)
@vue/runtime-core — ядро рантайма (Virtual DOM, компоненты, lifecycle)
@vue/runtime-dom — DOM-специфичный рантайм (директивы, события DOM)
@vue/compiler-core — парсер и компилятор шаблонов
@vue/compiler-dom — компилятор для DOM
@vue/compiler-sfc — компилятор SFC (.vue файлов)
@vue/server-renderer — SSR рендеринг

Вся реактивность — отдельный пакет! Можно использовать @vue/reactivity в Node.js без DOM.

Vue 3 использует JavaScript Proxy — это принципиально отличает его от Vue 2 с Object.defineProperty:

// Под капотом Vue 3 — упрощённо
function reactive(obj: object) {
return new Proxy(obj, {
get(target, key) {
// 📌 Регистрируем зависимость (track)
track(target, key)
return Reflect.get(target, key)
},
set(target, key, value) {
const result = Reflect.set(target, key, value)
// 🔔 Уведомляем подписчиков (trigger)
trigger(target, key)
return result
}
})
}

Преимущества перед Vue 2 / Object.defineProperty:

  • ✅ Перехватывает добавление новых свойств (Vue 2 не умел!)
  • ✅ Перехватывает удаление свойств
  • ✅ Работает с массивами без патчинга (push, splice)
  • ✅ Работает с Map, Set, WeakMap

Vue реализует паттерн MVVM (Model-View-ViewModel):

┌─────────────────────────────────────────────┐
│ Vue компонент │
│ │
│ ┌─────────┐ Data Binding ┌──────────┐ │
│ │ View │ ◄──────────────► │ViewModel │ │
│ │ (шаблон)│ │ (script)│ │
│ └─────────┘ └──────────┘ │
│ ▲ │ │
│ │ Observer ▼ │
│ └──────────────────── ┌──────────┐ │
│ │ Model │ │
│ │ (data) │ │
│ └──────────┘ │
└─────────────────────────────────────────────┘
// ViewModel — скрипт компонента
const count = ref(0) // ◄── Model (данные)
const doubled = computed(() => count.value * 2) // ◄── ViewModel (логика)
<!-- View — шаблон -->
<template>
<button @click="count++">{{ count }}</button> <!-- двусторонняя связь -->
<p>Удвоенное: {{ doubled }}</p>
</template>

Прямые манипуляции с DOM — медленные. DOM браузера — это сложный C++ объект. Каждое обращение к нему дорого стоит.

Virtual DOM — это лёгкое JS-представление DOM-дерева:

// Реальный DOM — тяжёлый C++ объект
document.createElement('div') // ≈ 500+ свойств!
// Virtual DOM в Vue 3 — просто объект
const vnode = {
type: 'div',
props: { class: 'card', onClick: handler },
children: [
{ type: 'h2', props: null, children: 'Заголовок' },
{ type: 'p', props: null, children: 'Текст' }
]
}

Алгоритм обновления (Diffing):

Старый VDOM Новый VDOM
<div> <div>
├─ <h2>A</h2> ├─ <h2>A</h2> ← не изменился, пропускаем
├─ <p>Hello</p> ├─ <p>World</p> ← изменился! обновляем только текст
└─ <span>1</span> └─ <span>2</span> ← изменился! обновляем только текст

Vue 3 ещё умнее — компилятор анализирует шаблон и помечает статические части, которые никогда не изменятся:

<template>
<div>
<h1>Статичный заголовок</h1> <!-- ← Vue 3 помечает как статику, пропускает при обновлении -->
<p>{{ dynamicText }}</p> <!-- ← только это обновляется -->
</div>
</template>

// Vue 2 — Options API
export default {
data() {
return { count: 0, user: null }
},
computed: {
doubled() { return this.count * 2 }
},
methods: {
increment() { this.count++ },
async fetchUser() {
this.user = await api.getUser()
}
},
mounted() {
this.fetchUser()
}
}
// Vue 3 — Composition API (гораздо гибче!)
import { ref, computed, onMounted } from 'vue'
const count = ref(0)
const doubled = computed(() => count.value * 2)
const increment = () => count.value++
const user = ref(null)
const fetchUser = async () => {
user.value = await api.getUser()
}
onMounted(fetchUser)
<!-- Vue 2 — ОШИБКА! нужен один корень -->
<template>
<h1>Заголовок</h1>
<p>Параграф</p>
</template>
<!-- Vue 3 — OK! Fragments! 🎉 -->
<template>
<h1>Заголовок</h1>
<p>Параграф</p>
</template>
<!-- Vue 3 — рендерим модальное окно в body, не в компоненте -->
<template>
<button @click="showModal = true">Открыть</button>
<Teleport to="body">
<div v-if="showModal" class="modal">
<p>Я рендерюсь прямо в body! 🎯</p>
</div>
</Teleport>
</template>
<!-- Vue 3 -->
<template>
<Suspense>
<template #default>
<AsyncUserProfile /> <!-- загружается асинхронно -->
</template>
<template #fallback>
<LoadingSpinner /> <!-- показывается пока грузится -->
</template>
</Suspense>
</template>
// Vue 3 написан на TypeScript, поэтому типы идеальны
import { ref, Ref } from 'vue'
interface User {
id: number
name: string
email: string
}
const user: Ref<User | null> = ref(null)
// TypeScript знает всё о user.value!
МетрикаVue 2Vue 3Улучшение
Размер бандла22.9KB13.5KB (с tree-shaking)−41%
Скорость рендерабазовая+55% быстрее
Использование памятибазовое−54% меньше
Скорость обновлениябазовая+133% быстрее

// main.ts — входной файл приложения
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { createPinia } from 'pinia'
// Создаём приложение
const app = createApp(App)
// Подключаем плагины
app.use(router)
app.use(createPinia())
// Регистрируем глобальные компоненты
app.component('BaseButton', BaseButton)
// Регистрируем глобальные директивы
app.directive('focus', { mounted: el => el.focus() })
// Глобальные свойства (аналог Vue.prototype в Vue 2)
app.config.globalProperties.$http = axios
// Монтируем в DOM
app.mount('#app')

Важно: в Vue 3 нет глобального Vue объекта — только инстансы приложения. Можно создать несколько независимых приложений на одной странице!


Замени Vetur на Volar — официальный Language Server для Vue 3:

.vscode/extensions.json
{
"recommendations": [
"Vue.volar", // подсветка, автодополнение, типы
"Vue.vscode-typescript-vue-plugin" // TypeScript поддержка
]
}

Расширение для Chrome/Firefox — просматривай дерево компонентов, состояние, события:

🛠️ Vue DevTools показывает:
├── 🧩 Components — дерево компонентов и их props/data
├── 🍍 Pinia — состояние всех сторов
├── 🗺️ Router — текущий маршрут, история
├── ⏱️ Timeline — события в хронологии
└── ⚡ Performance — скорость рендера компонентов

<!-- HelloVue.vue — Single File Component -->
<template>
<div class="hello">
<h1>{{ greeting }}, {{ name }}! 👋</h1>
<p>Ты нажал кнопку {{ count }} раз(а)</p>
<button @click="increment">Нажми меня!</button>
<input v-model="name" placeholder="Введи имя..." />
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
// Реактивные данные
const name = ref('Яша')
const count = ref(0)
// Вычисляемое свойство
const greeting = computed(() => {
return count.value > 5 ? 'Привет-привет' : 'Привет'
})
// Функция
const increment = () => {
count.value++
}
</script>
<style scoped>
.hello {
padding: 20px;
text-align: center;
}
button {
background: #42b883;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
}
</style>

Три секции Single File Component:

  • <template> — HTML с Vue-директивами
  • <script setup> — логика на TypeScript
  • <style scoped> — CSS изолированный в компоненте

✅ ВЫБИРАЙ Vue 3 если:
├── Команда знает HTML/CSS/JS — Vue очень интуитивен
├── Нужен быстрый старт — документация лучшая в классе
├── SPA, дашборды, интерактивные сайты
├── Хочешь гибкость: CDN → Vite → Nuxt
└── Важна читаемость шаблонов
❌ РАССМОТРИ АЛЬТЕРНАТИВЫ если:
├── Огромная enterprise команда → Angular
├── Нужен максимальный найм → React
├── Нативное мобильное приложение → React Native / Flutter
└── Статичный сайт без интерактивности → HTML/CSS

Vue 3 — это:

  • Прогрессивный фреймворк: от CDN-скрипта до full-stack SSR
  • Реактивность через Proxy: умнее и быстрее Vue 2
  • Composition API: код по фичам, не по типам опций
  • Отличный TypeScript: написан на TS, типы из коробки
  • Маленький бандл: tree-shaking, только то что используешь
  • Огромная экосистема: Vite, Pinia, Vue Router, VueUse, Nuxt 3

Следующий шаг — установка и создание первого проекта с Vite! ⚡