сентябрь 6 , 2015

Однажды пришла мне в голову безумная идея написать серию постов про различные подходы к организации javascript-кода. Такая мысль образовалась, когда по рабочей надобности изучал React.js и возрадовался от некоторых идей, заложенных его авторами. Захотелось потрогать его побольше, а потому как писать хеллоуворды из документации скучно, нужна была какая-то идея. Раз уж я начал вести блог на тему веб-разработки, то почему бы не создать простое, но более-менее внятное приложение с применением различных библиотек и фреймворков? И не только реакта, а любых других, до которых доберется дурной и воспаленный ум. В качестве подопытного приложения я возьму простенький интернет-магазин с каталогом и корзиной. Фишка будет в том, что код и каталога, и корзины будет написан на javascript. Корзина на фронте - не самое удачное решение для реальных проектов, но для небольших сайтов и в качестве изучения подойдет неплохо. Для изучения React понадобится сколько-то времени, поэтому для начала развлеку вас статьей, где опишу процесс создания нашего приложения без использования библиотек и фреймворков, но с использованием яваскрипт-модулей. Главная моя цель - это показать различные подходы к созданию приложений на javascript. С версткой заморачиваться сильно не буду, сверстаю на bootstrap, основной упор сделаю на javascript-код. Манипулировать DOM будем всем знакомым добрым jquery. Также подключим underscore для работы с данными и html-шаблонами. Данные для каталога загрузим из внешнего json-файла, а корзину будем хранить в localStorage. Итак, начнем...

Идея приложения и схема работы.

Итак, интернет-магазин на фронте. Что мы хотим от него? Хотим, чтобы была возможность как минимум вывести каталог товаров, реализовать добавление их в корзину, просматривать оную корзину, менять количество товаров в ней и удалять ошибочно добавленные с пересчетом стоимости заказа. Плюс добавим хранение данных в localStorage, дабы после перезагрузки страницы наша корзина не ушла в небытие.

Обращаю внимание, что это не одностраничное приложение. Мы создадим 2 html-страницы, каталог и корзина, но они будут служить только каркасом с основному коду. Основной код - это все-таки javascript.

Функционал подробнее.

Главное меню - 2 кнопки, каталог и корзина. В меню рядом с надписью "корзина" показывается выбранных количество товаров. Страница index - главная страница магазина, она же каталог. Подгружаем товары их из внешнего json-файла. Товары имеют поля: id, name, price, img. У каждого товара есть кнопка "Добавить в корзину". Список товаров храним в localStorage (id, name, count, price). Корзина - таблица с выбранными товарами. Выводим id и название товара, его количество и сумму. Под таблицей показываем общую сумму всех товаров. При изменении количества товаров и его удалении меняем все связанные данные. Каталог и корзину мы оформим в виде отдельных модулей.

Можно посмотреть, что у нас в итоге получится, . Попробуйте добавить товары в корзину, перейти в нее, менять количество и удалять товары, и увидите, как задумана работа магазина. Или можете сразу скачать исходники по этой ссылке .

Структура файлов

В корне проекта разместим 2 файла: index.html (каталог) и cart.html (корзина). И несколько папок: css, там лежит bootstrap.min.css и main.css - наши стили. Папка data содержит один файл goods.json - наши товары. fonts хранит шрифты от bootstrap-иконок. img - картинки товаров и гифку loading, которую мы будем показывать посетителям сайта, пока грузится каталог и корзина. Папка js разделена на 2 подпапки: vendor и modules. vendor содержит нужные нам библиотеки: jquery и underscore, а modules - модули нашего приложения. Их всего 3: main.js отвечает за инициализацию приложения, catalog - за вывод товаров, cart - за работу корзины.

Небольшое отступление : я намеренно не стал вводить лишнюю логику для нашего проекта. Хорошей практикой считается разработка с подходом MVC, разделение кода на модели, контроллеры и представления и разбиение этих частей на отдельные файлы для наглядности. Можно долго спорить на тему правильности применения такого подхода для абсолютно всех проектов, но в нашем конкретном примере мы отойдем от этого постулата и весь код для управления корзиной разместим в одном файле, а уже внутри него логически отделим работу с данными от разметки.

Приступаем к разработке.

Я не буду расписывать подробно каждую строчку кода, это заняло бы слишком много места и времени. В статье рассмотрим основные моменты, а весь код можно посмотреть в исходниках по ссылке выше. Код с подробными комментариями.
Начинаем.

Создаем разметку.

Создадим в корне нашего проекта файлы index.html и cart.html. Каждый файл - стандартная html5-заготовка. В блоке head подключим шрифт Ubuntu с Google Fonts и 2 css-файла: bootstrap.min.css и наши собственные стили main.css.

Webdevkin. Интернет-магазин. Javascript В конце страницы, перед закрывающим тегом body, подключим скрипты в таком порядке: Разметка для index.html

Из интересного: мы указываем в data-page тега body название страницы и элемент с id="total-cart-count", который будет содержать количество добавленных в корзину товаров. Список товаров каталога будет выводиться в списке id="goods". При загрузке страницы в список поместим нашу гифку loading, чтобы пользователи не скучали, ожидая загрузки каталога.

Разметка для cart.html

Здесь тоже нет ничего особенного: заготовка таблицы корзины, надпись "итого" и кнопка заказа (ее функционал мы реализовывать не будем). Содержимое корзины будет выводиться в tbody id="cart", сейчас на этом месте уже знакомая гифка. На заметку: соглашения по html и css-коду.

В верстке я всегда стараюсь не забывать несколько моментов и рекомендую их Вам.
Первое: верстаем всегда на классах и только на классах. Никаких айдишников в css. id нужны для яваскрипт-кода - для быстрого получения доступа к элементу DOM.
И второе: если в js-коде нам нужно обращаться к множеству элементов (много кнопок добавления в корзину), то навешиваем элементам классы с префиксом "js-". И не используем эти "js-ы" в css-коде. Сначала эти соглашения кажутся излишними, но понимание плюсов быстро проходит с ростом проекта. Лучше сразу привыкать к подобному стилю, тем более, что его используют достаточно много разработчиков.

Готовим данные и разметку для каталога

Для начала создадим файл для хранения наших товаров: data/goods.json

[ { "id": "1", "name": "Ноутбук Lenovo", "price": "18000", "img": "img/cars/notebook_lenovo.jpg" }, { "id": "2", "name": "Фотокамера Nikon", "price": "25000", "img": "img/cars/camera_nikon.jpg" }, { "id": "3", "name": "Apple ipad", "price": "35000", "img": "img/cars/ipad.jpg" }, { "id": "4", "name": "Samsung Galaxy", "price": "20000", "img": "img/cars/phone_galaxy.jpg" }, { "id": "5", "name": "Телевизор SUPRA", "price": "19000", "img": "img/cars/tv_supra.jpg" } ] Как видим, это обычный json-массив с четырьмя нужными нам полями. Теперь переходим к созданию каталога. Но прежде чем приступить к написанию js-кода, нам придется написать еще немного разметки для отображения отдельного товара. Мы будем использовать шаблоны html-кода библиотеки underscore для динамической генерации отдельных товаров. Если Вы не знакомы с шаблонами underscore, то у меня есть . Я же не буду зацикливаться на этом, а просто приведу код шаблона, тем более, что он достаточно тривиален и не требует долгих разбирательств: Что происходит в этом коде? underscore-шаблон представляет собой обычную строку, в которую подставляются нужные данные. Это неплохой способ отделить логику и данные от представления. Вся идея шаблонов в том, что мы не знаем, каким образом получены данные, но мы знаем, как их нужно отобразить. В нашем примере мы даем на вход массив товаров goods (из файла goods.json), перебираем все товары в цикле с помощью функции each библиотеки underscore и для каждого товара выводим свою разметку, подставляя в нужные места id товара, название, картинку и цену. Обратите внимание на дата-атрибуты у кнопки "Добавить в корзину", они будут использованы в дальнейшем. Приведенный код мы поместим в тело body файла index.html. Дальше мы увидим, как связать данные и наш underscore-шаблон.

Пишем js-модуль каталога

Код файла catalog.js будет очень коротким

"use strict"; // Модуль каталога var catalog = (function($) { // Инициализация модуля function init() { _render(); } // Рендерим каталог function _render() { var template = _.template($("#catalog-template").html()), $goods = $("#goods"); $.getJSON("data/goods.json", function(data) { $goods.html(template({goods: data})); }); } // Экспортируем наружу return { init: init } })(jQuery); Здесь с помощью замыкания мы объявляем переменную-модуль catalog, пишем функцию init, которая вызывает самую интересную нам функцию _render и экспортируем init наружу, разрешая при этом вызывать catalog.init() из других модулей приложения. На самом деле можно обойтись и без лишней init-функции, но лучше всегда объявлять публичную функцию инициализации во всех модулях для единообразия. При этом функция _render начинается со знака _, чем мы показываем, что эта функция частная и не должна выходить за пределы модуля. Применяя такой подход, мы уже в коде модуля видим, что используется в других модулях, а что предназначено только для внутреннего пользования. Этакая инкапсуляция кода, как в ООП.

Разберем функцию _render. Сначала мы объявляем переменную template = _.template($("#catalog-template").html()).
_.template - это функция underscore, которая рендерит html-разметку, используя шаблон html и данные для него.
$("#catalog-template").html() - содержимое шаблона, т.е. просто строка. $.getJSON получает данные из внешнего файла и передает наш массив товаров в колбэк. Выражение template({goods: data}) означает, что мы передаем функции template объект с данными и генерируем на их основе html-строку. Эта строка вставляется на страницу при помощи $goods.html(htmlString). Теперь вызов функции catalog.init() - это все, что нужно, чтобы загрузить каталог на страницу index.html

Модуль корзины

Наконец мы приступаем к самой интересной части нашего проекта - к корзине. Наш модуль будет разбит на 3 логические части:

  • 1 - логика работы с данными
  • 2 - работа с событиями DOM
  • 3 - общие функции инициализации и настройки
Вот так будет выглядеть заготовка модуля: "use strict"; // Модуль корзины var cart = (function($) { var cartData, // данные корзины - массив объектов opts = {}; // настройки модуля // Инициализация модуля function init(options) { _initOptions(options); // Получение данных // Рендер корзины _bindHandlers(); } // Инициализируем настройки function _initOptions(options) { // код } // Навешивам события function _bindHandlers() { // код } // Функции работы с данными // Функции рендеринга // Функции-обработчики событий // Экспортируем наружу return { init: init, // функции работы с данными } })(jQuery); Разберем нашу заготовку. Имеются 2 глобальных переменных для всего модуля: данные корзины и набор параметров. Этот набор содержит настройки модуля, такие как названия классов и дата-атрибутов, id элементов количества товаров и общей суммы заказа, классы для кнопок добавить, удалить, изменить количество и прочие. Подробнее рассмотрим ниже. Основная функция - инициализация модуля. Вне модуля будет вызываться только она, остальное скрыто в реализации корзины. Инициализируется модуль в таком порядке: назначаются опции модуля, получаем данные для корзины из localStorage, рендерим саму корзину, количество товаров и общую сумму заказа и напоследок привязываем обработчики к событиям DOM. Примечание: если Вы раньше не использовали такой подход, отделение данных от разметки, то удивитесь, насколько интереснее писать отдельно код обработки данных и после проще навешивать события на кнопочки. Дальше мы это продемонстрируем.

Вероятно, Вы обратили внимание, что я экспортирую наружу не только init, но и все функции, касающиеся обработки данных. Сделано это для того, чтобы облегчить тестирование кода. Каким образом проходят тесты? Есть 2 способа: ручной и unit-тесты. При тестировании руками мы в консоли браузера вызываем функции модуля и сразу же видим результат. Например, вызвав cart.add({id: 1, name: "notebook", price: 30000, count: 2}), мы в консоли же можем сразу увидеть изменения и убедиться, что данные действительно добавлены (или что-то пошло не так). Мы отделили логику работы с данными от остальных функций и увидели, что так тестировать гораздо веселее, чем тыкать по кнопочкам и проверять содержимое localStorage после каждого клика. Второй способ будет напрашиваться сам собой, когда нам надоест набивать команды в консоли и мы наконец разберемся с unit-тестированием кода. Об этом я напишу в одной из ближайших статей.

UPDATED: Для интересующихся unit-тестированием опубликована статья unit-тесты на фронте или изучаем jasmine.js . В ней рассказывается, как тестировать код на примере нашей корзины с помощью популярной библиотеки jasmine.js.

Пишем функции обработки данных

Всего мы напишем 11 функций:

  • 1. updateData - обновляем данные из localStorage, записываем содержимое в переменную cartData
  • 2. getData - возвращаем данные
  • 3. saveData - сохраняем корзину в localStorage
  • 4. clearData - очищаем корзину
  • 5. getById - ищем элемент корзины по id товара
  • 6. add - добавляем товар в корзину
  • 7. remove - удаляем товар из корзины
  • 8. changeCount - меняем количество
  • 9. getCount - возвращаем число уникальных товаров корзины
  • 10. getCountAll - возвращаем число всех товаров корзины
  • 11. getSumma - возвращаем общую сумму заказа
Код всех функций достаточно простой, в несколько строк, поэтому привожу сразу все функции. При обработке используются методы underscore. Если Вы еще не знакомы с этой библиотекой, настоятельно рекомендую ее изучить. Не зря ее называют "швейцарским ножом для javascript-разработчика". Беглое изучение официальной документации (есть на русском языке) займет немного времени, а пользу принесет заметную. Полный код работы с данными // Получаем данные function updateData() { cartData = JSON.parse(localStorage.getItem("cart")) || ; return cartData; } // Возвращаем данные function getData() { return cartData; } // Сохраняем данные в localStorage function saveData() { localStorage.setItem("cart", JSON.stringify(cartData)); return cartData; } // Очищаем данные function clearData() { cartData = ; saveData(); return cartData; } // Поиск объекта в коллекции cartData по id function getById(id) { return _.findWhere(cartData, {id: id}); } // Добавление товара в коллекцию function add(item) { var oldItem; updateData(); oldItem = getById(item.id); if(!oldItem) { cartData.push(item); } else { oldItem.count = oldItem.count + item.count; } saveData(); return item; } // Удаление товара из коллекции function remove(id) { updateData(); cartData = _.reject(cartData, function(item) { return item.id === id; }); saveData(); return cartData; } // Изменение количества товара в коллекции function changeCount(id, delta) { var item; updateData(); item = getById(id); if(item) { item.count = item.count + delta; if (item.count

Из интересного отмечу, что каждая функция возвращает какие-то данные: корзину целиком, добавленный товар или общую сумму. Не все возвращаемые данные используются в модуле, но все облегчают тестирование. Также видим, что в localStorage мы храним сериализованный массив товаров. В функции добавление предусмотрено условие: если мы добавляем товар, уже находящийся в корзине, то не создается дубликат товара, а увеличивается количество уже существующего. При уменьшении количества конкретного товара до нуля, оный удаляется из корзины.

Инициализация настроек. Настройки по умолчанию.

Прежде чем писать функции рендеринга и обработчиков событий, вернемся чуть назад и рассмотрим инициализацию настроек модуля. Функция _initOptions скопирует в переменную opts все настройки, переданные в модуль корзины при его создании.

// Инициализируем настройки function _initOptions(options) { var defaultOptions = { renderCartOnInit: true, // рендерить ли корзину при инициализации renderMenuCartOnInit: true, // рендерить ли количество товаров в меню при инициализации elAddToCart: ".js-add-to-cart", // селектор для кнопки добавления в корзину attrId: "data-id", // дата-атрибут для id товара attrName: "data-name", // дата-атрибут для названия товара attrPrice: "data-price", // дата-атрибут для цены товара attrDelta: "data-delta", // дата-атрибут, показывающий, на сколько нужно изменить количество товара в корзине (-1 и 1) elCart: "#cart", // селектор для содержимого корзины elTotalCartCount: "#total-cart-count", // селектор для количества товаров в корзине elTotalCartSumma: "#total-cart-summa", // селектор для общей суммы заказа elCartItem: ".js-cart-item", // селектор для отдельного пункта корзины elCartCount: ".js-count", // селектор для количества отдельного товара elCartSumma: ".js-summa", // селектор для суммы отдельного товара elChangeCount: ".js-change-count", // селектор для кнопок изменения количества elRemoveFromCart: ".js-remove-from-cart", // селектор для кнопки удаления из корзины elOrder: "#order" // селектор для кнопки оформления заказа } _.defaults(options || {}, defaultOptions); opts = _.clone(options); } Сначала мы объявляем настройки по умолчанию, а затем "склеиваем" их с данными, пришедшими извне. Для небольшого приложения, как у нас, реализовывать возможность настройки модуля было не обязательно. Но это небольшое увеличение кода дает нам большую гибкость при переносе этого модуля в другой проект.

Рендер корзины и html-шаблон

Для начала создадим шаблон для отображения корзины и поместим его в секцию body файла cart.html.

Здесь все знакомо по аналогичному фунционалу в каталоге. В дата-атрибуты помещаем id товаров, чтобы было понятно, с какими именно мы сейчас работаем. Атрибут data-delta показывает, увеличивать или уменьшать количество товара при клике на эту кнопку.

Функции рендеринга. // Рендерим корзину function renderCart() { var template = _.template($("#cart-template").html()), data = { goods: cartData }; $(opts.elCart).html(template(data)); renderTotalCartSumma(); } // Рендерим количество товаров в меню function renderMenuCart() { var countAll = getCountAll(); $(opts.elTotalCartCount).html(countAll !== 0 ? countAll: ""); } // Рендерим общую сумму товаров function renderTotalCartSumma() { $(opts.elTotalCartSumma).html(getSumma()); } Операции с DOM традиционно тяжелые, поэтому рендерить корзину мы будем целиком, а вот при генерации количества и суммы - точечно обращаться к элементам. Обработчики событий.

Приближаемся к завершению...

Напишем вспомогательную функцию получения элемента корзины по его id. Она пригодится нам при изменении количества и удалении товаров

// Поиск продукта в корзине по id function findCartElemById(id) { return $(opts.elCartItem + "[" + opts.attrId + "=""+id+""]"); } Выглядит строка страшно, но смысл сводится к поиску такого элемента $(".js-cart-item").

Всего у нас будет 4 обработчика-клика: добавление в корзину, изменение количества, удаление и оформление заказа. Смотрим:

// Добавление в корзину function _onClickAddBtn() { $("body").on("click", opts.elAddToCart, function(e) { var $this = $(this); add({ id: +$this.attr(opts.attrId), name: $this.attr(opts.attrName), price: +$this.attr(opts.attrPrice), count: 1 }); renderMenuCart(); alert("Товар добавлен в корзину"); }); } // Меняем количество товаров в корзине function _onClickChangeCountInCart() { $("body").on("click", opts.elChangeCount, function(e) { var $this = $(this), id = +$this.attr(opts.attrId), delta = +$this.attr(opts.attrDelta), $cartElem = findCartElemById(id), cartItem = changeCount(id, delta); if (cartItem.count) { $cartElem.find(opts.elCartCount).html(cartItem.count); $cartElem.find(opts.elCartSumma).html(cartItem.count * cartItem.price); } else { $cartElem.remove(); } renderMenuCart(); renderTotalCartSumma(); }); } // Удаляем товар из корзины function _onClickRemoveFromCart() { $("body").on("click", opts.elRemoveFromCart, function(e) { if(!confirm("Удалить товар из корзины?")) return false; var $this = $(this), id = +$this.attr(opts.attrId), $cartElem = findCartElemById(id); remove(id); $cartElem.remove(); renderMenuCart(); renderTotalCartSumma(); }); } // Оформляем заказ function _onClickOrder() { $("body").on("click", opts.elOrder, function(e) { // Предоставлю написать код для оформления заказа и отправки данных на сервер самим alert("Оформляем заказ:-)"); }); }

На заметку. Код, касающийся рендеринга и навешивания событий, можно было изрядно уменьшить, применив такой нехитрый трюк. Объединяем код отрисовки корзины, количества и суммы в одну функцию render и вызываем ее после любых манипуляций с корзиной. То есть для любого события схема такая: вызвали нужный метод обработки данных - отрендерили ВСЕ. Тогда мы избавляемся от проверок вроде "а не удалился ли товар из корзины после уменьшения его количества" и вызова нескольких функций рендера вместо одной. Для небольших проектов это оправдано, но когда Ваше приложение будет содержать кучу виджетов, сложную верстку и данные будут поступать не только по клику пользователей, а еще и в режиме онлайн от разных источников, перерисовка всего содержимого страницы негативно скажется на производительности браузера. Поэтому даже в нашем простом случае я выбрал чуть усложненную, но более правильную схему.

Собираем модуль корзины в одно целое

Основной код уже написан, нам осталось только написать функцию инициализации корзины и привязки обработчиков событий. Пойдем от обратного, обработчики:

// Навешивам события function _bindHandlers() { _onClickAddBtn(); _onClickChangeCountInCart(); _onClickRemoveFromCart(); _onClickOrder(); } Думаю, здесь без особых пояснений, собираем в кучу написанные ранее функции. Иницилизация: // Инициализация модуля function init(options) { _initOptions(options); updateData(); if (opts.renderCartOnInit) { renderCart(); } if (opts.renderMenuCartOnInit) { renderMenuCart(); } _bindHandlers(); } Почему мы ввели отдельные настройки renderCartOnInit и opts.renderMenuCartOnInit? Просто потому, что на странице каталога нам нужно инициализировать корзину (мы выводим количество добавленных товаров в меню), но не нужно ее рендерить. Чтобы не усложнять логику лишними проверками, мы разделили эти опции.

Полный код корзины

Код всей корзины мы уже рассмотрели в статье, но чтобы уложить это еще раз в голове, вот на файл cart.js - модуль целиком.

Главный модуль приложения

Вероятно, даже самый усидчивый читатель порядком устал от чтения букв, поэтому спешу завершить мой трактат.
Файл main.js - главный модуль, запуск приложения, царь-модуль.

"use strict"; // Модуль приложения var app = (function($) { var $body = $("body"), page = $body.data("page"), options = { elAddToCart: ".js-add-to-cart", attrId: "data-id", attrName: "data-name", attrPrice: "data-price", attrDelta: "data-delta", elCart: "#cart", elTotalCartCount: "#total-cart-count", elTotalCartSumma: "#total-cart-summa", elCartItem: ".js-cart-item", elCartCount: ".js-count", elCartSumma: ".js-summa", elChangeCount: ".js-change-count", elRemoveFromCart: ".js-remove-from-cart", elOrder: "#order" }, optionsCatalog = _.extend({ renderCartOnInit: false, renderMenuCartOnInit: true }, options), optionsCart = _.extend({ renderCartOnInit: true, renderMenuCartOnInit: true }, options); function init() { if (page === "catalog") { catalog.init(); cart.init(optionsCatalog); } if (page === "cart") { cart.init(optionsCart); } } return { init: init } })(jQuery); jQuery(document).ready(app.init); Идея такова: объявляем главный модуль, настройки приложения (в нашем случае дублируют опции по умолчанию), определяем текущую страницу и настройки модуля cart для текущей страницы и, наконец, инициализируем нужные модули. Приводит все это добро в действие волшебная строчка jQuery(document).ready(app.init);

Подводим итоги.

Итак, мы написали небольшое приложение простого интернет-магазина с каталогом и корзиной.

UPDATED: В связи с большой популярностью этой статьи и интересу к теме интернет-магазинов в целом запилена и опубликована статья-продолжение Реализация оформления заказа в интернет-магазине на клиенте и сервере . В ней рассмотрен полный цикл по сбору данных о клиенте, размещении формы заказа, отправки ajax-запроса на сервер, создание таблиц в базе данных и добавление этих самых данных, а также отправка писем с заказом. Как обычно, все с примерами. Исходники обновлены. Отправка заказа интегрирована с каталогом и корзиной, рассмотренными в этой статье. Это выглядит как цельное приложение, готовое к работе.
Еще одно обновление: готова статья про добавление способа доставки в интернет-магазин. Читайте здесь

Хотя главной целью была демонстрация модульного подхода при разработке на javascript и отделении логики от представления, все же модуль корзины получился вполне себе самодостаточным и независимым. При желании мы можем включать его в другие проекты. У нас есть только 2 зависимости модуля: jquery и underscore. Хотя полагаю, что люди, знакомые с обеими библиотеками, добавляют их практически в любой свой проект.

Многие моменты в нашем приложении достаточно спорны. Нет жесткого разделения логики и представления, эти функции объединены в один модуль. Также шаблоны underscore вшиты прямо в код страницы, что тоже не самая хорошая практика, нужно выносить их в отдельные файлы. Я намеренно не стал слишком усложнять структуру. В статье я рассмотрел пример создания кода с одной стороны достаточно модульного, чтобы его можно было удобно протестировать, поддерживать в дальнейшем или извлечь какие-то идеи для своих будущих приложений, но с другой стороны не настолько сложного, чтобы в нем нужно было слишком долго разбираться. В конце концов для серьезной javascript-разработки создаются библиотеки и фреймворки, и рано или поздно мы все приходим к пониманию, что их нужно знать и изучать. Backbone, Angular, Ember, React, существует их очень много и постоянно появляются новые. И чем больше мы будем изучать и узнавать различные подходы, тем шире будет наш кругозор и больше возможностей выбора.

Я пытаюсь создать простую корзину покупок PHP с ценами, продуктами, регистрацией и областью оформления. Я искал Google для учебных пособий, но все они включают SQL, который еще не входит в мой набор навыков. У кого-нибудь есть примеры или другие ресурсы учебника, которые вы могли бы назвать новичком PHP?

Снова просто пытается создать простую корзину покупок PHP (без SQL) с использованием массивов для продуктов, функций для различных задач программы, проверки формы, файлов cookie/сеансов для непрерывности корзины, файлов шаблонов и писем с подтверждением/получением.

Заранее благодарим за помощь!

3 ответа

Вместо того, чтобы критиковать, почему бы просто не помочь? Лицемерный, но что угодно. Пожалуйста, имейте в виду, без базы данных SQL вы не можете "зарегистрироваться", но вы можете иметь предварительные имена пользователей и пароли.

Итак, давайте создадим вашу базу псевдо sql с php.

Нам нужна таблица для хранения имен пользователей и паролей для вашей учетной записи.

Теперь нам нужна таблица для хранения продуктов

Таким образом, у нас есть наши продукты "таблица" и наша учетная запись "таблица". Теперь вот более сложная часть, которая создает систему, которая принимает всю эту информацию, отображает ее, позволяет войти и выйти из системы, а также отслеживает элементы, которые у вас есть в корзине.