Vue и Svelte — готовые компоненты
Готовые примеры Vue 3 и Svelte 5 с построчным разбором — как в галерее Turtle для рисования, только для кнопок, форм и списков в браузере.
Подойдёт, если вы:
- ищете в Google «vue counter example», «svelte todo list», «v-model input», «vue fetch api onmounted»;
- сдаёте лабораторную или курсовую по веб-интерфейсу;
- уже знаете HTML + CSS или DOM без фреймворка и хотите реактивность без ручного
textContentна каждой кнопке; - сравниваете Vue и Svelte перед выбором одного стека на pet-проект (рядом — React-рецепты).
Основы Vue и Svelte в браузере
Пошаговый tutorial Vue — первая программа на Vue.js. Обзор фреймворка — Vue.js. React для сравнения — первая программа на React и готовые React-компоненты. Мобильный UI на Dart — Flutter и готовые виджеты. Запросы к серверу — fetch / axios и Fullstack. Каркас страницы — HTML + CSS. После сборки — Nginx под SPA.
Школьникам — счётчик и список задач для урока информатики. Студентам — готовые блоки для лабораторной с разбором строк. Самоучкам — скопировали App.vue → npm run dev → разобрали таблицу под кодом. Ищете «как сделать счётчик на vue» или «svelte пример кнопки» — ниже код и объяснение, зачем каждая строка.
Частые запросы в Google — куда смотреть
| Ищут в интернете | Раздел ниже |
|---|---|
| vue 3 counter example ref | Счётчик и имя — Vue |
| svelte 5 counter button onclick | Счётчик и имя — Svelte |
| vue todo list v-for example | Список задач — Vue |
| svelte each block todo | Список задач — Svelte |
| vue fetch onmounted api | Загрузка с API — Vue |
| svelte onmount fetch json | Загрузка с API — Svelte |
| vue defineprops defineemits child | Дочерний компонент — Vue |
| svelte component props callback | Дочерний компонент — Svelte |
| npm create vue latest vite | Создание проекта |
| vue mustache not working raw {{ }} | Частые ошибки |
Базовые термины
| Термин | Простыми словами |
|---|---|
| SPA | Одна HTML-страница; при кликах контент меняет JavaScript, без полной перезагрузки |
| Компонент | Файл с разметкой + логикой + стилями (как отдельный «виджет») |
| Реактивность | Изменили переменную в коде — экран обновился сам |
ref (Vue) | Реактивная «коробка»; в script меняют через .value |
$state (Svelte 5) | Реактивная переменная; присвоение count = 5 обновляет UI |
v-model (Vue) | Связь поля ввода и переменной в обе стороны |
bind:value (Svelte) | То же, что v-model для input |
| Vite | Dev-сервер и сборка; при сохранении файла страница обновляется (HMR) |
mount('#app') | «Включить» Vue/Svelte в <div id="app"> на странице |
Зачем фреймворк, если есть DOM
На чистом DOM вы пишете так:
const btn = document.getElementById('plus');
const span = document.getElementById('count');
let n = 0;
btn.addEventListener('click', () => {
n += 1;
span.textContent = String(n);
});
Смысл: число n живёт в JavaScript, а textContent — ваша обязанность вручную синхронизировать экран. В списке из 20 полей таких строк становится десятки. Подробнее приёмы без фреймворка — 30 приёмов DOM.
Во Vue и Svelte вы описываете что показать, а фреймворк обновляет DOM при смене данных.
Как запустить пример за 2 минуты
- Установите Node.js LTS — в терминале
node -vиnpm -vпоказывают версии. - Выполните команды из Создание проекта.
- Откройте
src/App.vue(Vue) илиsrc/routes/+page.svelte(SvelteKit). - Удалите шаблонный код, вставьте пример целиком (включая
<style>, если он в блоке). npm run dev— откройте ссылку из терминала (частоhttp://localhost:5173).- Сохранили файл — страница обновилась (HMR).
| Где | Плюсы |
|---|---|
| Локально + Vite | Как на работе: HMR, сборка dist/ |
| StackBlitz | Без установки Node |
| Vue SFC Playground | Только .vue в браузере |
Создание проекта
Vue 3 + Vite
Задача: получить пустой проект с горячей перезагрузкой.
node -v
npm -v
npm create vue@latest my-vue-lab
cd my-vue-lab
npm install
npm run dev
Разбор команд:
| Команда | Смысл |
|---|---|
node -v | Проверка, что Node установлен |
npm create vue@latest my-vue-lab | Официальный генератор Vue 3 + Vite |
cd my-vue-lab | Все следующие команды — из папки проекта |
npm install | Скачать зависимости в node_modules/ |
npm run dev | Dev-сервер; URL в терминале |
| Вопрос мастера | На лабораторную |
|---|---|
| TypeScript | можно No |
| Vue Router | Yes, если нужны две «страницы» |
| Pinia | No на старте |
Svelte 5 + SvelteKit
npm create svelte@latest my-svelte-lab
cd my-svelte-lab
npm install
npm run dev
Разбор: генератор создаёт SvelteKit; главный UI обычно в src/routes/+page.svelte.
Production: npm run build → папка dist/ или .svelte-kit/output (зависит от шаблона). Статика на хостинг — Nginx SPA.
Обязательный каркас Vue
Задача: понять три блока .vue и точку входа main.js.
src/main.js
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
Разбор построчно:
| Строка | Смысл |
|---|---|
import { createApp } from 'vue' | Фабрика приложения Vue |
import App from './App.vue' | Корневой компонент — ваш экран |
createApp(App) | Связать приложение с компонентом |
.mount('#app') | Отрисовать внутри <div id="app"> из index.html |
Минимальный src/App.vue
<script setup>
import { ref } from 'vue'
const message = ref('Привет, Vue!')
</script>
<template>
<div class="app">
<h1>{{ message }}</h1>
</div>
</template>
<style scoped>
.app {
text-align: center;
padding: 2rem;
font-family: system-ui, sans-serif;
}
</style>
Разбор — script:
| Строка | Смысл |
|---|---|
<script setup> | Composition API: переменные видны в template |
ref('…') | Реактивная строка; в script — message.value |
import { ref } from 'vue' | Импорт из пакета vue |
Разбор — template:
| Строка | Смысл |
|---|---|
{{ message }} | Подстановка текста; без .value в шаблоне |
<style scoped> | CSS только для этого компонента |
Что увидите: заголовок «Привет, Vue!» по центру.
Попробуйте: в script после объявления: message.value = 'Лабораторная №3'.
Обязательный каркас Svelte
<script>
let message = $state('Привет, Svelte!')
</script>
<main>
<h1>{message}</h1>
</main>
<style>
main {
text-align: center;
padding: 2rem;
font-family: system-ui, sans-serif;
}
</style>
Разбор построчно:
| Строка | Смысл |
|---|---|
$state('…') | Реактивность Svelte 5 (runes) |
{message} | Интерполяция — одни фигурные скобки, не двойные как во Vue |
<style> | Стили локальны для файла по умолчанию |
Стартовые интерфейсы
Три задачи, которые чаще всего ищут: счётчик, список задач, загрузка JSON.
Счётчик и поле имени — Vue
Google: vue 3 counter ref example, vue v-model input greeting
Задача: кнопки ±1, сброс, приветствие по имени.
Вставьте в src/App.vue:
<script setup>
import { ref } from 'vue'
const count = ref(0)
const name = ref('')
const increment = () => { count.value++ }
const decrement = () => { count.value-- }
const reset = () => { count.value = 0 }
</script>
<template>
<div class="app">
<h1>Моя первая программа на Vue</h1>
<section class="greeting">
<input v-model="name" type="text" placeholder="Введите имя" />
<h2 v-if="name">Привет, {{ name }}!</h2>
</section>
<section class="counter">
<h2>Счётчик: {{ count }}</h2>
<button type="button" @click="decrement">−</button>
<button type="button" @click="reset">Сброс</button>
<button type="button" @click="increment">+</button>
</section>
</div>
</template>
<style scoped>
.app { text-align: center; padding: 2rem; }
.greeting, .counter { margin: 1.5rem 0; padding: 1rem; border-radius: 8px; }
.greeting { background: #f0f0f0; }
.counter { background: #e8f4f8; }
button {
margin: 0 4px;
padding: 0.5rem 1rem;
background: #42b883;
color: #fff;
border: none;
border-radius: 6px;
cursor: pointer;
}
button:hover { background: #3aa876; }
</style>
Разбор — script:
| Строка | Смысл |
|---|---|
ref(0) | Реактивное число, старт 0 |
count.value++ | В script у ref обязателен .value — главная ошибка новичков |
() => { … } | Функция передаётся в @click, не вызывается сразу |
Разбор — template:
| Синтаксис | Смысл |
|---|---|
v-model="name" | Двусторонняя связь с input |
v-if="name" | Показать <h2>, только если строка не пустая |
@click="increment" | Сокращение v-on:click |
type="button" | Кнопка не отправляет форму |
Что увидите: поле имени, приветствие при вводе, три кнопки счётчика.
Попробуйте: кнопка ×2 — const double = () => { count.value *= 2 } и @click="double".
Счётчик и поле имени — Svelte
<script>
let count = $state(0)
let name = $state('')
function increment() { count += 1 }
function decrement() { count -= 1 }
function reset() { count = 0 }
</script>
<main>
<h1>Моя первая программа на Svelte</h1>
<section class="greeting">
<input bind:value={name} type="text" placeholder="Введите имя" />
{#if name}
<h2>Привет, {name}!</h2>
{/if}
</section>
<section class="counter">
<h2>Счётчик: {count}</h2>
<button type="button" onclick={decrement}>−</button>
<button type="button" onclick={reset}>Сброс</button>
<button type="button" onclick={increment}>+</button>
</section>
</main>
<style>
main { text-align: center; padding: 2rem; }
.greeting, .counter { margin: 1.5rem 0; padding: 1rem; border-radius: 8px; }
.greeting { background: #f0f0f0; }
.counter { background: #fff3e0; }
button {
margin: 0 4px;
padding: 0.5rem 1rem;
background: #ff3e00;
color: #fff;
border: none;
border-radius: 6px;
cursor: pointer;
}
</style>
Сравнение с Vue:
| Идея | Vue | Svelte |
|---|---|---|
| Состояние | ref(0) + .value | $state(0) + count += 1 |
| Input | v-model="name" | bind:value={name} |
| Условие | v-if="name" | {#if name} … {/if} |
| Клик | @click="fn" | onclick={fn} |
Список задач — Vue
Google: vue todo list v-for v-model
<script setup>
import { ref } from 'vue'
const newTask = ref('')
const tasks = ref([
{ id: 1, text: 'Изучить ref и v-model', done: false },
])
let nextId = 2
const addTask = () => {
const text = newTask.value.trim()
if (!text) return
tasks.value.push({ id: nextId++, text, done: false })
newTask.value = ''
}
const removeTask = (id) => {
tasks.value = tasks.value.filter((t) => t.id !== id)
}
</script>
<template>
<section class="todo">
<h2>Список задач</h2>
<form @submit.prevent="addTask">
<input v-model="newTask" placeholder="Новая задача" />
<button type="submit">Добавить</button>
</form>
<ul>
<li v-for="task in tasks" :key="task.id">
<label>
<input type="checkbox" v-model="task.done" />
<span :class="{ done: task.done }">{{ task.text }}</span>
</label>
<button type="button" @click="removeTask(task.id)">×</button>
</li>
</ul>
</section>
</template>
<style scoped>
.done { text-decoration: line-through; color: #888; }
.todo ul { list-style: none; padding: 0; }
.todo li { display: flex; justify-content: space-between; align-items: center; margin: 0.5rem 0; }
</style>
Разбор построчно:
| Строка | Смысл |
|---|---|
tasks = ref([...]) | Массив объектов в реактивной обёртке |
trim() + if (!text) return | Пустые задачи не добавляем |
@submit.prevent | Enter в поле добавляет задачу без перезагрузки страницы |
v-for + :key="task.id" | Список; ключ нужен для корректного обновления DOM |
v-model="task.done" | Чекбокс меняет поле объекта в массиве |
:class="{ done: task.done }" | Зачёркивание через CSS-класс |
filter в removeTask | Новый массив без удалённой строки |
Список задач — Svelte
<script>
let newTask = $state('')
let tasks = $state([
{ id: 1, text: 'Изучить $state и {#each}', done: false },
])
let nextId = 2
function addTask() {
const text = newTask.trim()
if (!text) return
tasks = [...tasks, { id: nextId++, text, done: false }]
newTask = ''
}
function removeTask(id) {
tasks = tasks.filter((t) => t.id !== id)
}
</script>
<section class="todo">
<h2>Список задач</h2>
<form onsubmit={(e) => { e.preventDefault(); addTask() }}>
<input bind:value={newTask} placeholder="Новая задача" />
<button type="submit">Добавить</button>
</form>
<ul>
{#each tasks as task (task.id)}
<li>
<label>
<input type="checkbox" bind:checked={task.done} />
<span class:done={task.done}>{task.text}</span>
</label>
<button type="button" onclick={() => removeTask(task.id)}>×</button>
</li>
{/each}
</ul>
</section>
<style>
.done { text-decoration: line-through; color: #888; }
.todo ul { list-style: none; padding: 0; }
.todo li { display: flex; justify-content: space-between; margin: 0.5rem 0; }
</style>
Разбор:
| Строка | Смысл |
|---|---|
tasks = [...tasks, item] | Новая ссылка на массив — явное обновление |
{#each tasks as task (task.id)} | Цикл; (task.id) — ключ, как :key во Vue |
class:done={task.done} | Условный класс в Svelte |
Загрузка с API — Vue
Google: vue 3 fetch onmounted example
Задача: при открытии страницы запросить JSON и показать список или ошибку.
Для теста без своего сервера — публичный API. Для курсовой с Node — API «Заметки» и Fullstack 264.
<script setup>
import { ref, onMounted } from 'vue'
const notes = ref([])
const error = ref('')
const loading = ref(true)
onMounted(async () => {
try {
const res = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=5')
if (!res.ok) throw new Error(`HTTP ${res.status}`)
notes.value = await res.json()
} catch (e) {
error.value = e.message
} finally {
loading.value = false
}
})
</script>
<template>
<section>
<h2>Записи с сервера</h2>
<p v-if="loading">Загрузка…</p>
<p v-else-if="error">Ошибка: {{ error }}</p>
<ul v-else>
<li v-for="n in notes" :key="n.id">{{ n.title }}</li>
</ul>
</section>
</template>
Разбор построчно:
| Строка | Смысл |
|---|---|
onMounted | Код после появления компонента в DOM |
await fetch | GET по умолчанию |
!res.ok | 404/500 — fetch не бросает ошибку сам |
notes.value = await res.json() | Массив в реактивное состояние |
finally | Снять «Загрузка…» всегда |
v-if / v-else-if / v-else | Три экрана: ждём, ошибка, данные |
Шаблоны fetch — 1145.
Загрузка с API — Svelte
<script>
import { onMount } from 'svelte'
let notes = $state([])
let error = $state('')
let loading = $state(true)
onMount(async () => {
try {
const res = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=5')
if (!res.ok) throw new Error(`HTTP ${res.status}`)
notes = await res.json()
} catch (e) {
error = e.message
} finally {
loading = false
}
})
</script>
<section>
<h2>Записи с сервера</h2>
{#if loading}
<p>Загрузка…</p>
{:else if error}
<p>Ошибка: {error}</p>
{:else}
<ul>
{#each notes as n (n.id)}
<li>{n.title}</li>
{/each}
</ul>
{/if}
</section>
Разбор: onMount из svelte — аналог onMounted. {:else if} — цепочка условий.
Дочерний компонент — Vue
Google: vue defineprops defineemits example
Задача: вынести счётчик в файл; родитель хранит число, ребёнок шлёт события.
src/components/Counter.vue:
<script setup>
defineProps({
value: { type: Number, required: true },
})
const emit = defineEmits(['increment', 'decrement', 'reset'])
</script>
<template>
<section class="counter">
<h2>Счётчик: {{ value }}</h2>
<button type="button" @click="emit('decrement')">−</button>
<button type="button" @click="emit('reset')">Сброс</button>
<button type="button" @click="emit('increment')">+</button>
</section>
</template>
src/App.vue:
<script setup>
import { ref } from 'vue'
import Counter from './components/Counter.vue'
const count = ref(0)
</script>
<template>
<Counter
:value="count"
@increment="count++"
@decrement="count--"
@reset="count = 0"
/>
</template>
Разбор:
| Место | Смысл |
|---|---|
defineProps | Данные вниз от родителя |
defineEmits | События вверх |
:value="count" | Привязка prop (v-bind:value) |
@increment="count++" | Родитель — единственный источник истины |
Тот же паттерн в React — 1146.
Дочерний компонент — Svelte
src/lib/Counter.svelte:
<script>
let { value = 0, onincrement, ondecrement, onreset } = $props()
</script>
<section class="counter">
<h2>Счётчик: {value}</h2>
<button type="button" onclick={ondecrement}>−</button>
<button type="button" onclick={onreset}>Сброс</button>
<button type="button" onclick={onincrement}>+</button>
</section>
Родитель:
<script>
import Counter from './lib/Counter.svelte'
let count = $state(0)
</script>
<Counter
value={count}
onincrement={() => count++}
ondecrement={() => count--}
onreset={() => { count = 0 }}
/>
Разбор: в Svelte 5 колбэки onincrement вместо emit из Svelte 4.
Форма с проверкой — Vue
<script setup>
import { ref, computed } from 'vue'
const email = ref('')
const submitted = ref(false)
const emailError = computed(() => {
if (!submitted.value) return ''
if (!email.value.includes('@')) return 'Нужен символ @'
return ''
})
const onSubmit = () => {
submitted.value = true
if (!emailError.value) alert(`Отправлено: ${email.value}`)
}
</script>
<template>
<form @submit.prevent="onSubmit">
<label>
Email
<input v-model="email" type="email" />
</label>
<p v-if="emailError" class="err">{{ emailError }}</p>
<button type="submit">Отправить</button>
</form>
</template>
<style scoped>
.err { color: #c00; font-size: 0.9rem; }
</style>
Разбор:
| Строка | Смысл |
|---|---|
submitted | Ошибку показываем только после первой отправки |
computed | Пересчёт при смене email или submitted |
emailError.value в onSubmit | У computed в script тоже .value |
Vue и Svelte — что выбрать на курсовой
| Критерий | Vue 3 | Svelte 5 |
|---|---|---|
| Синтаксис | HTML + v-* | HTML + {#…} |
| После HTML/CSS | Обычно привычнее | Мягкий вход |
| Вакансии | Много | Меньше, растёт |
| Учебник | 282 | экосистема JS |
Один фреймворк на проект до рабочего pet-приложения — достаточно для зачёта.
Частые ошибки
| Симптом | Причина | Решение |
|---|---|---|
| Счётчик не меняется (Vue) | count++ без .value | count.value++ в script |
Сырой {{ count }} на странице | Нет mount('#app') | Проверить main.js, консоль F12 |
Failed to fetch | CORS или API выключен | 264, прокси Vite |
Предупреждение про key | Нет :key в v-for | task.id |
| Svelte: список «застыл» | Мутация без новой ссылки | tasks = [...tasks, x] |
404 на /about после build | SPA без fallback | Nginx SPA |
На старте достаточно Vue или Svelte (или React — отдельная статья). Три фреймворка в одной папке ломают сборку. Сравнение синтаксиса — здесь; курсовой проект — в одном выбранном стеке.
Практика — что добавить для зачёта
| Усложнение | Vue | Svelte |
|---|---|---|
| Фильтр задач | computed | $derived |
| Таймер | onMounted + onUnmounted | onMount + cleanup |
| POST на API | fetch + method: 'POST' | то же |
| Две страницы | Vue Router | SvelteKit routes |
Чек-лист перед сдачей лабораторной
-
npm run devбез ошибок, UI виден в браузере. - В Vue в script у
refпри изменении есть.value. - У
v-for/{#each}есть ключ. -
fetchпроверяетres.ok. -
npm run buildпроходит успешно.
Куда двигаться дальше
| Задача | Материал |
|---|---|
| Tutorial Vue | 282 |
| React-рецепты | 1146 |
| DOM без фреймворка | 1144 |
| fetch, axios | 1145 |
| Turtle / p5 | 111 · 1114 |
См. также
Другие статьи этого же раздела в боковом меню (как на странице "О разделе"). Практическая карта типовых IT-задач: термины, пошаговое внедрение, проверка качества и типичные ошибки. Простой консольный чат на C# — учебное приложение с сокетами: TCP между клиентом и сервером, многопоточность и обмен сообщениями в консоли. Примеры вёрстки на HTML и CSS с разбором: центрирование, Flexbox, Grid, формы, шапка, подвал и адаптив для учебы и портфолио. Перед началом работы обязательно изучите главу Turtle . Галерея 3D-фигур на Panda3D — карточки, куб, пирамида, сфера, сетки и составные сцены; код для локального запуска. Готовые docker-compose.yml с разбором каждой строки — nginx, PostgreSQL, Redis, WordPress, MongoDB. Примеры для школьников и студентов: postgres example, поднять базу локально, app + db. Примеры nginx.conf для статики, reverse proxy, React/Vue SPA, PHP, SSL и балансировки — построчный разбор директив, проверка curl и типичные ошибки для лабораторных и VPS. dockerfile example — 10 готовых Dockerfile с построчным разбором: node, python, golang, react nginx, spring boot, php, dotnet. Для студентов, лабораторных и docker build с нуля. PromQL example — готовые запросы Prometheus и Grafana с построчным разбором: up, rate, node_exporter cpu, memory, disk, http_requests_total, histogram_quantile p99, алерты. Для студентов, лабораторных и devops docker compose. Готовые манифесты Kubernetes с разбором каждой строки — Pod, Deployment, Service, ConfigMap, Secret, Ingress. Примеры для Minikube, kind и kubectl apply. Примеры графиков Matplotlib на Python для школьников и студентов — sin, cos, парабола, столбцы, scatter, гистограмма, подграфики; код с подробным разбором. Примеры pandas на Python для школьников и студентов — DataFrame, фильтрация, groupby, очистка, merge, сводные таблицы и экспорт; код с подробным разбором каждой строки.Готовые решения
Простой консольный чат на CSharp
HTML + CSS — готовые макеты
Примеры фигур Turtle на Python
Примеры фигур Panda3D на Python
Docker Compose — готовые стеки
Nginx — конфиги под задачу
Dockerfile — 10 типовых образов
Prometheus + Grafana — запросы
Kubernetes YAML — минимальные манифесты
Matplotlib — графики
Pandas — типовые операции