react如何实现美团加入购物车美团效果

import { useNavigate } from "react-router-dom"

import React from 'react'

import { SideBar, Image, List, Popup, Badge } from 'antd-mobile'

import { useState } from 'react'

import "./Goods.css"

export default function Goods() {

  const navigate = useNavigate()

  const [activeKey, setActiveKey] = useState('key1')

  const [cartList, setCartList] = useState([])

  const [visible1, setVisible1] = useState(false)

  const tabs = [

    {

      key: 'key1',

      title: '手工水饺',

    },

    {

      key: 'key2',

      title: '小咸菜',

      badge: '5',

    },

    {

      key: 'key3',

      title: '汤汤水水',

      badge: '99+',

    },

  ]

  const [users, setUsers] = useState([

    {

      id: 1,

      avatar:

        'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F1194c0a2-6286-45ae-9e22-69d8190083f6%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1683513502&t=261e904d3e43fdfef8cb640c3897da46',

      name: '韭菜鸡蛋水饺',

      description: '好吃不贵  月售44',

      price: 18,

      num: 0,

      state: false,

      isChecked: false,

    },

    {

      id: 2,

      avatar:

        'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F1194c0a2-6286-45ae-9e22-69d8190083f6%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1683513502&t=261e904d3e43fdfef8cb640c3897da46',

      name: '猪肉韭菜水饺',

      description: '好吃不贵  月售44',

      price: 20,

      num: 0,

      state: false,

      isChecked: false,

    },

    {

      id: 3,

      avatar:

        'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F1194c0a2-6286-45ae-9e22-69d8190083f6%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1683513502&t=261e904d3e43fdfef8cb640c3897da46',

      name: '猪肉大葱水饺',

      description: '好吃不贵  月售44',

      price: 21,

      num: 0,

      state: false,

      isChecked: false,

    },

    {

      id: 4,

      avatar:

        'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F1194c0a2-6286-45ae-9e22-69d8190083f6%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1683513502&t=261e904d3e43fdfef8cb640c3897da46',

      name: '三鲜水饺',

      description: '好吃不贵  月售44',

      price: 30,

      num: 0,

      state: false,

      isChecked: false,

    },

    {

      id: 5,

      avatar:

        'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F1194c0a2-6286-45ae-9e22-69d8190083f6%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1683513502&t=261e904d3e43fdfef8cb640c3897da46',

      name: '腌黄瓜',

      description: '好吃不贵  月售36',

      price: 10,

      num: 0,

      state: false,

      isChecked: false,

    },

    {

      id: 6,

      avatar:

        'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F1194c0a2-6286-45ae-9e22-69d8190083f6%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1683513502&t=261e904d3e43fdfef8cb640c3897da46',

      name: '腌芹菜',

      description: '好吃不贵  月售18',

      price: 20,

      num: 0,

      state: false,

      isChecked: false,

    },

    {

      id: 7,

      avatar:

        'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F1194c0a2-6286-45ae-9e22-69d8190083f6%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1683513502&t=261e904d3e43fdfef8cb640c3897da46',

      name: '鸡蛋汤',

      description: '好吃不贵  月售106',

      price: 3,

      num: 0,

      state: false,

      isChecked: false,

    },

    {

      id: 8,

      avatar:

        'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F1194c0a2-6286-45ae-9e22-69d8190083f6%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1683513502&t=261e904d3e43fdfef8cb640c3897da46',

      name: '丸子汤',

      description: '好吃不贵  月售56',

      price: 5,

      num: 0,

      state: false,

      isChecked: false,

    }

  ])

  const handleNum = (obj, str) => {

    if (str === "jia") {

      obj.num++

      obj.state = true

      let idx = users.findIndex(item => { return item.id === obj.id })

      users[idx] = obj

      setUsers([...users])

      let idx2 = cartList.findIndex(item => { return item.id === obj.id })

      if (idx2 !== -1) {

        cartList[idx2] = obj

        setCartList([...cartList])

      }

      if (idx2 === -1) {

        cartList.push(obj)

        setCartList([...cartList])

      }

    }

    if (str === "jian") {

      if (obj.num < 2) {

        if (obj.num === 1) {

          obj.num--

        }

        obj.state = false

        let idx = users.findIndex(item => { return item.id === obj.id })

        users[idx] = obj

        setUsers([...users])

        let idx2 = cartList.findIndex(item => { return item.id === obj.id })

        cartList.splice(idx2, 1)

        setCartList([...cartList])

        return false

      }

      obj.num--

      let idx = users.findIndex(item => { return item.id === obj.id })

      users[idx] = obj

      setUsers([...users])

      let idx2 = cartList.findIndex(item => { return item.id === obj.id })

      cartList[idx2] = obj

      setCartList([...cartList])

    }

  }

  const handleGoods = () => {

    if (cartList.reduce((num, a) => { num += a.price * a.num; return num }, 0) !== 0) {

      setVisible1(true)

    }

  }

  const Getcollect = () => document.getElementById("cart")

  // 创建小球添加动画

  const createBall = (left, top) => {

    // 创建div元素

    let Ball = document.createElement('div')

    // 给div定位

    Ball.style.position = "absolute";

    // div的left和span的left是一样的

    Ball.style.left = left + 'px'

    // div的top和span的top是一样的

    Ball.style.top = top + 'px'

    Ball.style.width = '20px'

    Ball.style.height = '20px'

    Ball.style.borderRadius = '50%'

    Ball.style.backgroundColor = 'red'

    // 贝塞尔曲线

    Ball.style.transition = "left .6s linear, top .6s cubic-bezier(0.5, -0.5, 1, 1)";

    // 向父元素最后添加

    document.body.appendChild(Ball);

    // 添加动画属性

    setTimeout(() => {

      Ball.style.left = Getcollect().offsetLeft + Getcollect().offsetWidth / 2 + "px";

      Ball.style.top = 500 + "px";

    }, 0);

    //动画结束后,删除自己

    // ontransitionend事件 是在 transition过度完之后执行的

    Ball.ontransitionend = function () {

      Ball.remove();

    };

  }

  const add = (e, user) => {

    handleNum(user, "jia")

    // console.log(Getcollect().offsetTop)

    // 获取当前span的x和y的值

    let x = e.clientX

    let y = e.clientY

    // 调用函数把x和y当参数传过去

    createBall(x, y)

  }

  return (

    <div className='goods'>

      <div className="container">

        <div className="side">

          <SideBar activeKey={activeKey} onChange={setActiveKey}>

            {tabs.map(item => (

              <SideBar.Item key={item.key} title={item.title} />

            ))}

          </SideBar>

        </div>

        <div className="main">

          <div

            className="content"

            style={{ display: activeKey === "key1" ? "flex" : "" }}

          >

            <List header='手工水饺'>

              {users.filter(item => { return item.id <= 4 }).map(user => (

                <List.Item

                  key={user.name}

                  prefix={

                    <Image

                      src={user.avatar}

                      style={{ borderRadius: 20 }}

                      fit='cover'

                      width={60}

                      height={60}

                    />

                  }

                  description={user.description}

                >

                  <div className='list-content'>

                    <h4 style={{ color: "black" }} onClick={() => { navigate("/detail", { state: user }) }}>{user.name}</h4>

                    <div style={{ display: "flex", justifyContent: "space-between" }}>

                      <span style={{ color: "red" }}>¥{user.price}</span>

                      <div style={{ display: "flex" }}>

                        {user.state ?

                          <div style={{ display: "flex" }}>

                            <span className={user.state ? "qiu-enter" : "qiu-exit"} onClick={() => { handleNum(user, "jian") }} style={{ boxSizing: "border-box", display: "block", width: "20px", height: "20px", background: "white", border: "1px solid orange", display: "flex", alignItems: "center", justifyContent: "center", color: "black", borderRadius: "5px" }}>-</span>

                            <div style={{ margin: "0px 5px", color: "black" }}>{user.num}</div>

                          </div>

                          :

                          <div style={{ display: "flex" }}>

                            <span className={user.state ? "qiu-enter" : "qiu-exit"} onClick={() => { handleNum(user, "jian") }} style={{ boxSizing: "border-box", display: "block", width: "20px", height: "20px", background: "white", border: "1px solid orange", display: "flex", alignItems: "center", justifyContent: "center", color: "black", borderRadius: "5px" }}>-</span>

                          </div>

                        }

                        <span onClick={(e) => { add(e, user) }} style={{ display: "block", width: "20px", height: "20px", background: "orange", display: "flex", alignItems: "center", justifyContent: "center", color: "black", borderRadius: "5px" }}>+</span>

                        <div id="red-qiu"></div>

                      </div>

                    </div>

                  </div>

                </List.Item>

              ))}

            </List>

          </div>

          <div

            className="content"

            style={{ display: activeKey === "key2" ? "flex" : "" }}

          >

            <List header='小咸菜'>

              {users.filter(item => { return item.id <= 6 && item.id >= 5 }).map(user => (

                <List.Item

                  key={user.name}

                  prefix={

                    <Image

                      src={user.avatar}

                      style={{ borderRadius: 20 }}

                      fit='cover'

                      width={60}

                      height={60}

                    />

                  }

                  description={user.description}

                >

                  <div className='list-content'>

                    <h4 style={{ color: "black" }} onClick={() => { navigate("/detail", { state: user }) }}>{user.name}</h4>

                    <div>

                      <h5 style={{ display: "flex", justifyContent: "space-between" }}>

                        <span style={{ color: "red" }}>¥{user.price}</span>

                        <div style={{ display: "flex" }}>

                          {user.state ?

                            <div style={{ display: "flex" }}>

                              <span onClick={() => { handleNum(user, "jian") }} style={{ boxSizing: "border-box", display: "block", width: "20px", height: "20px", background: "white", border: "1px solid orange", display: "flex", alignItems: "center", justifyContent: "center", color: "black", borderRadius: "5px" }}>-</span>

                              <div style={{ margin: "0px 5px", color: "black" }}>{user.num}</div>

                            </div>

                            : ""}

                          <span onClick={(e) => { add(e, user) }} style={{ display: "block", width: "20px", height: "20px", background: "orange", display: "flex", alignItems: "center", justifyContent: "center", color: "black", borderRadius: "5px" }}>+</span>

                        </div>

                      </h5>

                    </div>

                  </div>

                </List.Item>

              ))}

            </List>

          </div>

          <div

            className="content"

            style={{ display: activeKey === "key3" ? "flex" : "" }}

          >

            <List header='汤汤水水'>

              {users.filter(item => { return item.id <= 8 && item.id >= 7 }).map(user => (

                <List.Item

                  key={user.name}

                  prefix={

                    <Image

                      src={user.avatar}

                      style={{ borderRadius: 20 }}

                      fit='cover'

                      width={60}

                      height={60}

                    />

                  }

                  description={user.description}

                >

                  <div className='list-content'>

                    <h4 style={{ color: "black" }} onClick={() => { navigate("/detail", { state: user }) }}>{user.name}</h4>

                    <div>

                      <h5 style={{ display: "flex", justifyContent: "space-between" }}>

                        <span style={{ color: "red" }}>¥{user.price}</span>

                        <div style={{ display: "flex" }}>

                          {user.state ?

                            <div style={{ display: "flex" }}>

                              <span onClick={() => { handleNum(user, "jian") }} style={{ boxSizing: "border-box", display: "block", width: "20px", height: "20px", background: "white", border: "1px solid orange", display: "flex", alignItems: "center", justifyContent: "center", color: "black", borderRadius: "5px" }}>-</span>

                              <div style={{ margin: "0px 5px", color: "black" }}>{user.num}</div>

                            </div>

                            : ""}

                          <span onClick={(e) => { add(e, user) }} style={{ display: "block", width: "20px", height: "20px", background: "orange", display: "flex", alignItems: "center", justifyContent: "center", color: "black", borderRadius: "5px" }}>+</span>

                        </div>

                      </h5>

                    </div>

                  </div>

                </List.Item>

              ))}

            </List>

          </div>

          <div className='footer'>

            <div id="cart">

              <Badge content={cartList.reduce((num, a) => { num += a.num; return num }, 0)}>

                <svg t="1681562360047" className="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3777" width="42" height="42"><path d="M757.8624 953.4976H271.616c-107.264 0-194.2016-86.9376-194.2016-194.2016V272.9984c0-107.264 86.9376-194.2016 194.2016-194.2016h486.2464c107.264 0 194.2016 86.9376 194.2016 194.2016v486.2464c0 107.264-86.9376 194.2528-194.2016 194.2528z" fill="#F78748" p-id="3778"></path><path d="M786.8416 757.0432H429.5168c-46.4896 0-85.4016-33.3312-92.5696-79.2576L276.4288 290.56a30.65344 30.65344 0 0 0-30.464-26.0608h-22.3232c-14.1312 0-25.6-11.4688-25.6-25.6s11.4688-25.6 25.6-25.6h22.3232c40.6528 0 74.752 29.184 81.0496 69.3248l60.4672 387.2256a42.24 42.24 0 0 0 41.984 35.9424h357.3248c14.1312 0 25.6 11.4688 25.6 25.6s-11.4176 25.6512-25.5488 25.6512z" fill="#FFFFFF" p-id="3779"></path><path d="M454.1952 639.7952c-13.4144 0-24.6784-10.4448-25.5488-24.0128a25.56928 25.56928 0 0 1 23.9616-27.136l288.8704-18.1248a18.69312 18.69312 0 0 0 17.3056-15.5648l33.2288-195.4304c1.28-7.4752-2.048-12.7488-4.1472-15.2576-2.0992-2.5088-6.7584-6.656-14.336-6.656h-361.472c-14.1312 0-25.6-11.4688-25.6-25.6s11.4688-25.6 25.6-25.6h361.472c20.6336 0 40.1408 9.0624 53.4528 24.832 13.312 15.7696 18.9952 36.5056 15.5136 56.832l-33.2288 195.4304a69.65248 69.65248 0 0 1-64.5632 58.0608l-288.8704 18.1248c-0.5632 0.1024-1.1264 0.1024-1.6384 0.1024z" fill="#FFFFFF" p-id="3780"></path><path d="M407.3472 821.8624m-34.9184 0a34.9184 34.9184 0 1 0 69.8368 0 34.9184 34.9184 0 1 0-69.8368 0Z" fill="#FFFFFF" p-id="3781"></path><path d="M738.1504 821.8624m-34.9184 0a34.9184 34.9184 0 1 0 69.8368 0 34.9184 34.9184 0 1 0-69.8368 0Z" fill="#FFFFFF" p-id="3782"></path></svg>

              </Badge>

            </div>

            <div>

              总价:<span style={{ color: "red" }}>¥ {cartList.reduce((num, a) => { num += a.price * a.num; return num }, 0)}</span>

            </div>

            <div onClick={handleGoods} style={{ background: cartList.reduce((num, a) => { num += a.price * a.num; return num }, 0) !== 0 ? "orange" : "" }}>去结算</div>

          </div>

        </div>

      </div>

      <Popup

        visible={visible1}

        onMaskClick={() => {

          setVisible1(false)

        }}

        bodyStyle={{ height: '60vh' }}

      >

        <div style={{ overflow: "auto", height: "100%" }}>

          <List header='购物车'>

            {cartList.map(user => (

              <List.Item

                key={user.name}

                prefix={

                  <Image

                    src={user.avatar}

                    style={{ borderRadius: 20 }}

                    fit='cover'

                    width={60}

                    height={60}

                  />

                }

                description={user.description}

              >

                <div className='list-content'>

                  <h4 style={{ color: "black" }}>{user.name}</h4>

                  <div>

                    <h5 style={{ display: "flex", justifyContent: "space-between" }}>

                      <span style={{ color: "red" }}>¥{user.price}</span>

                      <div style={{ display: "flex" }}>

                        <div style={{ display: "flex" }}>

                          <span onClick={() => { handleNum(user, "jian") }} style={{ boxSizing: "border-box", display: "block", width: "20px", height: "20px", background: "white", border: "1px solid orange", display: "flex", alignItems: "center", justifyContent: "center", color: "black", borderRadius: "5px" }}>-</span>

                          <div style={{ margin: "0px 5px", color: "black" }}>{user.num}</div>

                        </div>

                        <span onClick={(e) => { add(e, user) }} style={{ display: "block", width: "20px", height: "20px", background: "orange", display: "flex", alignItems: "center", justifyContent: "center", color: "black", borderRadius: "5px" }}>+</span>

                      </div>

                    </h5>

                  </div>

                </div>

              </List.Item>

            ))}

          </List>

        </div>

      </Popup>

    </div>

  )

}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值