我刚刚使用 HTML、CSS 和 vanilla JavaScript 创建了一个前端购物车 Web 应用程序。因为我喜欢在当地的杂货店购买蔬菜,所以我的想法是基于一家名为芬利农场商店的农场商店的想法。
要点击该项目,实时链接是:https://gabrielrowan.github.io/Finleys-Farm-Shop-FE/
使用此应用程序,您可以:
?将商店商品添加到购物车
?更改商店商品的数量
?在手推车模式上查看购物车中的所有商品
?查看购物车中所有商品的总价
?查看购物车中的商品数量
?即使您刷新页面或关闭选项卡然后重新打开它,仍将所有商品保留在购物车中
到目前为止,我在工作中主要从事后端应用程序的工作。不过,今年夏天,我开始从事一个全栈项目,包括设计和实现前端。我真的很喜欢它,它让我想更多地发展我的前端技能。
我想挑战自己在不使用 CSS 库的情况下完成这个项目,不是因为我认为使用它们不好,而是因为像 Bootstrap 这样的东西通常是我前端的首选。
我之前从未在 JavaScript 中使用过浏览器本地存储,因此我决定创建一个项目将是我实际了解它的最佳方式。
当我第一次开始这个项目时,我心中有几个目标。这些是:
?响应能力 - 我希望 UI 能够适应移动设备、ipad 和桌面视图
?不使用 CSS 库创建购物车模式
?熟悉在 JavaScript 中使用本地存储
创建前端是我这个项目计划的第 1 部分。第二部分是使用 Django 将其转换为全栈应用程序,以便商店商品来自数据库,而不是硬编码在 HTML 中。
为了使应用程序适应不同的屏幕尺寸,我使用了 Kevin Powell 视频中的响应式网格版本。
.shop-items { display: grid; gap: 0.6rem; grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); }
神奇之处在于 grid-template-columns 值。它的本质意思是:
在此父容器中容纳尽可能多的列,最小尺寸为 12rem,最大尺寸为可用空间的 1 分之一。
使用此网格,当从更宽的桌面视图到更窄的移动视图时,列数(以商店商品卡的数量表示)可以动态地从 4 减少到 1,而无需编写额外的媒体查询。
对于横幅标题“Finley's Farm Shop”,我使用了clamp(),以便字体大小能够自动缩放。如果不这样做,我发现适用于桌面的字体大小对于移动设备来说太大了。
.shop-items { display: grid; gap: 0.6rem; grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); }
这意味着字体大小的目标是 5vw(视口宽度 - 又称为总可见屏幕宽度的 5%)。
字体大小的最小值为 3.8rem,因此如果 5vw 等于小于 3.8rem,则字体大小将为 3.8rem。
字体大小的最大值可以设置为 5.6rem,因此如果 5vw 相当于大于 5.6rem,则字体大小将为 5.6rem。
有多种方法可以精确计算最小和最大字体大小之间的渐变,并使用它来选择您喜欢的中间值,但我使用检查器来观察它?
这里有一篇关于计算精确渐变的 CSS 技巧文章。
对于手推车,我想要一个会从桌面屏幕右侧出现的模式:
在移动视图上,我决定它应该占据全屏尺寸:
当购物车项目被添加到购物车时,我的大部分时间都花在了 CSS 上。我使用网格模板区域,以便购物车项目的不同部分(项目标题,即“Apple”、价格、项目数量和图像)占用我为它们计划的分配空间。
.banner-title { font-size: clamp(3.8rem, 5vw, 5.6rem); }
对于模态 JavaScript,我的目标是:
为了实现这一点,我向两个图标添加了事件监听器,调用了函数toggleModal。如果尚未将其添加到模态元素中,则会添加一个名为 .active 的类;如果已存在,则将其删除。
在CSS中,我将模态框设置为默认隐藏,并将.active类设置为显示它。
.shop-items { display: grid; gap: 0.6rem; grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); }
.banner-title { font-size: clamp(3.8rem, 5vw, 5.6rem); }
这意味着关闭图标和购物车图标上的事件侦听器可以重用相同的功能,因为如果尚未显示,它将显示模态,如果已经打开,它将隐藏它。
对于本地存储,我发现 Web Dev Simplified 的视频“JavaScript Cookies vs. Local Storage vs. Session Storage”特别有帮助。它讨论了这三种存储数据方式之间的差异、如何在开发工具的“应用程序”选项卡中查看数据以及如何为每种数据存储类型添加和删除项目。
这是我将 2 件商品添加到购物车后项目的“应用程序”选项卡的样子:
我决定将与修改 DOM(添加元素、删除元素、编辑元素)相关的函数与与本地存储相关的函数分开。例如,我有一个函数removeCartItemFromLocalStorage,它的功能与上面所说的一样,并且与removeCartItemFromModalDOM不同,它从模态中删除商店项目html。
.cart-item { display: grid; grid-template-areas: "image description description" "image price quantity"; grid-template-columns: min-content 1fr 1fr; grid-template-rows: 2.5rem 3.5rem; }
当商店商品从购物车中移除时,需要调用这两个函数,将它们作为单独的函数可以帮助我检查是否已完成该过程的两个所需部分。如果不从 DOM 中删除 html,网页将不会直观地反映出该商品已从购物车中删除。如果不从本地存储中删除该项目,刷新页面或关闭选项卡时更改将无法保留。
当我在研究 JavaScript 中的本地存储功能时,我遇到了一个让我非常困惑的问题。到目前为止我完成的步骤是:
我点击了一下,看起来也很棒! ...直到我刷新页面。然后,价格设置为与之前相同的总价,但 DOM 已完全恢复为初始页面加载时的样子。从视觉上看,购物车中似乎没有商品(显示的是添加按钮,而不是数量输入控件),但总数超过 0 英镑。
这真的让我很困惑,我花了一段时间才弄清楚。最终,我明白了。是的,我正在将这些项目添加到本地存储中。但是,当重新加载页面并触发 DOMContentLoaded 事件侦听器时,我没有根据本地存储中的内容渲染 DOM。事实上,现阶段我根本没有检查本地存储中的内容。
意识到这一点后,我创建了一个名为 DOMContentLoaded 的函数,该函数循环遍历本地存储中的产品数组中的所有产品,找到每个产品的 id,然后更新相关产品的 html 元素以显示已添加的产品到购物车。
该函数的简化版本是:
const loadCartState = () =>; { const cart = JSON.parse(localStorage.getItem("cart")); 如果(!购物车) { 购物车=[]; localStorage.setItem("购物车", JSON.stringify(cart)); } cart.forEach(产品 => { const shopItem = document.querySelector(`.shop-item[data- > <h2> 部署 </h2> <p>我使用 Github Pages 部署了这个应用程序。我之前没有使用它进行部署,但发现该过程非常简单。我遇到的唯一问题是起初没有显示任何图像。我意识到这是因为区分大小写:我的图像文件夹名为 Img 但图像路径是 html 中的 img/ 。修复此问题并清除缓存后,网站按预期显示。 </p> <h2> 结论 </h2> <p>我从这个项目中学到了很多东西,特别是关于 CSS 网格和通过 JavaScript 使用本地存储。我很想添加更多页面并将其变成一个完整的前端电子商务应用程序,但我决定暂时保留它的 MVP,以便我可以专注于下一阶段将其变成 Django 应用程序并挂钩它到数据库?</p>
以上是我的农场商店购物车项目的详细内容。更多信息请关注PHP中文网其他相关文章!