браузер не видит компоненты, класс!

This commit is contained in:
2025-09-25 01:11:17 +04:00
parent f7afa74bed
commit 632835f834
10 changed files with 426 additions and 2 deletions

View File

@@ -58,8 +58,9 @@
}
</style>
<!-- В main контейнере basket.html замените содержимое на: -->
<main class="container my-4">
<div class="text-center py-5">
<div class="empty-basket text-center py-5">
<h1 class="mb-4">Здесь будут лежать твои товары</h1>
<p class="lead mb-4">А пока здесь так пусто...</p>
<img src="img/sad1.jpg" alt="Пустая корзина" class="img-fluid rounded" style="max-height: 300px;">
@@ -69,6 +70,8 @@
</a>
</div>
</div>
<div id="basketContainer"></div>
</main>
<footer class="py-4 mt-5" style="background-color: #00264d; color: white;">
@@ -98,5 +101,18 @@
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="./components/basket/model.js"></script>
<script src="./components/basket/view.js"></script>
<script src="./components/basket/controller.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Проверяем, есть ли необходимые элементы на странице
if (document.getElementById('basketContainer') || document.getElementById('productsContainer')) {
const model = new Model();
const view = new View();
new Controller(model, view);
}
});
</script>
</body>
</html>

View File

@@ -353,5 +353,19 @@
this.reset();
});
</script>
<script src="./components/basket/model.js"></script>
<script src="./components/basket/view.js"></script>
<script src="./components/basket/controller.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Проверяем, есть ли необходимые элементы на странице
if (document.getElementById('basketContainer') || document.getElementById('productsContainer')) {
const model = new Model();
const view = new View();
new Controller(model, view);
}
});
</script>
</body>
</html>

View File

@@ -0,0 +1,133 @@
// controller.js
export class Controller {
constructor(model, view) {
this.model = model;
this.view = view;
this.init();
}
async init() {
// Для страницы корзины
if (window.location.pathname.includes('basket.html')) {
await this.loadBasket();
this.setupBasketEventListeners();
}
// Для страницы каталога
if (window.location.pathname.includes('catalog.html')) {
this.setupCatalogEventListeners();
}
}
// Загрузить и отобразить корзину
async loadBasket() {
const basketItems = await this.model.getBasketItems();
this.view.showBasket(basketItems);
}
// Настройка обработчиков событий для корзины
setupBasketEventListeners() {
document.addEventListener('click', async (e) => {
const basketItem = e.target.closest('.basket-item');
if (!basketItem) return;
const productId = basketItem.dataset.id;
// Удаление товара
if (e.target.closest('.remove-btn')) {
await this.model.removeFromBasket(productId);
this.view.showNotification('Товар удален из корзины');
await this.loadBasket();
}
// Увеличение количества
if (e.target.closest('.increase-btn')) {
const quantityInput = basketItem.querySelector('.quantity-input');
const newQuantity = parseInt(quantityInput.value) + 1;
quantityInput.value = newQuantity;
await this.model.updateBasketItem(productId, newQuantity);
await this.loadBasket();
}
// Уменьшение количества
if (e.target.closest('.decrease-btn')) {
const quantityInput = basketItem.querySelector('.quantity-input');
let newQuantity = parseInt(quantityInput.value) - 1;
if (newQuantity < 1) newQuantity = 1;
quantityInput.value = newQuantity;
await this.model.updateBasketItem(productId, newQuantity);
await this.loadBasket();
}
});
// Обработка изменения количества через input
document.addEventListener('change', async (e) => {
if (e.target.classList.contains('quantity-input')) {
const basketItem = e.target.closest('.basket-item');
const productId = basketItem.dataset.id;
const newQuantity = parseInt(e.target.value) || 1;
if (newQuantity < 1) {
e.target.value = 1;
return;
}
await this.model.updateBasketItem(productId, newQuantity);
await this.loadBasket();
}
});
// Оформление заказа
document.addEventListener('click', async (e) => {
if (e.target.id === 'checkoutBtn') {
const basketItems = await this.model.getBasketItems();
if (basketItems.length === 0) {
this.view.showNotification('Корзина пуста', 'error');
return;
}
this.view.showNotification('Заказ оформлен! Спасибо за покупку!');
await this.model.clearBasket();
await this.loadBasket();
}
});
}
// Настройка обработчиков событий для каталога
setupCatalogEventListeners() {
document.addEventListener('click', async (e) => {
if (e.target.closest('.btn') && e.target.closest('.btn').textContent.includes('В корзину')) {
const card = e.target.closest('.card');
const product = this.extractProductData(card);
if (product) {
await this.model.addToBasket(product);
this.view.showNotification('Товар добавлен в корзину!');
}
}
});
}
extractProductData(card) {
try {
const name = card.querySelector('.card-title').textContent;
const priceText = card.querySelector('.text-muted').textContent.replace('$', '');
const description = card.querySelector('.card-text').textContent;
const image = card.querySelector('img').src;
// Генерируем ID на основе содержимого карточки
const id = btoa(`${name}-${priceText}`).substring(0, 8);
return {
id: id,
name: name.trim(),
price: parseFloat(priceText),
description: description.trim(),
image: image
};
} catch (error) {
console.error('Ошибка при извлечении данных товара:', error);
return null;
}
}
}

118
components/basket/model.js Normal file
View File

@@ -0,0 +1,118 @@
// model.js
export class Model {
constructor() {
this.apiUrl = 'http://localhost:3000';
}
async request(url, options = {}) {
try {
const response = await fetch(`${this.apiUrl}${url}`, {
...options,
headers: {
'Content-Type': 'application/json',
...options.headers
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('Request failed:', error);
throw error;
}
}
async getBasketItems() {
try {
return await this.request('/basket');
} catch (error) {
console.error('Ошибка при получении корзины:', error);
return [];
}
}
// Добавить товар в корзину
async addToBasket(product) {
try {
// Проверяем, есть ли товар уже в корзине
const basketItems = await this.getBasketItems();
const existingItem = basketItems.find(item => item.id === product.id);
if (existingItem) {
// Если товар уже есть, увеличиваем количество
await this.updateBasketItem(product.id, existingItem.quantity + 1);
} else {
// Если товара нет, добавляем новый
const basketItem = {
...product,
quantity: 1,
addedAt: new Date().toISOString()
};
const response = await fetch(`${this.apiUrl}/basket`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(basketItem)
});
return await response.json();
}
} catch (error) {
console.error('Ошибка при добавлении в корзину:', error);
}
}
// Обновить количество товара в корзине
async updateBasketItem(productId, quantity) {
try {
const response = await fetch(`${this.apiUrl}/basket/${productId}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ quantity })
});
return await response.json();
} catch (error) {
console.error('Ошибка при обновлении корзины:', error);
}
}
// Удалить товар из корзины
async removeFromBasket(productId) {
try {
await fetch(`${this.apiUrl}/basket/${productId}`, {
method: 'DELETE'
});
} catch (error) {
console.error('Ошибка при удалении из корзины:', error);
}
}
// Очистить корзину
async clearBasket() {
try {
const basketItems = await this.getBasketItems();
for (const item of basketItems) {
await this.removeFromBasket(item.id);
}
} catch (error) {
console.error('Ошибка при очистке корзины:', error);
}
}
// Получить все товары из каталога
async getProducts() {
try {
const response = await fetch(`${this.apiUrl}/shmots`);
return await response.json();
} catch (error) {
console.error('Ошибка при получении товаров:', error);
return [];
}
}
}

113
components/basket/view.js Normal file
View File

@@ -0,0 +1,113 @@
// view.js
export class View {
constructor() {
this.basketContainer = document.getElementById('basketContainer');
this.emptyBasketElement = document.querySelector('.empty-basket');
}
// Показать корзину с товарами
showBasket(items) {
if (items.length === 0) {
this.showEmptyBasket();
return;
}
this.hideEmptyBasket();
const basketHTML = items.map(item => this.createBasketItemHTML(item)).join('');
this.basketContainer.innerHTML = `
<div class="row">
<div class="col-12">
<div class="card border-0 shadow">
<div class="card-header" style="background-color: #00264d; color: white;">
<h5 class="mb-0"><i class="bi bi-cart me-2"></i>Корзина</h5>
</div>
<div class="card-body">
${basketHTML}
<div class="d-flex justify-content-between align-items-center mt-4 pt-3 border-top">
<h5>Итого: $${this.calculateTotal(items).toFixed(2)}</h5>
<button class="btn btn-lg" style="background-color: #00264d; color: white;" id="checkoutBtn">
<i class="bi bi-credit-card me-2"></i>Оформить заказ
</button>
</div>
</div>
</div>
</div>
</div>
`;
}
// Создать HTML для элемента корзины
createBasketItemHTML(item) {
return `
<div class="row align-items-center mb-3 basket-item" data-id="${item.id}">
<div class="col-md-2">
<img src="${item.image}" alt="${item.name}" class="img-fluid rounded" style="max-height: 80px;">
</div>
<div class="col-md-4">
<h6 class="mb-1">${item.name}</h6>
<p class="text-muted small mb-0">${item.description}</p>
</div>
<div class="col-md-2">
<span class="fw-bold">$${item.price}</span>
</div>
<div class="col-md-2">
<div class="input-group input-group-sm">
<button class="btn btn-outline-secondary decrease-btn" type="button">-</button>
<input type="number" class="form-control text-center quantity-input" value="${item.quantity}" min="1">
<button class="btn btn-outline-secondary increase-btn" type="button">+</button>
</div>
</div>
<div class="col-md-2">
<span class="fw-bold me-3">$${(item.price * item.quantity).toFixed(2)}</span>
<button class="btn btn-sm btn-outline-danger remove-btn">
<i class="bi bi-trash"></i>
</button>
</div>
</div>
`;
}
// Показать пустую корзину
showEmptyBasket() {
if (this.emptyBasketElement) {
this.emptyBasketElement.style.display = 'block';
}
if (this.basketContainer) {
this.basketContainer.innerHTML = '';
}
}
// Скрыть сообщение о пустой корзине
hideEmptyBasket() {
if (this.emptyBasketElement) {
this.emptyBasketElement.style.display = 'none';
}
}
// Рассчитать общую сумму
calculateTotal(items) {
return items.reduce((total, item) => total + (item.price * item.quantity), 0);
}
// Показать уведомление
showNotification(message, type = 'success') {
// Создаем элемент уведомления
const notification = document.createElement('div');
notification.className = `alert alert-${type === 'success' ? 'success' : 'danger'} alert-dismissible fade show`;
notification.style.cssText = 'position: fixed; top: 20px; right: 20px; z-index: 1050; min-width: 300px;';
notification.innerHTML = `
${message}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
`;
document.body.appendChild(notification);
// Автоматически удаляем через 3 секунды
setTimeout(() => {
if (notification.parentNode) {
notification.remove();
}
}, 3000);
}
}

View File

View File

0
components/likes/view.js Normal file
View File

18
dist/basket.html vendored
View File

@@ -58,8 +58,9 @@
}
}
</style>
<!-- В main контейнере basket.html замените содержимое на: -->
<main class="container my-4">
<main class="container my-4">
<div class="empty-basket text-center py-5">
<h1 class="mb-4">Здесь будут лежать твои товары</h1>
<p class="lead mb-4">А пока здесь так пусто...</p>
@@ -69,6 +70,8 @@
<i class="bi bi-arrow-left me-2"></i>Вернуться в каталог
</a>
</div>
</div>
<div id="basketContainer"></div>
</main>
@@ -98,5 +101,18 @@
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="./components/basket/model.js"></script>
<script src="./components/basket/view.js"></script>
<script src="./components/basket/controller.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Проверяем, есть ли необходимые элементы на странице
if (document.getElementById('basketContainer') || document.getElementById('productsContainer')) {
const model = new Model();
const view = new View();
new Controller(model, view);
}
});
</script>
</body>

14
dist/catalog.html vendored
View File

@@ -353,5 +353,19 @@
this.reset();
});
</script>
<script src="./components/basket/model.js"></script>
<script src="./components/basket/view.js"></script>
<script src="./components/basket/controller.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Проверяем, есть ли необходимые элементы на странице
if (document.getElementById('basketContainer') || document.getElementById('productsContainer')) {
const model = new Model();
const view = new View();
new Controller(model, view);
}
});
</script>
</body>