Веб-приложения на языке JavaScript: практические примеры и решения
Способы построения приложений на JavaScript
Создание интерактивных страниц и полноценных веб-приложений - одна из главных задач JavaScript. Рассмотрим несколько подходов, отличающихся по сложности и производительности, начиная с чистого языка и заканчивая использованием готовых библиотек.
Как реализовать одностраничное приложение без фреймворков?
Самый прозрачный способ - использовать чистый JavaScript с управлением маршрутами через hashchange и динамическим рендерингом. Это даёт полный контроль над кодом и лучше понимание внутренних механизмов.
Алгоритм:
- Определить структуру SPA (Single Page Application) с главным контейнером
#app. - Реализовать функцию-роутер, которая анализирует
window.location.hashи вызывает соответствующий рендер. - Создать функции рендеринга для каждой страницы (например,
renderHome(),renderAbout()). - Подписаться на событие
hashchangeи запускать роутер при загрузке.
// index.html
<nav>
<a href="#/home">Главная</a>
<a href="#/about">О нас</a>
</nav>
<div id="app"></div>
<script src="app.js"></script>Find js (поиск в javascript)
// app.js
const app = document.getElementById('app');
function router() {
const hash = window.location.hash.slice(1) || '/home';
const routes = {
'/home': renderHome,
'/about': renderAbout
};
const render = routes[hash] || renderNotFound;
app.innerHTML = render();
}
function renderHome() {
return '<h2>Главная страница</h2><p>Добро пожаловать!</p>';
}
function renderAbout() {
return '<h2>О нас</h2><p>Создано на чистом JS.</p>';
}
function renderNotFound() {
return '<h2>404</h2><p>Страница не найдена</p>';
}
window.addEventListener('hashchange', router);
window.addEventListener('load', router);Js примеры (примеры кода на javascript)
Результат: при клике по ссылкам меняется содержимое #app без перезагрузки страницы.
Javascript строки (строки в javascript)
Типичные ошибки:
- Забыть подписаться на
load, и начальная страница не отображается. - Неправильное значение hash - нужно использовать
window.location.hashбез ошибок. - Инъекция HTML через
innerHTML- для пользовательского ввода требуется санитизация.
Цель: подходит для небольших проектов, портфолио, учебных примеров.
Как упростить работу с DOM и событиями в приложении?
Библиотека jQuery предлагает лаконичный синтаксис для манипуляций, анимаций и AJAX. Она удобна, когда проект уже использует устаревший код или нужна быстрая совместимость с IE.
// подключение jQuery (через CDN)
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<div id="content"></div>
<script>
// Навигация с помощью jQuery
$(document).ready(function() {
function loadPage(hash) {
const pages = {
'home': '<h2>Домой</h2>',
'about': '<h2>О проекте</h2>'
};
$('#content').html(pages[hash] || '<h2>404</h2>');
}
$(window).on('hashchange', function() {
var hash = location.hash.slice(1) || 'home';
loadPage(hash);
}).trigger('hashchange');
});
</script>Js фильтр (фильтрация в javascript)
Результат: тот же принцип SPA, но короче за счёт цепочек jQuery.
Meta js (мета-теги в javascript)
Проблемы:
- Устаревший подход, современные проекты редко используют jQuery.
- Избыточная загрузка библиотеки для небольших задач.
- Не решает проблему управления состоянием и сложной логики.
Как быстро создать реактивное приложение с компонентами?
React - современная библиотека для построения UI. Использование JSX, компонентов и виртуального DOM упрощает разработку масштабируемых приложений. Пример - та же маршрутизация с помощью react-router-dom.
// App.jsx
import React from 'react';
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
function Home() { return <h2>Главная</h2>; }
function About() { return <h2>О нас</h2>; }
function App() {
return (
<BrowserRouter>
<nav>
<Link to="/">Домой</Link>
<Link to="/about">О проекте</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</BrowserRouter>
);
}
export default App;Href javascript (ссылки javascript)
Результат: полноценная SPA с навигацией, поддерживающая вложенные маршруты и lazy loading.
Возможные сложности:
- Необходимость сборщика (Webpack, Vite).
- Кривая обучения для начинающих.
- Избыток абстракций для простых сайтов.
Расширенные примеры создания приложений на JavaScript
Чистое SPA с загрузкой данных и сохранением состояния
В этом примере используется localStorage для хранения избранных элементов и fetch для получения списка постов с JSONPlaceholder. Реализована обработка ошибок при загрузке.
// advanced-app.html
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>Расширенное SPA</title></head>
<body>
<nav>
<a href="#/posts">Посты</a>
<a href="#/favorites">Избранное</a>
</nav>
<div id="app"></div>
<div id="status"></div>
<script type="module">
const app = document.getElementById('app');
const status = document.getElementById('status');
// Состояние приложения
let favorites = JSON.parse(localStorage.getItem('favorites')) || [];
function saveFavorites() {
localStorage.setItem('favorites', JSON.stringify(favorites));
}
function renderStatus(msg, isError = false) {
status.innerHTML = isError ? `<p style="color:red">${msg}</p>` : `<p>${msg}</p>`;
}
async function renderPosts() {
app.innerHTML = '<p>Загрузка...</p>';
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
if (!response.ok) throw new Error('Ошибка HTTP: ' + response.status);
const posts = await response.json();
let html = '<h2>Посты</h2><ul>';
posts.slice(0, 10).forEach(post => {
const isFav = favorites.includes(post.id);
html += `<li>${post.title} <button data-id="${post.id}" class="fav-btn">${isFav ? 'Убрать' : 'В избранное'}</button></li>`;
});
html += '</ul>';
app.innerHTML = html;
// Обработка кликов по кнопкам избранного
app.querySelectorAll('.fav-btn').forEach(btn => {
btn.addEventListener('click', (e) => {
const id = Number(e.target.dataset.id);
const idx = favorites.indexOf(id);
if (idx === -1) {
favorites.push(id);
renderStatus('Добавлено в избранное');
} else {
favorites.splice(idx, 1);
renderStatus('Удалено из избранного');
}
saveFavorites();
renderPosts(); // обновление списка
});
});
} catch (error) {
renderStatus(error.message, true);
app.innerHTML = '<p>Не удалось загрузить посты.</p>';
}
}
function renderFavorites() {
if (favorites.length === 0) {
app.innerHTML = '<h2>Избранное</h2><p>Пока ничего нет.</p>';
return;
}
// Загружаем посты, соответствующие избранным ID
fetch('https://jsonplaceholder.typicode.com/posts')
.then(res => res.json())
.then(posts => {
const favPosts = posts.filter(p => favorites.includes(p.id));
let html = '<h2>Избранные посты</h2><ul>';
favPosts.forEach(p => {
html += `<li>${p.title}</li>`;
});
html += '</ul>';
app.innerHTML = html;
})
.catch(err => renderStatus(err.message, true));
}
function router() {
const hash = location.hash.slice(1) || '/posts';
if (hash === '/posts') renderPosts();
else if (hash === '/favorites') renderFavorites();
else app.innerHTML = '<h2>404</h2>';
}
window.addEventListener('hashchange', router);
window.addEventListener('load', router);
</script>
</body>
</html>Результат: посты загружаются с сервера, можно добавлять/удалять избранное, данные сохраняются в localStorage.
Создание приложения с помощью классов ES6
Организация кода в виде классов улучшает читаемость и модульность. Пример простого слайдера изображений.
class ImageSlider {
constructor(container, images) {
this.container = container;
this.images = images;
this.current = 0;
this.render();
}
render() {
this.container.innerHTML = `
<img id="slider-img" src="${this.images[this.current]}" style="width:400px" />
<div>
<button id="prev">Назад</button>
<button id="next">Вперёд</button>
</div>
`;
this.bindEvents();
}
bindEvents() {
document.getElementById('prev').addEventListener('click', () => this.prev());
document.getElementById('next').addEventListener('click', () => this.next());
}
prev() {
this.current = (this.current - 1 + this.images.length) % this.images.length;
this.updateImage();
}
next() {
this.current = (this.current + 1) % this.images.length;
this.updateImage();
}
updateImage() {
document.getElementById('slider-img').src = this.images[this.current];
}
}
// Использование
const images = [
'https://picsum.photos/id/10/400/300',
'https://picsum.photos/id/20/400/300',
'https://picsum.photos/id/30/400/300'
];
const container = document.getElementById('slider-container');
const slider = new ImageSlider(container, images);Результат: слайдер с кнопками, работающими по кругу. Код инкапсулирован в класс.