Разработка современного интернет-магазина требует внимания к деталям и удобству пользователей. Одним из ключевых элементов, повышающих удобство покупок, является мини-корзина. Этот компонент позволяет покупателям быстро просматривать содержимое корзины и вносить изменения без перехода на отдельную страницу. В данной статье будет рассмотрено создание мини-корзины для интернет-магазина на Laravel, популярном PHP-фреймворке.
Что такое мини-корзина и почему она важна?
Мини-корзина представляет собой компактное отображение товаров, добавленных пользователем в корзину. Обычно она располагается в верхнем правом углу страницы и доступна с любой страницы сайта. Основные преимущества использования мини-корзины включают:
- Улучшение пользовательского опыта
- Увеличение конверсии
- Снижение количества брошенных корзин
- Упрощение процесса покупки
Реализация мини-корзины в Laravel требует знания фреймворка, а также понимания принципов работы с сессиями и AJAX-запросами.
Подготовка проекта Laravel
Перед началом работы над мини-корзиной необходимо убедиться, что проект Laravel настроен корректно и все необходимые зависимости установлены.
Установка Laravel
Если проект еще не создан, следует установить Laravel с помощью Composer:
composer create-project --prefer-dist laravel/laravel mini-cart-project
После установки нужно перейти в директорию проекта:
cd mini-cart-project
Настройка базы данных
Для работы с корзиной потребуется настроить подключение к базе данных. В файле .env необходимо указать параметры подключения:
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=mini_cart_db DB_USERNAME=root DB_PASSWORD=
После настройки подключения следует выполнить миграции:
php artisan migrate
Создание модели и миграции для товаров
Для работы с товарами в интернет-магазине необходимо создать соответствующую модель и миграцию.
Создание модели Product
Выполните команду для создания модели Product:
php artisan make:model Product -m
Эта команда создаст файл модели app/Models/Product.php и файл миграции в директории database/migrations.
Настройка миграции для товаров
Откройте созданный файл миграции и добавьте необходимые поля для товара:
public function up() { Schema::create('products', function (Blueprint $table) { $table->id(); $table->string('name'); $table->text('description'); $table->decimal('price', 8, 2); $table->string('image')->nullable(); $table->integer('stock')->default(0); $table->timestamps(); }); }
После внесения изменений выполните миграцию:
php artisan migrate
Реализация основной логики корзины
Теперь, когда база подготовлена, можно приступить к реализации основной логики корзины.
Создание сервиса корзины
Для управления корзиной создадим отдельный сервис. Создайте файл app/Services/CartService.php со следующим содержимым:
namespace App\Services; use Illuminate\Session\SessionManager; class CartService { const CART_KEY = 'cart'; protected $session; public function __construct(SessionManager $session) { $this->session = $session; } public function add($product, $quantity = 1) { $cart = $this->getCart(); if (isset($cart[$product->id])) { $cart[$product->id]['quantity'] += $quantity; } else { $cart[$product->id] = [ 'id' => $product->id, 'name' => $product->name, 'price' => $product->price, 'quantity' => $quantity, ]; } $this->session->put(self::CART_KEY, $cart); } public function remove($productId) { $cart = $this->getCart(); if (isset($cart[$productId])) { unset($cart[$productId]); } $this->session->put(self::CART_KEY, $cart); } public function update($productId, $quantity) { $cart = $this->getCart(); if (isset($cart[$productId])) { $cart[$productId]['quantity'] = $quantity; } $this->session->put(self::CART_KEY, $cart); } public function clear() { $this->session->forget(self::CART_KEY); } public function getCart() { return $this->session->get(self::CART_KEY, []); } public function getTotal() { $cart = $this->getCart(); $total = 0; foreach ($cart as $item) { $total += $item['price'] * $item['quantity']; } return $total; } }
Регистрация сервиса в сервис-контейнере
Для удобного использования сервиса корзины в различных частях приложения, зарегистрируем его в сервис-контейнере Laravel. Откройте файл app/Providers/AppServiceProvider.php и добавьте следующий код в метод register:
use App\Services\CartService; public function register() { $this->app->singleton(CartService::class, function ($app) { return new CartService($app['session']); }); }
Создание контроллера для управления корзиной
Следующим шагом будет создание контроллера для обработки запросов, связанных с корзиной.
Генерация контроллера
Выполните команду для создания контроллера:
php artisan make:controller CartController
Реализация методов контроллера
Откройте созданный файл app/Http/Controllers/CartController.php и добавьте следующий код:
namespace App\Http\Controllers; use App\Models\Product; use App\Services\CartService; use Illuminate\Http\Request; class CartController extends Controller { protected $cartService; public function __construct(CartService $cartService) { $this->cartService = $cartService; } public function add(Request $request) { $product = Product::findOrFail($request->input('product_id')); $quantity = $request->input('quantity', 1); $this->cartService->add($product, $quantity); return response()->json([ 'message' => 'Товар добавлен в корзину', 'cart' => $this->cartService->getCart(), 'total' => $this->cartService->getTotal(), ]); } public function remove(Request $request) { $productId = $request->input('product_id'); $this->cartService->remove($productId); return response()->json([ 'message' => 'Товар удален из корзины', 'cart' => $this->cartService->getCart(), 'total' => $this->cartService->getTotal(), ]); } public function update(Request $request) { $productId = $request->input('product_id'); $quantity = $request->input('quantity'); $this->cartService->update($productId, $quantity); return response()->json([ 'message' => 'Количество товара обновлено', 'cart' => $this->cartService->getCart(), 'total' => $this->cartService->getTotal(), ]); } public function clear() { $this->cartService->clear(); return response()->json([ 'message' => 'Корзина очищена', 'cart' => $this->cartService->getCart(), 'total' => $this->cartService->getTotal(), ]); } public function getCart() { return response()->json([ 'cart' => $this->cartService->getCart(), 'total' => $this->cartService->getTotal(), ]); } }
Настройка маршрутов для корзины
После создания контроллера необходимо настроить маршруты для обработки запросов к корзине.
Добавление маршрутов в web.php
Откройте файл routes/web.php и добавьте следующие маршруты:
use App\Http\Controllers\CartController; Route::post('/cart/add', [CartController::class, 'add'])->name('cart.add'); Route::post('/cart/remove', [CartController::class, 'remove'])->name('cart.remove'); Route::post('/cart/update', [CartController::class, 'update'])->name('cart.update'); Route::post('/cart/clear', [CartController::class, 'clear'])->name('cart.clear'); Route::get('/cart', [CartController::class, 'getCart'])->name('cart.get');
Создание интерфейса мини-корзины
Теперь, когда базовая функциональность корзины реализована, можно приступить к созданию интерфейса мини-корзины.
Создание шаблона мини-корзины
Создайте новый файл resources/views/components/mini-cart.blade.php со следующим содержимым:
<div id="mini-cart"> <h3>Корзина</h3> <ul id="cart-items"> <!-- Здесь будут отображаться товары --> </ul> <p>Итого: <span id="cart-total">0</span> руб.</p> <button id="clear-cart">Очистить корзину</button> </div>
Добавление стилей для мини-корзины
Создайте файл public/css/mini-cart.css и добавьте следующие стили:
#mini-cart { position: fixed; top: 20px; right: 20px; width: 300px; background-color: #fff; border: 1px solid #ccc; padding: 15px; box-shadow: 0 0 10px rgba(0,0,0,0.1); } #mini-cart h3 { margin-top: 0; } #cart-items { list-style-type: none; padding: 0; } #cart-items li { margin-bottom: 10px; } #clear-cart { background-color: #f44336; color: white; border: none; padding: 5px 10px; cursor: pointer; } #clear-cart:hover { background-color: #d32f2f; }
Интеграция мини-корзины в шаблон
Для отображения мини-корзины на всех страницах сайта, её нужно интегрировать в основной шаблон.
Обновление основного шаблона
Откройте файл resources/views/layouts/app.blade.php (или создайте его, если он отсутствует) и добавьте следующий код перед закрывающим тегом </body>:
@include('components.mini-cart') <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="{{ asset('js/mini-cart.js') }}"></script> <link rel="stylesheet" href="{{ asset('css/mini-cart.css') }}">
Реализация JavaScript для работы с мини-корзиной
Для обеспечения динамического обновления мини-корзины без перезагрузки страницы необходимо реализовать JavaScript-функционал.
Создание файла mini-cart.js
Создайте файл public/js/mini-cart.js и добавьте следующий код:
$(document).ready(function
() {
function updateMiniCart() {
$.ajax({
url: '/cart',
method: 'GET',
success: function(response) {
renderMiniCart(response.cart, response.total);
}
});
}
function renderMiniCart(cart, total) {
let cartItems = $('#cart-items');
cartItems.empty();
$.each(cart, function(index, item) {
cartItems.append(`
${item.name} - ${item.quantity} шт. x ${item.price} руб.
`);
});
$('#cart-total').text(total);
}
$(document).on('click', '.add-to-cart', function(e) {
e.preventDefault();
let productId = $(this).data('id');
let quantity = 1;
$.ajax({
url: '/cart/add',
method: 'POST',
data: {
product_id: productId,
quantity: quantity,
_token: $('meta[name="csrf-token"]').attr('content')
},
success: function(response) {
updateMiniCart();
alert(response.message);
}
});
});
$(document).on('click', '.remove-item', function() {
let productId = $(this).data('id');
$.ajax({
url: '/cart/remove',
method: 'POST',
data: {
product_id: productId,
_token: $('meta[name="csrf-token"]').attr('content')
},
success: function(response) {
updateMiniCart();
alert(response.message);
}
});
});
$(document).on('change', '.update-quantity', function() {
let productId = $(this).data('id');
let quantity = $(this).val();
$.ajax({
url: '/cart/update',
method: 'POST',
data: {
product_id: productId,
quantity: quantity,
_token: $('meta[name="csrf-token"]').attr('content')
},
success: function(response) {
updateMiniCart();
}
});
});
$('#clear-cart').on('click', function() {
$.ajax({
url: '/cart/clear',
method: 'POST',
data: {
_token: $('meta[name="csrf-token"]').attr('content')
},
success: function(response) {
updateMiniCart();
alert(response.message);
}
});
});
updateMiniCart();
});
Добавление функциональности добавления товаров в корзину
Теперь необходимо добавить возможность добавления товаров в корзину со страниц каталога или отдельных товаров.
Обновление шаблона товара
Откройте или создайте файл шаблона для отображения товара (например, resources/views/products/show.blade.php) и добавьте кнопку «Добавить в корзину»:
<div class="product"> <h2>{{ $product->name }}</h2> <p>{{ $product->description }}</p> <p>Цена: {{ $product->price }} руб.</p> <button class="add-to-cart" data-id="{{ $product->id }}">Добавить в корзину</button> </div>
Оптимизация производительности мини-корзины
Для обеспечения быстрой работы мини-корзины можно применить несколько методов оптимизации.
Кэширование данных корзины
Добавьте кэширование данных корзины в сервис CartService. Обновите файл app/Services/CartService.php:
use Illuminate\Support\Facades\Cache; class CartService { // ... public function getCart() { return Cache::remember('cart_' . $this->session->getId(), 60, function () { return $this->session->get(self::CART_KEY, []); }); } public function updateCart($cart) { $this->session->put(self::CART_KEY, $cart); Cache::put('cart_' . $this->session->getId(), $cart, 60); } // Обновите методы add, remove, update и clear, чтобы использовать updateCart вместо прямой записи в сессию }
Отложенная загрузка мини-корзины
Для улучшения времени загрузки страницы можно реализовать отложенную загрузку мини-корзины. Обновите файл public/js/mini-cart.js:
$(document).ready(function() { let miniCartLoaded = false; function loadMiniCart() { if (!miniCartLoaded) { updateMiniCart(); miniCartLoaded = true; } } // Загрузка мини-корзины при наведении мыши $('#mini-cart').on('mouseenter', loadMiniCart); // Загрузка мини-корзины при прокрутке страницы $(window).on('scroll', function() { if ($(window).scrollTop() > 200) { loadMiniCart(); } }); // ... остальной код });
Реализация анимации для мини-корзины
Добавление анимации может улучшить пользовательский опыт при работе с мини-корзиной.
Добавление CSS-анимаций
Обновите файл public/css/mini-cart.css, добавив следующие стили:
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes slideIn { from { transform: translateX(100%); } to { transform: translateX(0); } } #mini-cart { animation: fadeIn 0.3s ease-out, slideIn 0.3s ease-out; } .cart-item-added { animation: fadeIn 0.3s ease-out; } .cart-item-removed { animation: fadeOut 0.3s ease-out; } @keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } }
Обновление JavaScript для поддержки анимаций
Измените функцию renderMiniCart в файле public/js/mini-cart.js:
function renderMiniCart(cart, total) { let cartItems = $('#cart-items'); cartItems.empty(); $.each(cart, function(index, item) { let newItem = $(` ${item.name} - ${item.quantity} шт. x ${item.price} руб. `); cartItems.append(newItem); setTimeout(() => newItem.removeClass('cart-item-added'), 300); }); $('#cart-total').text(total); }
Добавление функции «Быстрый просмотр» для товаров
Функция «Быстрый просмотр» позволяет пользователям получить более подробную информацию о товаре без перехода на отдельную страницу.
Создание модального окна для быстрого просмотра
Добавьте следующий HTML-код в конец файла resources/views/layouts/app.blade.php:
<div id="quick-view-modal" class="modal"> <div class="modal-content"> <span class="close">×</span> <div id="quick-view-content"></div> </div> </div>
Добавление стилей для модального окна
Добавьте следующие стили в файл public/css/mini-cart.css:
.modal { display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgba(0,0,0,0.4); } .modal-content { background-color: #fefefe; margin: 15% auto; padding: 20px; border: 1px solid #888; width: 80%; max-width: 600px; } .close { color: #aaa; float: right; font-size: 28px; font-weight: bold; cursor: pointer; } .close:hover, .close:focus { color: #000; text-decoration: none; cursor: pointer; }
Реализация функциональности быстрого просмотра
Добавьте следующий код в файл public/js/mini-cart.js:
$(document).on('click', '.quick-view', function(e) { e.preventDefault(); let productId = $(this).data('id'); $.ajax({ url: '/products/' + productId + '/quick-view', method: 'GET', success: function(response) { $('#quick-view-content').html(response); $('#quick-view-modal').show(); } }); }); $('.close').on('click', function() { $('#quick-view-modal').hide(); }); $(window).on('click', function(event) { if (event.target == $('#quick-view-modal')[0]) { $('#quick-view-modal').hide(); } });
Создание контроллера и маршрута для быстрого просмотра
Создайте новый метод в app/Http/Controllers/ProductController.php:
public function quickView($id) { $product = Product::findOrFail($id); return view('products.quick-view', compact('product')); }
Добавьте новый маршрут в routes/web.php:
Route::get('/products/{id}/quick-view', [ProductController::class, 'quickView'])->name('products.quick-view');
Создание шаблона для быстрого просмотра
Создайте новый файл resources/views/products/quick-view.blade.php:
<div class="quick-view-product"> <h2>{{ $product->name }}</h2> <img src="{{ $product->image }}" alt="{{ $product->name }}"> <p>{{ $product->description }}</p> <p>Цена: {{ $product->price }} руб.</p> <button class="add-to-cart" data-id="{{ $product->id }}">Добавить в корзину</button> </div>
Реализация функции «Похожие товары»
Функция «Похожие товары» может увеличить продажи, предлагая пользователям дополнительные товары, которые могут их заинтересовать.
Добавление метода для получения похожих товаров
Добавьте следующий метод в модель app/Models/Product.php:
public function getSimilarProducts($limit = 4) { return $this->where('id', '!=', $this->id) ->inRandomOrder() ->limit($limit) ->get(); }
Обновление контроллера товара
Обновите метод show в app/Http/Controllers/ProductController.php:
public function show($id) { $product = Product::findOrFail($id); $similarProducts = $product->getSimilarProducts(); return view('products.show', compact('product', 'similarProducts')); }
Обновление шаблона товара
Добавьте секцию похожих товаров в resources/views/products/show.blade.php:
<h3>Похожие товары</h3> <div class="similar-products"> @foreach($similarProducts as $similarProduct) <div class="similar-product"> <h4>{{ $similarProduct->name }}</h4> <img src="{{ $similarProduct->image }}" alt="{{ $similarProduct->name }}"> <p>Цена: {{ $similarProduct->price }} руб.</p> <button class="add-to-cart" data-id="{{ $similarProduct->id }}">Добавить в корзину</button> <a href="{{ route('products.show', $similarProduct->id) }}" class="quick-view" data-id="{{ $similarProduct->id }}">Быстрый просмотр</a> </div> @endforeach </div>
Реализация функции «Часто покупаемые вместе»
Функция «Часто покупаемые вместе» помогает увеличить средний чек, предлагая пользователям товары, которые часто приобретаются вместе с выбранным товаром.
Создание таблицы для хранения связей между товарами
Создайте новую миграцию:
php artisan make:migration create_product_relations_table
Заполните файл миграции следующим содержимым:
public function up() { Schema::create('product_relations', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('product_id'); $table->unsignedBigInteger('related_product_id'); $table->integer('relation_count')->default(0); $table->timestamps(); $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade'); $table->foreign('related_product_id')->references('id')->on('products')->onDelete('cascade'); }); } public function down() { Schema::dropIfExists('product_relations'); }
Выполните миграцию:
php artisan migrate
Обновление модели Product
Добавьте следующий метод в модель app/Models/Product.php:
public function getFrequentlyBoughtTogether($limit = 4) { return $this->belongsToMany(Product::class, 'product_relations', 'product_id', 'related_product_id') ->withPivot('relation_count') ->orderByDesc('pivot_relation_count') ->limit($limit) ->get(); }
Создание сервиса для обновления связей между товарами
Создайте новый файл app/Services/ProductRelationService.php:
namespace App\Services; use App\Models\Product; use Illuminate\Support\Facades\DB; class ProductRelationService { public function updateRelations(array $productIds) { $combinations = $this->getCombinations($productIds); foreach ($combinations as $combination) { DB::table('product_relations') ->updateOrInsert( [ 'product_id' => $combination[0], 'related_product_id' => $combination[1] ], [ 'relation_count' => DB::raw('relation_count + 1'), 'updated_at' => now() ] ); } } private function getCombinations(array $items) { $result = []; for ($i = 0; $i < count($items); $i++) { for ($j = $i + 1; $j < count($items); $j++) { $result[] = [$items[$i], $items[$j]]; } } return $result; } }
Обновление OrderController
Обновите метод store в app/Http/Controllers/OrderController.php, чтобы обновлять связи между товарами после оформления заказа:
use App\Services\ProductRelationService; public function store(Request $request, CartService $cartService, ProductRelationService $productRelationService) { // ... код создания заказа $productIds = $cartService->getCart()->pluck('id')->toArray(); $productRelationService->updateRelations($productIds); $cartService->clear(); return redirect()->route('orders.success'); }
Обновление шаблона товара
Добавьте секцию "Часто покупают вместе" в resources/views/products/show.blade.php:
<h3>Часто покупают вместе</h3> <div class="frequently-bought-together"> @foreach($product->getFrequentlyBoughtTogether() as $relatedProduct) <div class="related-product"> <h4>{{ $relatedProduct->name }}</h4> <img src="{{ $relatedProduct->image }}" alt="{{ $relatedProduct->name }}"> <p>Цена: {{ $relatedProduct->price }} руб.</p> <button class="add-to-cart" data-id="{{ $relatedProduct->id }}">Добавить в корзину</button> <a href="{{ route('products.show', $relatedProduct->id) }}" class="quick-view" data-id="{{ $relatedProduct->id }}">Быстрый просмотр</a> </div> @endforeach </div>
Реализация функции "Недавно просмотренные товары"
Функция "Недавно просмотренные товары" помогает пользователям быстро вернуться к товарам, которые они просматривали ранее.
Создание сервиса для работы с недавно просмотренными товарами
Создайте новый файл app/Services/RecentlyViewedService.php:
namespace App\Services; use Illuminate\Session\SessionManager; use App\Models\Product; class RecentlyViewedService { const RECENTLY_VIEWED_KEY = 'recently_viewed'; const MAX_ITEMS = 10; protected $session; public function __construct(SessionManager $session) { $this->session = $session; } public function addProduct($productId) { $recentlyViewed = $this->getRecentlyViewed(); if (($key = array_search($productId, $recentlyViewed)) !== false) { unset($recentlyViewed[$key]); } array_unshift($recentlyViewed, $productId); $recentlyViewed = array_slice($recentlyViewed, 0, self::MAX_ITEMS); $this->session->put(self::RECENTLY_VIEWED_KEY, $recentlyViewed); } public function getRecentlyViewed() { return $this->session->get(self::RECENTLY_VIEWED_KEY, []); } public function getRecentlyViewedProducts() { $productIds = $this->getRecentlyViewed(); return Product::whereIn('id', $productIds) ->orderByRaw("FIELD(id, " . implode(',', $productIds) . ")") ->get(); } }
Регистрация сервиса в сервис-контейнере
Добавьте следующий код в метод register в файле app/Providers/AppServiceProvider.php:
use App\Services\RecentlyViewedService; $this->app->singleton(RecentlyViewedService::class, function ($app) { return new RecentlyViewedService($app['session']); });
Обновление ProductController
Обновите метод show в app/Http/Controllers/ProductController.php:
use App\Services\RecentlyViewedService; public function show($id, RecentlyViewedService $recentlyViewedService) { $product = Product::findOrFail($id); $recentlyViewedService->addProduct($id); $similarProducts = $product->getSimilarProducts(); $frequentlyBoughtTogether = $product->getFrequentlyBoughtTogether(); $recentlyViewedProducts = $recentlyViewedService->getRecentlyViewedProducts()->except($id); return view('products.show', compact('product', 'similarProducts', 'frequentlyBoughtTogether', 'recentlyViewedProducts')); }
Обновление шаблона товара
Добавьте секцию "Недавно просмотренные товары" в resources/views/products/show.blade.php:
<h3>Недавно просмотренные товары</h3> <div class="recently-viewed-products"> @foreach($recentlyViewedProducts as $recentProduct) <div class="recent-product"> <h4>{{ $recentProduct->name }}</h4> <img src="{{ $recentProduct->image }}" alt="{{ $recentProduct->name }}"> <p>Цена: {{ $recentProduct->price }} руб.</p> <button class="add-to-cart" data-id="{{ $recentProduct->id }}">Добавить в корзину</button> <a href="{{ route('products.show', $recentProduct->id) }}" class="quick-view" data-id="{{ $recentProduct->id }}">Быстрый просмотр</a> </div> @endforeach </div>
Оптимизация загрузки страницы товара
Для улучшения производительности страницы товара можно применить несколько методов оптимизации.
Использование кэширования
Добавьте кэширование для часто запрашиваемых данных. Обновите метод show в app/Http/Controllers/ProductController.php:
use Illuminate\Support\Facades\Cache; public function show($id, RecentlyViewedService $recentlyViewedService) { $product = Cache::remember('product_' . $id, 3600, function () use ($id) { return Product::findOrFail($id); }); $recentlyViewedService->addProduct($id); $similarProducts = Cache::remember('similar_products_' . $id, 3600, function () use ($product) { return $product->getSimilarProducts(); }); $frequentlyBoughtTogether = Cache::remember('frequently_bought_' . $id, 3600, function () use ($product) { return $product->getFrequentlyBoughtTogether(); }); $recentlyViewedProducts = $recentlyViewedService->getRecentlyViewedProducts()->except($id); return view('products.show', compact('product', 'similarProducts', 'frequentlyBoughtTogether', 'recentlyViewedProducts')); }
Отложенная загрузка изображений
Используйте атрибут loading="lazy" для изображений, чтобы отложить их загрузку. Обновите все теги img в шаблонах:
<img src="{{ $product->image }}" alt="{{ $product->name }}" loading="lazy">
Минификация CSS и JavaScript
Используйте Laravel Mix для минификации и объединения CSS и JavaScript файлов. Обновите файл webpack.mix.js:
const mix = require('laravel-mix'); mix.js('resources/js/app.js', 'public/js') .sass('resources/sass/app.scss', 'public/css') .styles([ 'public/css/mini-cart.css', // другие CSS файлы ], 'public/css/all.css') .scripts([ 'public/js/mini-cart.js', // другие JS файлы ], 'public/js/all.js') .version();
Затем обновите ссылки на CSS и JavaScript файлы в вашем основном шаблоне:
<link rel="stylesheet" href="{{ mix('css/all.css') }}"> <script src="{{ mix('js/all.js') }}" defer></script>
Добавление функции "Список желаний"
Функция "Список желаний" позволяет пользователям сохранять товары, которые они хотели бы купить в будущем.
Создание модели и миграции для списка желаний
Создайте новую модель и миграцию:
php artisan make:model Wishlist -m
Заполните файл миграции следующим содержимым:
public function up() { Schema::create('wishlists', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('user_id'); $table->unsignedBigInteger('product_id'); $table->timestamps(); $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade'); }); } public function down() { Schema::dropIfExists('wishlists'); }
Выполните миграцию:
php artisan migrate
Обновление модели User
Добавьте следующий метод в модель app/Models/User.php:
public function wishlist() { return $this->belongsToMany(Product::class, 'wishlists')->withTimestamps(); }
Создание контроллера для списка желаний
Создайте новый контроллер:
php artisan make:controller WishlistController
Заполните файл app/Http/Controllers/WishlistController.php следующим содержимым:
namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\Product; class WishlistController extends Controller { public function __construct() { $this->middleware('auth'); } public function index() { $wishlist = auth()->user
()->wishlist;
return view('wishlist.index', compact('wishlist'));
}
public function add(Request $request)
{
$product = Product::findOrFail($request->input('product_id'));
auth()->user()->wishlist()->attach($product);
return response()->json(['message' => 'Товар добавлен в список желаний']);
}
public function remove(Request $request)
{
$product = Product::findOrFail($request->input('product_id'));
auth()->user()->wishlist()->detach($product);
return response()->json(['message' => 'Товар удален из списка желаний']);
}
}
Добавление маршрутов для списка желаний
Добавьте следующие маршруты в файл routes/web.php:
Route::get('/wishlist', [WishlistController::class, 'index'])->name('wishlist.index'); Route::post('/wishlist/add', [WishlistController::class, 'add'])->name('wishlist.add'); Route::post('/wishlist/remove', [WishlistController::class, 'remove'])->name('wishlist.remove');
Создание шаблона для списка желаний
Создайте новый файл resources/views/wishlist/index.blade.php:
@extends('layouts.app') @section('content') <h1>Список желаний</h1> @if($wishlist->count() > 0) <ul> @foreach($wishlist as $product) <li> <h3>{{ $product->name }}</h3> <img src="{{ $product->image }}" alt="{{ $product->name }}" loading="lazy"> <p>Цена: {{ $product->price }} руб.</p> <button class="add-to-cart" data-id="{{ $product->id }}">Добавить в корзину</button> <button class="remove-from-wishlist" data-id="{{ $product->id }}">Удалить из списка желаний</button> </li> @endforeach </ul> @else <p>Ваш список желаний пуст.</p> @endif @endsection @section('scripts') <script> $(document).ready(function() { $('.remove-from-wishlist').on('click', function() { let productId = $(this).data('id'); $.ajax({ url: '{{ route('wishlist.remove') }}', method: 'POST', data: { product_id: productId, _token: '{{ csrf_token() }}' }, success: function(response) { alert(response.message); location.reload(); } }); }); }); </script> @endsection
Обновление шаблона товара
Добавьте кнопку "Добавить в список желаний" в файл resources/views/products/show.blade.php:
<button class="add-to-wishlist" data-id="{{ $product->id }}">Добавить в список желаний</button>
Добавьте JavaScript для обработки добавления в список желаний:
@section('scripts') <script> $(document).ready(function() { $('.add-to-wishlist').on('click', function() { let productId = $(this).data('id'); $.ajax({ url: '{{ route('wishlist.add') }}', method: 'POST', data: { product_id: productId, _token: '{{ csrf_token() }}' }, success: function(response) { alert(response.message); } }); }); }); </script> @endsection
Реализация функции сравнения товаров
Функция сравнения товаров позволяет пользователям сравнивать характеристики нескольких товаров одновременно.
Создание сервиса для сравнения товаров
Создайте новый файл app/Services/CompareService.php:
namespace App\Services; use Illuminate\Session\SessionManager; use App\Models\Product; class CompareService { const COMPARE_KEY = 'compare_products'; const MAX_ITEMS = 4; protected $session; public function __construct(SessionManager $session) { $this->session = $session; } public function addProduct($productId) { $compareList = $this->getCompareList(); if (!in_array($productId, $compareList) && count($compareList) < self::MAX_ITEMS) { $compareList[] = $productId; $this->session->put(self::COMPARE_KEY, $compareList); } } public function removeProduct($productId) { $compareList = $this->getCompareList(); if (($key = array_search($productId, $compareList)) !== false) { unset($compareList[$key]); $this->session->put(self::COMPARE_KEY, array_values($compareList)); } } public function getCompareList() { return $this->session->get(self::COMPARE_KEY, []); } public function getCompareProducts() { $productIds = $this->getCompareList(); return Product::whereIn('id', $productIds)->get(); } public function clearCompareList() { $this->session->forget(self::COMPARE_KEY); } }
Регистрация сервиса в сервис-контейнере
Добавьте следующий код в метод register в файле app/Providers/AppServiceProvider.php:
use App\Services\CompareService; $this->app->singleton(CompareService::class, function ($app) { return new CompareService($app['session']); });
Создание контроллера для сравнения товаров
Создайте новый контроллер:
php artisan make:controller CompareController
Заполните файл app/Http/Controllers/CompareController.php следующим содержимым:
namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Services\CompareService; class CompareController extends Controller { protected $compareService; public function __construct(CompareService $compareService) { $this->compareService = $compareService; } public function index() { $products = $this->compareService->getCompareProducts(); return view('compare.index', compact('products')); } public function add(Request $request) { $this->compareService->addProduct($request->input('product_id')); return response()->json(['message' => 'Товар добавлен к сравнению']); } public function remove(Request $request) { $this->compareService->removeProduct($request->input('product_id')); return response()->json(['message' => 'Товар удален из сравнения']); } public function clear() { $this->compareService->clearCompareList(); return response()->json(['message' => 'Список сравнения очищен']); } }
Добавление маршрутов для сравнения товаров
Добавьте следующие маршруты в файл routes/web.php:
Route::get('/compare', [CompareController::class, 'index'])->name('compare.index'); Route::post('/compare/add', [CompareController::class, 'add'])->name('compare.add'); Route::post('/compare/remove', [CompareController::class, 'remove'])->name('compare.remove'); Route::post('/compare/clear', [CompareController::class, 'clear'])->name('compare.clear');
Создание шаблона для сравнения товаров
Создайте новый файл resources/views/compare/index.blade.php:
@extends('layouts.app') @section('content') <h1>Сравнение товаров</h1> @if($products->count() > 0) <table> <tr> <th>Характеристика</th> @foreach($products as $product) <th> {{ $product->name }} <button class="remove-from-compare" data-id="{{ $product->id }}">Удалить</button> </th> @endforeach </tr> <tr> <td>Цена</td> @foreach($products as $product) <td>{{ $product->price }} руб.</td> @endforeach </tr> <!-- Добавьте другие характеристики для сравнения --> </table> <button id="clear-compare">Очистить список сравнения</button> @else <p>Список сравнения пуст.</p> @endif @endsection @section('scripts') <script> $(document).ready(function() { $('.remove-from-compare').on('click', function() { let productId = $(this).data('id'); $.ajax({ url: '{{ route('compare.remove') }}', method: 'POST', data: { product_id: productId, _token: '{{ csrf_token() }}' }, success: function(response) { alert(response.message); location.reload(); } }); }); $('#clear-compare').on('click', function() { $.ajax({ url: '{{ route('compare.clear') }}', method: 'POST', data: { _token: '{{ csrf_token() }}' }, success: function(response) { alert(response.message); location.reload(); } }); }); }); </script> @endsection
Обновление шаблона товара
Добавьте кнопку "Добавить к сравнению" в файл resources/views/products/show.blade.php:
<button class="add-to-compare" data-id="{{ $product->id }}">Добавить к сравнению</button>
Добавьте JavaScript для обработки добавления к сравнению:
@section('scripts') <script> $(document).ready(function() { $('.add-to-compare').on('click', function() { let productId = $(this).data('id'); $.ajax({ url: '{{ route('compare.add') }}', method: 'POST', data: { product_id: productId, _token: '{{ csrf_token() }}' }, success: function(response) { alert(response.message); } }); }); }); </script> @endsection
Оптимизация SEO для страниц товаров
Оптимизация SEO поможет улучшить видимость страниц товаров в поисковых системах.
Добавление мета-тегов
Обновите файл resources/views/products/show.blade.php, добавив мета-теги:
@section('meta') <meta name="description" content="{{ $product->description }}"> <meta name="keywords" content="{{ $product->name }}, {{ $product->category }}"> <meta property="og:title" content="{{ $product->name }}"> <meta property="og:description" content="{{ $product->description }}"> <meta property="og:image" content="{{ $product->image }}"> <meta property="og:url" content="{{ route('products.show', $product->id) }}"> @endsection
Использование семантической разметки
Добавьте семантическую разметку Schema.org для товара:
<div itemscope itemtype="http://schema.org/Product"> <h1 itemprop="name">{{ $product->name }}</h1> <img itemprop="image" src="{{ $product->image }}" alt="{{ $product->name }}"> <p itemprop="description">{{ $product->description }}</p> <div itemprop="offers" itemscope itemtype="http://schema.org/Offer"> <span itemprop="price">{{ $product->price }}</span> <meta itemprop="priceCurrency" content="RUB"> </div> </div>