最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用原生JS實(shí)現(xiàn)移動(dòng)端購(gòu)物車(chē)效果案例

 更新時(shí)間:2026年02月06日 10:13:51   作者:苦瓜大王~  
原生JavaScript作為前端開(kāi)發(fā)的基石,在構(gòu)建交互式網(wǎng)頁(yè)應(yīng)用中扮演著至關(guān)重要的角色,下面這篇文章主要介紹了使用原生JS實(shí)現(xiàn)移動(dòng)端購(gòu)物車(chē)效果案例的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下

實(shí)現(xiàn)效果

  • 顯示所有商品列表
  • 基本的加減商品、商品數(shù)量、計(jì)算價(jià)格功能
  • 頁(yè)腳有商品時(shí)顯示高亮樣式、配送費(fèi)等

素材、文件展示

代碼展示

html部分

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>外賣(mài)</title>
    <link rel="shortcut icon" href="./assets/favicon.ico" rel="external nofollow"  type="image/x-icon" />
    <link rel="stylesheet" href="./css/common.css" rel="external nofollow"  />
    <link rel="stylesheet" href="./css/container.css" rel="external nofollow"  />
    <link rel="stylesheet" href="./css/footer.css" rel="external nofollow"  />
    <link rel="stylesheet" href="./css/add-to-car.css" rel="external nofollow"  />
  </head>
  <body>
    <div class="container">
      <div class="menu">
        <div class="menu-item active"><span>推薦</span></div>
        <div class="menu-item"><span>熱銷(xiāo)</span></div>
        <div class="menu-item"><span>折扣</span></div>
        <div class="menu-item"><span>夏日冰咖必喝榜</span></div>
        <div class="menu-item"><span>進(jìn)店必喝</span></div>
        <div class="menu-item"><span>只喝美式</span></div>
        <div class="menu-item"><span>酷爽特調(diào)水果冰萃</span></div>
        <div class="menu-item"><span>經(jīng)典奶咖</span></div>
        <div class="menu-item"><span>創(chuàng)意奶咖</span></div>
        <div class="menu-item"><span>瑞納冰季</span></div>
        <div class="menu-item"><span>不喝咖啡</span></div>
        <div class="menu-item"><span>輕食甜品</span></div>
        <div class="menu-item"><span>熱賣(mài)套餐</span></div>
      </div>
      <div class="goods-list">
      </div>
    </div>
    <div class="footer">
      <div class="footer-car-container">
        <div class="footer-car">
          <i class="iconfont i-gouwuchefill"></i>
          <span class="footer-car-badge">0</span>
        </div>
        <div class="footer-car-price">
          <span class="footer-car-unit">¥</span>
          <span class="footer-car-total">0.00</span>
        </div>
        <div class="footer-car-tip">配送費(fèi)¥0</div>
      </div>
      <div class="footer-pay">
        <a href="">去結(jié)算</a>
        <span>還差¥0元起送</span>
      </div>
    </div>

    <div class="add-to-car">
      <i class="iconfont i-jiajianzujianjiahao"></i>
    </div>

    <script src="./js/data.js"></script>
    <script src="./js/index.js"></script>
  </body>
</html>

css部分

  • 由于篇幅有限,css不展示完整代碼,可根據(jù)喜好調(diào)整
  • 此處放一張,未加入index.js的展示圖

js部分

  • 僅展示index.js文件

單個(gè)商品數(shù)據(jù)

class UIGoods {
  constructor(g) {
    this.data = g
    this.choose = 0
  }
  // 獲取總價(jià)
  getTotalPrice() {
    return this.data.price * this.choose
  }
  // 是否選擇了商品
  isChoose() {
    return this.choose > 0
  }
  // 選擇的數(shù)量+1
  increase() {
    this.choose++
  }
  // 選擇的數(shù)量-1
  decrease() {
    if (this.choose === 0) {
      return
    }
    this.choose--
  }
}

整個(gè)界面的數(shù)據(jù)

class UIData {
  constructor() {
    // 所有商品
    const getTotalGoods = goods.map(function (goods) {
      return new UIGoods(goods)
    })
    this.uiGoods = getTotalGoods
    // 起送費(fèi)
    this.deliveryThreshold = 30
    // 配送費(fèi)
    this.deliveryPrice = 5
  }
  // 總價(jià)
  getTotalPrice() {
    return this.uiGoods.reduce((acc, cur) => {
      return acc + cur.getTotalPrice()
    }, 0)
  }
  // 增加某件商品的選中數(shù)量
  increase(index) {
    this.uiGoods[index].increase()
  }
  // 減少某件商品的選中數(shù)量
  decrease(index) {
    this.uiGoods[index].decrease()
  }
  // 獲取全部商品的選中數(shù)量
  getTotalGoodsNumber() {
    return this.uiGoods.reduce((acc, cur) => {
      return acc + cur.choose
    }, 0)
  }
  // 是否選擇了商品
  hasGoodsInCar() {
    return this.getTotalGoodsNumber() > 0
  }
  // 是否到達(dá)起送費(fèi)
  isCrossDeliveryThreshold() {
    return this.getTotalPrice() >= this.deliveryThreshold
  }
}

界面

class UI {
  constructor() {
    // 界面數(shù)據(jù)
    this.uiData = new UIData()
    // 獲取dom元素對(duì)象
    this.doms = {
      goodsContainer: document.querySelector('.goods-list'),
      deliveryPrice: document.querySelector('.footer-car-tip'),
      footerPay: document.querySelector('.footer-pay'),
      footerPayInnerSpan: document.querySelector('.footer-pay span'),
      totalPrice: document.querySelector('.footer-car-total'),
      car: document.querySelector('.footer-car'),
      badge: document.querySelector('.footer-car-badge')
    }

    // 計(jì)算跳躍坐標(biāo)
    let carRect = this.doms.car.getBoundingClientRect()
    let jumpTarget = {
      x: carRect.left + carRect.width / 2,
      y: carRect.top + carRect.height / 5
    }

    this.createHTML()
    this.updateFooter()
    this.listenEvent()
    this.jumpTarget = jumpTarget
  }
  // 監(jiān)聽(tīng)事件
  listenEvent() {
    this.doms.car.addEventListener('animationend', function () {
      this.classList.remove('animate')
    })
  }
  // 創(chuàng)建商品元素
  createHTML() {
    let html = ''
    for (let i = 0; i < this.uiData.uiGoods.length; i++) {
      let g = this.uiData.uiGoods[i]
      html += `
        <div class="goods-item">
          <img src="${g.data.pic}" alt="" class="goods-pic" />
          <div class="goods-info">
            <h2 class="goods-title">${g.data.title}</h2>
            <p class="goods-desc">
              ${g.data.desc}
            </p>
            <p class="goods-sell">
              <span>月售 ${g.data.sellNumber}</span>
              <span>好評(píng)率${g.data.favorRate}%</span>
            </p>
            <div class="goods-confirm">
              <p class="goods-price">
                <span class="goods-price-unit">¥</span>
                <span>${g.data.price}</span>
              </p>
              <div class="goods-btns">
                <i index=${i} class="iconfont i-jianhao"></i>
                <span>0</span>
                <i index=${i} class="iconfont i-jiajianzujianjiahao"></i>
              </div>
            </div>
          </div>
        </div>
      `
    }
    this.doms.goodsContainer.innerHTML = html
  }
  // 增加商品
  increase(index) {
    this.uiData.increase(index)
    this.updateGoodsItem(index)
    this.updateFooter()
    this.jump(index)
  }
  // 減少商品
  decrease(index) {
    this.uiData.decrease(index)
    this.updateGoodsItem(index)
    this.updateFooter()
  }
  // 更新商品的顯示狀態(tài)
  updateGoodsItem(index) {
    let goodsDom = this.doms.goodsContainer.children[index]
    // 移除添加類(lèi)
    if (this.uiData.uiGoods[index].isChoose()) {
      goodsDom.classList.add('active')
    } else {
      goodsDom.classList.remove('active')
    }
    // 數(shù)量顯示
    let span = goodsDom.querySelector('.goods-btns span')
    span.textContent = this.uiData.uiGoods[index].choose
  }
  // 更新頁(yè)腳
  updateFooter() {
    // 得到總價(jià)數(shù)據(jù)
    let total = this.uiData.getTotalPrice()
    // 設(shè)置配送費(fèi)
    this.doms.deliveryPrice.textContent = `配送費(fèi)${this.uiData.deliveryPrice}`
    // 移除添加類(lèi)
    if (this.uiData.isCrossDeliveryThreshold()) {
      this.doms.footerPay.classList.add('active')
    } else {
      this.doms.footerPay.classList.remove('active')
      // 起送差價(jià)
      let dis = this.uiData.deliveryThreshold - total
      this.doms.footerPayInnerSpan.textContent = `還差¥${dis}元起送`
    }
    // 設(shè)置總價(jià)
    this.doms.totalPrice.textContent = total.toFixed(2)
    // 設(shè)置購(gòu)物車(chē)樣式狀態(tài)
    if (this.uiData.hasGoodsInCar()) {
      this.doms.car.classList.add('active')
    } else {
      this.doms.car.classList.remove('active')
    }
    // 設(shè)置購(gòu)物車(chē)數(shù)量
    this.doms.badge.textContent = this.uiData.getTotalGoodsNumber()
  }
  // 購(gòu)物車(chē)動(dòng)畫(huà)
  carAnimate() {
    this.doms.car.classList.add('animate')
  }
  // 跳躍動(dòng)畫(huà)
  jump(index) {
    // 獲取坐標(biāo)
    let btnAdd = this.doms.goodsContainer.children[index].querySelector('.i-jiajianzujianjiahao')
    let rect = btnAdd.getBoundingClientRect()
    let start = {
      x: rect.left,
      y: rect.top
    }
    // 創(chuàng)建跳躍元素
    let div = document.createElement('div')
    div.className = 'add-to-car'
    let i = document.createElement('i')
    i.className = 'iconfont i-jiajianzujianjiahao'
    div.appendChild(i)
    document.body.appendChild(div)
    // 設(shè)置初始位置
    div.style.transform = `translateX(${start.x}px)`
    i.style.transform = `translateY(${start.y}px)`
    // 渲染動(dòng)畫(huà)效果(觸發(fā)reflow即可)
    div.clientWidth
    // 設(shè)置結(jié)束位置
    div.style.transform = `translateX(${this.jumpTarget.x}px)`
    i.style.transform = `translateY(${this.jumpTarget.y}px)`

    div.addEventListener('transitionend',
      () => {
        div.remove()
        this.carAnimate()
      },
      {
        once: true
      }
    )
  }
}
const ui = new UI()

事件

ui.doms.goodsContainer.addEventListener('click', function(e){
  if (e.target.classList.contains('i-jiajianzujianjiahao')){
    let index = +e.target.getAttribute('index')
    ui.increase(index)
  } else if (e.target.classList.contains('i-jianhao')) {
    let index = +e.target.getAttribute('index')
    ui.decrease(index)
  }
})

總結(jié) 

到此這篇關(guān)于使用原生JS實(shí)現(xiàn)移動(dòng)端購(gòu)物車(chē)效果案例的文章就介紹到這了,更多相關(guān)JS移動(dòng)端購(gòu)物車(chē)效果內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

汉寿县| 汶川县| 昭通市| 广平县| 亚东县| 凌海市| 石首市| 江油市| 合阳县| 阳泉市| 江源县| 金山区| 天长市| 邓州市| 桑植县| 文昌市| 蓝田县| 台江县| 军事| 房山区| 哈尔滨市| 临湘市| 上林县| 松滋市| 新巴尔虎右旗| 枣庄市| 高安市| 广丰县| 静海县| 城口县| 祁门县| 比如县| 灵宝市| 红桥区| 德安县| 松江区| 大新县| 元朗区| 永福县| 竹北市| 九台市|