【Vue实战】使用vue实现购物车案例

这篇具有很好参考价值的文章主要介绍了【Vue实战】使用vue实现购物车案例。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 实现步骤

【Vue实战】使用vue实现购物车案例
【备注】这里的接口地址目前(2022年6月)还是可以用的哦~

2. 实现
2.1 代码结构

【Vue实战】使用vue实现购物车案例
使用的样式是Boostrap,需要npm i bootstrap,然后在main.js中引入bootstrap。
【Vue实战】使用vue实现购物车案例

2.2 Header头部的代码
<template>
  <div class="header-container">{{ title }}</div>
</template>

<script>
export default {
  props: {
    title: {
      default: '',
      type: String
    }
  }
};
</script>

<style lang="less" scoped>
.header-container {
  font-size: 12px;
  height: 45px;
  width: 100%;
  background-color: #1d7bff;
  display: flex;
  justify-content: center;
  align-items: center;
  color: #fff;
  position: fixed;
  top: 0;
  z-index: 999;
  left: 0;
}
</style>
2.3 Goods商品组件代码

【Vue实战】使用vue实现购物车案例
代码:

<template>
  <div class="goods-container">
    <!-- 左侧图片 -->
    <div class="thumb">
      <div class="custom-control custom-checkbox">
        <!-- 复选框 -->
        <input
          type="checkbox"
          class="custom-control-input"
          :id="'cb' + id"
          :checked="state"
          @change="stateChange"
        />
        <label class="custom-control-label" :for="'cb' + id">
          <!-- 商品的缩略图 -->
          <img :src="pic" alt="" />
        </label>
      </div>
    </div>
    <!-- 右侧信息区域 -->
    <div class="goods-info">
      <!-- 商品标题 -->
      <h6 class="goods-title">{{ title }}</h6>
      <div class="goods-info-bottom">
        <!-- 商品价格 -->
        <span class="goods-price">{{ price }}</span>
        <!-- 商品的数量 -->
        <Counter :num="count" :id="id"></Counter>
      </div>
    </div>
  </div>
</template>

<script>
import Counter from '../Counter/Counter.vue';
export default {
  props: {
    id: {
      required: true,
      type: Number,
    },
    title: {
      default: "",
      type: String,
    },
    pic: {
      default: "",
      type: String,
    },
    price: {
      default: 0,
      type: Number,
    },
    state: {
      default: true,
      type: Boolean,
    },
    count: {
      default: 1,
      type: Number,
    }
  },
  methods: {
    // 复选框发生改变,调用这个事件
    stateChange(e) {
      // console.log(e);
      const newState = e.target.checked;
      // console.log(this.id);
      // 触发自定义事件(子传父)
      this.$emit('state-change', { id: this.id, value: newState})
    }
  },
  components: {
    Counter,
  }
};
</script>

<style lang="less" scoped>
.goods-container {
  + .goods-container {
    border-top: 1px solid #efefef;
  }
  padding: 10px;
  display: flex;
  .thumb {
    display: flex;
    align-items: center;
    img {
      width: 100px;
      height: 100px;
      margin: 0 10px;
    }
  }

  .goods-info {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    flex: 1;
    .goods-title {
      font-weight: bold;
      font-size: 12px;
    }
    .goods-info-bottom {
      display: flex;
      justify-content: space-between;
      .goods-price {
        font-weight: bold;
        color: red;
        font-size: 13px;
      }
    }
  }
}
</style>

2.4 Footer组件代码
<template>
  <div class="footer-container">
    <!-- 左侧的全选 -->
    <div class="custom-control custom-checkbox">
      <input
        type="checkbox"
        class="custom-control-input"
        id="cbFull"
        :checked="isFull"
        @change="fullChange"
      />
      <label class="custom-control-label" for="cbFull">全选</label>
    </div>

    <!-- 中间的合计 -->
    <div>
      <span>合计:</span>
      <span class="total-price">{{ amount.toFixed(2) }}</span>
    </div>

    <!-- 结算按钮 -->
    <button type="button" class="btn btn-primary btn-settle">
      结算({{ all }}</button>
  </div>
</template>

<script>
export default {
  props: {
    isFull: {
      default: true,
      type: Boolean,
    },
    amount: {
      default: 0,
      type: Number,
    },
    all: {
      default: 0,
      type: Number,
    }
  },
  methods: {
    // 监听全选的状态变化
    fullChange(e) {
      // console.log(e.target.checked);
      this.$emit("full-change", e.target.checked);
    },
  },
};
</script>

<style lang="less" scoped>
.footer-container {
  font-size: 12px;
  height: 50px;
  width: 100%;
  border-top: 1px solid #efefef;
  position: fixed;
  bottom: 0;
  background-color: #fff;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 10px;
}

.custom-checkbox {
  display: flex;
  align-items: center;
}

#cbFull {
  margin-right: 5px;
}

.btn-settle {
  height: 80%;
  min-width: 110px;
  border-radius: 25px;
  font-size: 12px;
  color: #fff;
  background-color: #1d7bff;
  border: 0;
}

.total-price {
  font-weight: bold;
  font-size: 14px;
  color: red;
}
</style>

2.5 Counter组件代码
<template>
  <div
    class="number-container d-flex justify-content-center align-items-center"
  >
    <!--1 的按钮 -->
    <button type="button" class="btn btn-light btn-sm" @click="sub">-</button>
    <!-- 购买的数量 -->
    <span class="number-box">{{ num }}</span>
    <!--1 的按钮 -->
    <button type="button" class="btn btn-light btn-sm" @click="add">+</button>
  </div>
</template>

<script>
import bus from '@/components/eventBus.js';

export default {
  props: {
    // 接收商品的id,将来使用eventBus方案,把数量传递到app.vue的时候,需要通知App组件,更新哪个商品的数量
    id: {
      type: Number,
      required: true,
    },
    num: {
      default: 1,
      type: Number,
    },
  },
  methods: {
    // 点击按钮,数值加1
    add() {
      // 要发送给App的数据,id是商品的id,value是商品的数量
      const obj = {
        id : this.id, 
        value : this.num + 1,
      }
      // 通过eventBus把obj对象发送给App.vue组件
      // console.log(obj);
      bus.$emit('share', obj);
    },
    // 点击按钮,数值减1
    sub() {
      if(this.num-1 === 0) return;
      const obj = {
        id: this.id,
        value: this.num - 1,
      }
      bus.$emit('share', obj);
    }
  }
};
</script>

<style lang="less" scoped>
.number-box {
  min-width: 30px;
  text-align: center;
  margin: 0 5px;
  font-size: 12px;
}

.btn-sm {
  width: 30px;
}
</style>

2.6 App.vue根组件代码
<template>
  <div id="app-container">
  	<hr>
    <!-- 头部区域 -->
    <Header title="购物车案例"></Header>

    <!-- 商品列表(循环渲染每一个商品的信息) -->
    <Goods
      v-for="item in list"
      :key="item.id"
      :id="item.id"
      :title="item.goods_name"
      :pic="item.goods_img"
      :price="item.goods_price"
      :state="item.goods_state"
      :count="item.goods_count"
      @state-change="getNewState"
    ></Goods>

    <!-- footer区域 -->
    <Footer
      :isFull="fullState"
      :amount="amt"
      :all="total"
      @full-change="getFullState"
    ></Footer>
    <br>
  </div>
</template>

<script>
import axios from "axios";
import Header from "@/components/Header/Header";
import Goods from "./components/Goods/Goods.vue";
import Footer from "@/components/Footer/Footer";
import bus from '@/components/eventBus.js';

export default {
  data() {
    return {
      // 用来存储购物车列表数据,默认为空数组
      list: [],
    };
  },
  methods: {
    // 封装请求列表数据的方法
    async initCardList() {
      const { data: res } = await axios.get("https://www.escook.cn/api/cart");
      // console.log(res);
      if (res.status === 200) {
        this.list = res.list;
      }
      // console.log(this.list);
    },
    // 接收子组件发来的数据
    getNewState(e) {
      // console.log(e);
      this.list.some((item) => {
        if (item.id === e.id) {
          item.goods_state = e.value;
          return true;
        }
      });
    },
    // 接收Footer子组件发来的全选状态
    getFullState(val) {
      // console.log(val);
      this.list.forEach((item) => {
        item.goods_state = val;
      });
    },
  },
  components: {
    Header,
    Goods,
    Footer,
  },
  created() {
    this.initCardList();
    bus.$on('share', (val) => {
      // console.log(val);
      this.list.some(item => {
        if(item.id === val.id) {
          item.goods_count = val.value;
          // 终止循环
          return true;
        }
      })
    })
  },
  computed: {
    // 动态计算出全选的状态是 true 还是 false
    fullState() {
      return this.list.every((item) => item.goods_state);
    },
    // 已勾选状态的商品总价
    amt() {
      // 1. 先filter过滤
      // 2. 再reduce累加
      return this.list.filter(item=>item.goods_state).reduce((total, item)=>{
        return total += item.goods_price * item.goods_count;
      },0)
    },
    // 已勾选的数量总数
    total() {
      return this.list.filter(item=>item.goods_state).reduce((t,item)=> {
        return t += item.goods_count;
      },0)
    }
  },
};
</script>

<style lang="less">
.app-container {
  padding-top: 45px;
  padding-bottom: 50px;
}
</style>

2.7 eventBus.js 代码

【Vue实战】使用vue实现购物车案例

import Vue from 'vue';

export default new Vue()
2.8 效果

【Vue实战】使用vue实现购物车案例

3. 总结
3.1 组件之间的嵌套关系
  1. App为根组件
  2. App有三个子组件:Header、Goods、Footer;
  3. Goods有一个子组件:Counter;
3.2 这个案例涉及到的知识点
  1. 使用axios的get方法获取商品信息列表;
  2. vue的组件化;
  3. v-bind、v-for、@事件绑定;
  4. 父组件向子组件传值:自定义属性;
  5. 子组件向父组件传值:自定义事件;
  6. 兄弟组件之间传值,使用eventBus.js;
  7. 计算属性的使用(注意一定要return);
  8. 数组的forEach、every、filter、some、reduce等方法的使用;

参考:黑马vue视频,感谢llb老师。文章来源地址https://www.toymoban.com/news/detail-483174.html

到了这里,关于【Vue实战】使用vue实现购物车案例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 使用JavaScript和Vue.js框架开发的电子商务网站,实现商品展示和购物车功能

    引言: 随着互联网的快速发展和智能手机的普及,电子商务行业正迎来一个全新的时代。越来越多的消费者选择网上购物,而不再局限于传统的实体店。这种趋势不仅仅是改变了消费者的习惯购物,也给企业带来了巨大的商机。为了不断满足消费者的需求,电子商务网站需要

    2024年02月15日
    浏览(45)
  • Vue入门三(表单控制|购物车案例|v-model进阶|与后端交互|计算属性|监听属性|Vue生命周期)

    v-model双向数据绑定,还可以对输入框数据进行一定的限定。 v-modle 释义 lazy 等待input框的数据绑定时区焦点之后再变化 number 以数字开头并只保留后面的数字,不保留字母;字母开头都保留 trim 去除首位的空格 与后端交互统一使用json编码格式 与后端交互涉及到跨域问题后,

    2024年01月21日
    浏览(35)
  • 购物车功能实现(小兔鲜儿)【Vue3】

    购物车业务逻辑梳理拆解 整个购物车的实现分为两个大分支, 本地购物车操作和接口购物车操作 由于购物车数据的特殊性, 采取Pinia管理购物车列表数据并添加持久化缓存 本地购物车 - 加入购物车实现 添加购物车 基础思想:如果已经添加过相同的商品,就在其数量count上加一

    2024年02月15日
    浏览(35)
  • Vue项目(购物车)

    目录 购物车效果展示: 购物车代码: 购物车效果展示: 此项目添加、修改、删除数据的地方都写了浏览器都会把它存储起来 下次运行项目时会把浏览器数据拿出来并在页面展示 Video_20230816145047 购物车代码: 复制完代码,需改下script中引入的vue文件地址; 可直接使用

    2024年02月12日
    浏览(25)
  • Vue第三篇:最简单的vue购物车示例

    本文参考:Vue Cli(脚手架)实现购物车小案例 - - php中文网博客  效果图:   编写流程: 1、首先通过@vue/cli创建工程 vue create totalprice 2、改写App.vue代码如下: 3、代码中相关内容说明: (1)caption为table的标题 (2)在组件中使用v-for时,必须添加:key属性,否则会报错,为了

    2024年02月17日
    浏览(27)
  • 微信小程序实现商品加入购物车案例

    思考: 购物车中的数据保存在哪里?用哪种数据结构进行保存? 小程序中可能有多个页面需要对购物车中的数据进行操作,因此我们想到把数据存到全局中。可以使用 wx.setStorageSync() 储存,用 wx.getStorageSync() 进行获取,以数组格式方便对数据进行操作。 一、商品加入购物车

    2024年02月10日
    浏览(32)
  • 14-案例:购物车

    需求说明:         1. 渲染功能                 v-if/v-else v-for :class         2. 删除功能                 点击传参 filter 过滤覆盖原数组         3. 修改个数                 点击传参 find 找对象         4. 全选反选                 计算属性 computed 完整写法 get/

    2024年02月12日
    浏览(34)
  • [gtp]购物车案例参考

    react hooks,购物车案例. 在列表上点击+或者-更新数量,调用接口更新单个价格. 点击table的checkbox勾选后,计算总价? 对于React Hooks和购物车案例,您可以使用useState来管理列表中商品的数量和总价。当点击\\\"+“或”-\\\"按钮时,可以更新相应商品的数量,并通过调用接口来更新单个商品

    2024年02月13日
    浏览(22)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包