所有分类
  • 所有分类
  • 游戏源码
  • 网站源码
  • 单机游戏
  • 游戏素材
  • 搭建教程
  • 精品工具

手把手教你用JS编写购物车界面:新手一看就会的完整实战教程

手把手教你用JS编写购物车界面:新手一看就会的完整实战教程 一

文章目录CloseOpen

我们从0到1,手把手教你实现一个完整的购物车:先搭好HTML结构和基础样式,再一步步写JS逻辑——商品怎么动态渲染?数量增减怎么联动数据?总价怎么实时更新?选中商品怎么统计?每一步都有详细代码+通俗讲解,没有复杂黑科技,新手跟着敲就能懂。更重要的是,这个购物车不是“玩具”——它包含了实际项目里常用的核心功能,做完就能直接用到你的小项目里。

不管你是刚学JS的新手,还是想补全实战能力的学习者,跟着这篇教程走,保证你能亲手做出一个能落地的购物车,把“纸上的JS知识”变成“能跑的交互功能”,成就感直接拉满!

你有没有过这种情况?学JS的时候跟着教程做购物车,要么代码copy过来能跑但根本不懂逻辑,要么做完只有个空架子,连数量增减都不联动总价?我去年帮朋友的社区团购小站做购物车时,就遇到过这问题——他找了个教程跟着做,结果用户点“+”号,数量涨了但总价没变,反馈全是骂人的。后来我帮他重构了一遍,把“数据驱动界面”的逻辑理清楚,才解决了问题。今天我就把当时的步骤拆解给你,不用懂复杂的框架,纯JS就能做,做完直接能用在小项目里。

先理清楚:购物车界面到底要实现哪些核心功能?

很多新手刚学的时候,总想着“做个好看的界面”,但实际项目里,功能的合理性比样式重要10倍。我帮朋友做的时候,一开始没明确核心功能,导致做了很多无用功——比如先加了商品分类筛选,结果用户根本用不上,反而把购物车搞得很复杂。后来我查了几个小电商站的购物车,又问了做前端的朋友,才 出购物车的5个必做核心功能

  • 商品列表展示:得清晰显示商品图片、名称、单价——别嫌麻烦,我之前漏了商品图片,朋友说用户看不到图就没购买欲;
  • 数量增减:支持“+/-”按钮和输入框修改数量,且数量不能小于1——之前帮另一个做美妆小店的朋友调bug,就是因为没加“最小1”的限制,用户把数量改成0,导致总价负数;
  • 总价实时计算:选了的商品、改了数量后,总价要立刻变——这是用户最在意的,我朋友之前就是漏了这个,被用户骂“诈骗”;
  • 选中状态联动:勾选商品后,总价要包含它;取消勾选,总价要去掉——别像我之前那样,把选中和总价分开,结果逻辑混乱;
  • 删除商品:用户不想买了能删掉——这个功能看似简单,但要注意删除后要重新渲染列表和计算总价。
  • 为了让你更清楚“功能和数据的对应关系”,我做了张表格——你看,每个功能都对应着具体的数据字段,后面写代码时直接“对号入座”就行:

    核心功能 对应数据字段 用户操作场景
    商品展示 id/name/price/imgUrl 用户打开购物车看商品
    数量增减 quantity 用户想多买/少买几件
    总价计算 price/quantity/isChecked 用户想知道要付多少钱
    选中状态 isChecked 用户想选/不选某件商品

    记住:所有操作都要先修改数据,再渲染界面——我之前犯过“直接改DOM”的错,比如用户点“+”号,我直接把输入框的value加1,但数据数组里的quantity没改,结果后面计算总价时,用的还是原来的数量,导致“界面和数据不一致”的bug。后来改成“先改数据,再重新渲染”,就再也没出现过这种问题。

    手把手写代码:从0到1实现能落地的购物车

    现在开始写代码——我尽量把每一步的逻辑讲透,你跟着敲就行,有疑问的地方可以标出来,后面留言问我。

    第一步:搭HTML结构——越简洁越好

    先写基础的HTML,核心是“购物车容器”和“商品项模板”。我一般会用语义化标签,比如用

      放商品列表,

    • 放单个商品,这样搜索引擎和屏幕阅读器都能识别:

      我的购物车

        <!-
      • 商品列表容器 >
      • 然后,每个商品项的HTML我会用JS动态生成(后面讲),但你要先想清楚商品项里要包含哪些元素:

      • 勾选框(选商品用);
      • 商品图片(可视化很重要);
      • 商品名称和单价(用户要知道买的是什么);
      • 数量增减按钮(改数量用);
      • 删除按钮(删商品用)。
      • 我给每个元素加了明确的类名,比如.cart-item代表商品项,.item-check代表勾选框——别用.box1.btn2这种命名,不然过一周你自己都忘了哪个是哪个。

        第二步:写CSS基础样式——先保证功能能用

        样式不用太复杂,先做“能用的布局”,后面再调美观。我用Flex布局做商品项的排列,这样能快速实现“图片左、信息中、数量右”的结构:

        .cart-container {
        

        width: 800px;

        margin: 50px auto;

        border: 1px solid #eee;

        padding: 20px;

        }

        .cart-title {

        font-size: 18px;

        margin-bottom: 20px;

        }

        .cart-item {

        display: flex;

        align-items: center;

        padding: 15px 0;

        border-bottom: 1px solid #eee;

        }

        .item-check {

        margin-right: 15px;

        }

        .item-img {

        width: 80px;

        height: 80px;

        object-fit: cover;

        margin-right: 15px;

        }

        .item-info {

        flex: 1; / 占剩余空间 /

        }

        .item-name {

        font-size: 16px;

        margin-bottom: 10px;

        }

        .item-price {

        font-size: 14px;

        color: #ff5722;

        }

        .item-quantity {

        display: flex;

        align-items: center;

        margin-right: 30px;

        }

        .quantity-btn {

        width: 30px;

        height: 30px;

        border: 1px solid #ddd;

        background: #fff;

        cursor: pointer;

        }

        .quantity-input {

        width: 50px;

        height: 30px;

        text-align: center;

        border: 1px solid #ddd;

        margin: 0 5px;

        }

        .item-delete {

        background: #ff4444;

        color: #fff;

        border: none;

        padding: 5px 10px;

        cursor: pointer;

        }

        .cart-footer {

        display: flex;

        justify-content: space-between;

        align-items: center;

        margin-top: 20px;

        padding-top: 20px;

        border-top: 1px solid #eee;

        }

        .total-price {

        font-size: 18px;

        color: #ff5722;

        font-weight: bold;

        }

        .checkout-btn {

        background: #ff5722;

        color: #fff;

        border: none;

        padding: 10px 20px;

        cursor: pointer;

        }

        注意:数量输入框要加min="1"的限制——我之前没加,用户把数量改成0,导致总价变成负数,朋友差点被投诉。

        第三步:写JS逻辑——分模块,别堆在一起

        JS是购物车的“大脑”,我会把逻辑分成4个模块:数据初始化、渲染商品、绑定事件、计算总价。这样后期维护的时候,找问题也方便。

      • 数据初始化——用数组模拟商品数据
      • 真实项目里,购物车数据是从后端接口拿的,但新手可以用数组+对象模拟:

        // 购物车数据源(模拟后端返回的数据)
        

        const cartData = [

        {

        id: 1,

        name: "国产红富士苹果(5斤装)",

        price: 19.9,

        quantity: 1,

        isChecked: false,

        imgUrl: "https://via.placeholder.com/80" // 用占位图代替真实图片

        },

        {

        id: 2,

        name: "云南阳光玫瑰葡萄(2斤装)",

        price: 39.8,

        quantity: 1,

        isChecked: false,

        imgUrl: "https://via.placeholder.com/80"

        },

        {

        id: 3,

        name: "新疆库尔勒香梨(3斤装)",

        price: 25.8,

        quantity: 1,

        isChecked: false,

        imgUrl: "https://via.placeholder.com/80"

        }

        ];

        每个商品对象里的字段,对应之前表格里的“核心功能”——比如id用来唯一标识商品(删商品时要用),isChecked表示是否选中(计算总价时要用)。

      • 渲染商品列表——把数据变成界面
      • 写一个renderCart函数,用来把cartData里的数据变成HTML,插入到

          里。我用模板字符串(反引号)来拼HTML,比之前用字符串相加方便多了:

          function renderCart() {
          

          const cartList = document.querySelector('.cart-list');

          // 用map遍历数据,生成每个商品项的HTML

          const html = cartData.map(item =>

        • <!-

        • 勾选框 >
        • <!-

        • 商品图片 >
        • 手把手教你用JS编写购物车界面:新手一看就会的完整实战教程 二

          <!-

        • 商品信息 >
        • ${item.name}

          ¥${item.price.toFixed(2)}

          <!-
        • 保留两位小数 >
        • <!-

        • 数量控制 >
        • <!-

        • 删除按钮 >
        • ).join(''); // 把数组变成字符串

          cartList.innerHTML = html; // 插入到商品列表容器

          }

          这里有个小技巧:给每个商品项加data-id="${item.id}"——后面点击删除或改数量时,能通过这个data-id找到对应的商品数据。比如用户点“删除”按钮,我可以用e.target.closest('.cart-item').dataset.id拿到商品id,再从cartData里找到对应的商品删掉。

        • 绑定事件——让购物车“动起来”
        • 事件绑定是购物车的“交互核心”,我会写几个函数,分别处理数量增减、勾选、删除的事件:

          (1)数量增减事件——修改数量并重新渲染

          给“+/-”按钮绑定点击事件,逻辑是:

        • 找到对应的商品数据;
        • 修改quantity(减的时候不能小于1);
        • 重新渲染购物车(更新界面);
        • 重新计算总价(更新合计)。
        • function bindQuantityEvents() {
          

          // 找所有“减”按钮

          const minusBtns = document.querySelectorAll('.minus');

          minusBtns.forEach(btn => {

          btn.addEventListener('click', e => {

          // 找到当前商品项的id

          const itemId = e.target.closest('.cart-item').dataset.id;

          // 找到对应的商品数据

          const item = cartData.find(i => i.id === parseInt(itemId));

          // 数量不能小于1

          if (item.quantity > 1) {

          item.quantity;

          renderCart(); // 重新渲染购物车

          calculateTotal(); // 重新计算总价

          bindQuantityEvents(); // 重新绑定事件(因为渲染后按钮被替换了)

          bindDeleteEvents(); // 同理,删除按钮也要重新绑定

          }

          });

          });

          // “加”按钮的逻辑,和减类似

          const plusBtns = document.querySelectorAll('.plus');

          plusBtns.forEach(btn => {

          btn.addEventListener('click', e => {

          const itemId = e.target.closest('.cart-item').dataset.id;

          const item = cartData.find(i => i.id === parseInt(itemId));

          item.quantity++;

          renderCart();

          calculateTotal();

          bindQuantityEvents();

          bindDeleteEvents();

          });

          });

          }

          注意:重新渲染后,原来的按钮被替换了,所以要重新绑定事件——新手容易漏这一步,导致“点击第二次没反应”的bug。我当初帮朋友调的时候,就因为漏了bindQuantityEvents(),结果用户点“+”号只能加一次,第二次就没反应了。

          (2)勾选事件——联动选中状态和总价

          给勾选框绑定change事件,修改isChecked字段,然后重新计算总价:

          function bindCheckEvents() {
          

          const checkboxes = document.querySelectorAll('.item-check');

          checkboxes.forEach(checkbox => {

          checkbox.addEventListener('change', e => {

          const itemId = e.target.closest('.cart-item').dataset.id;

          const item = cartData.find(i => i.id === parseInt(itemId));

          item.isChecked = e.target.checked; // 修改选中状态

          calculateTotal(); // 重新计算总价

          });

          });

          }

          (3)删除事件——删掉商品并重新渲染

          给删除按钮绑定点击事件,逻辑是:

        • 找到商品id;
        • cartData里过滤掉对应的商品;
        • 重新渲染购物车;
        • 重新计算总价。
        • function bindDeleteEvents() {
          

          const deleteBtns = document.querySelectorAll('.item-delete');

          deleteBtns.forEach(btn => {

          btn.addEventListener('click', e => {

          const itemId = e.target.closest('.cart-item').dataset.id;

          // 过滤掉要删除的商品(保留id不等于当前id的商品)

          cartData = cartData.filter(item => item.id !== parseInt(itemId));

          renderCart(); // 重新渲染

          calculateTotal(); // 重新计算总价

          bindQuantityEvents(); // 重新绑定数量事件

          });

          });

          }


        • 本文常见问题(FAQ)

          购物车界面必须实现的核心功能有哪些?

          购物车的核心功能主要有5个:一是商品列表展示,得清晰显示商品图片、名称、单价;二是数量增减,支持“+/-”按钮和输入框修改,且数量不能小于1;三是总价实时计算,选商品或改数量后总价要立刻更新;四是选中状态联动,勾选或取消勾选商品时,总价要对应变化;五是删除商品,用户能删掉不想买的商品。这些功能是实际项目里用户最在意的,比如之前帮朋友做社区团购站,漏了总价实时计算,被用户骂“诈骗”,补全后才解决问题。

          什么是“数据驱动界面”?为什么做购物车要重视这个逻辑?

          “数据驱动界面”就是做操作时先修改背后的数据,再根据数据重新渲染界面。比如用户点“+”号,不是直接改输入框的value,而是先找到cartData里对应商品的quantity并加1,再重新调用renderCart函数更新界面。之前帮朋友做的时候,一开始直接改DOM,结果数量涨了但总价没变——因为数据没同步,后来换成“数据驱动”,界面和数据就一致了,再也没出现过这种bug。

          写购物车的JS逻辑时,为什么要分模块?

          分模块写JS主要是方便维护和找bug。比如把逻辑分成数据初始化、渲染商品、绑定事件、计算总价这几个模块,后期如果数量增减的逻辑出问题,直接找bindQuantityEvents函数就行,不用在一堆代码里翻。之前我犯过堆代码的错,改数量的bug花了2小时,分模块后只花10分钟就找到了问题。

          跟着这个教程做的购物车,能直接用到实际小项目里吗?

          完全可以!这个购物车包含了社区团购、美妆小店、水果电商等小项目常用的核心功能,比如数量限制、总价实时联动、选中状态管理、删除商品。只要把教程里的模拟数据(cartData)换成后端接口返回的数据,就能直接用在项目里——我去年帮朋友的社区团购站就用了这个逻辑,用户反馈比之前的购物车好用多了。

          搭购物车的HTML结构时,为什么要越简洁越好?

          简洁的HTML结构更容易维护和修改。比如用语义化标签(ul放商品列表、li放单个商品),加明确的类名(.cart-item代表商品项、.item-check代表勾选框),后期想改商品图片的大小,直接找.item-img类就行;如果结构复杂,用了很多div嵌套,改起来得找半天元素。之前我用复杂结构搭购物车,改商品名称的位置花了半小时,现在用简洁结构10分钟就搞定了。

          原文链接:https://www.mayiym.com/51119.html,转载请注明出处。
        • 0
          显示验证码
          没有账号?注册  忘记密码?

          社交账号快速登录

          微信扫一扫关注
          如已关注,请回复“登录”二字获取验证码