项目初始化:

需求1:从0新建项目

需求2:分拆组件,创建组件文件

分析:

①:vue命令创建项目(在根目录下运行)

vue create shopcar-deom

②:下载需要得配置:

yarn add less less-loader bootstrap

③:main.js - 引入bootst 样式

// 直接引入 bootstrap 的css文件样式
import 'bootstrap/dist/css/bootstrap.css'

补充:下载时候可能会因为网络出问题

//查看当前源
yarn config get registry
//设置淘宝源或内网源
yarn config set registry https://registry.npm.taobao.org --global
//恢复源
yarn config set registry https://registry.yarnpkg.com --global

准备代码:

MyHeader:

<template><div class="my-header">购物车案例</div>
</template><script>
export default {}
</script><style lang="less" scoped>
.my-header {  height: 45px;
  line-height: 45px;
  text-align: center;
  background-color: #1d7bff;
  color: #fff;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  z-index: 2;
}
</style>

MyGoods:

<template><div class="my-goods-item"><div class="left"><div class="custom-control custom-checkbox"><input type="checkbox" class="custom-control-input" id="input"><label class="custom-control-label" for="input"><img src="http://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg" alt=""></label></div></div><div class="right"><div class="top">商品名字</div><div class="bottom"><span class="price">¥ 100</span><span><MyCount></MyCount></span></div></div></div>
</template>
<script>
import MyCount from './MyCount';
export default {  components: {    MyCount}
}
</script><style lang="less">
.my-goods-item {  display: flex;
  padding: 10px;
  border-bottom: 1px solid #ccc;.left {    img {      width: 120px;
      height: 120px;
      margin-right: 8px;
      border-radius: 10px;}.custom-control-label::before,.custom-control-label::after {      top: 50px;}}.right {    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: space-between;.top {      font-size: 14px;
      font-weight: 700;}.bottom {      display: flex;
      justify-content: space-between;
      padding: 5px 0;
      align-items: center;.price {        color: red;
        font-weight: bold;}}}
}
</style>

MyCount:

<template><div class="my-counter"><button type="button" class="btn btn-light">-</button><input type="" class="form-control inp" placeholder="10"><button type="button" class="btn btn-light">+</button></div>
</template><script>
export default {}
</script><style lang="less" scoped>
.my-counter {  display: flex;.inp {    width: 45px;
    text-align: center;
    margin: 0 10px;}.btn,.inp {    transform: scale(0.9);}
}
</style>

MyFooter:

<template><!-- 底部 --><div class="my-footer"><!-- 全选 --><div class="custom-control custom-checkbox"><input type="checkbox" class="custom-control-input" id="footerCheck"><label class="custom-control-label" for="footerCheck">全选</label></div><!-- 合计 --><div><span>合计:</span><span class="price">¥ 100</span></div><!-- 按钮 --><button type="button" class="footer-btn btn btn-primary">结算 ( 0 )</button></div></template><script>
export default {}
</script><style lang="less" scoped>
.my-footer {  position: fixed;
  z-index: 2;
  bottom: 0;
  width: 100%;
  height: 50px;
  border-top: 1px solid #ccc;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 10px;
  background: #fff;.price {    color: red;
    font-weight: bold;
    font-size: 15px;}.footer-btn {    min-width: 80px;
    height: 30px;
    line-height: 30px;
    border-radius: 25px;
    padding: 0;}
}
</style>

App.vue盒子优化:

<template><div><MyHeader></MyHeader><div class="main"><MyGoods></MyGoods></div><MyFooter></MyFooter></div>
</template>
<script>
import MyHeader from './components/MyHeader'
import MyGoods from './components/MyGoods';
import MyFooter from './components/MyFooter';
export default {data() {return {}},
  components: {    MyHeader,
    MyGoods,
    MyFooter,}
}
</script><style scoped>
.main {  padding: 45px 0 50px;
}
</style>

头部自定义

我们的组件要自定义(大致样式一样,颜色,字体我们要变化的来适应不同场景)

分析:

①:背景色定义props里变量接收使用

②:文字颜色定义props里变量接收-设默认值

③:文字内容定义props里变量接收-设必传值

④:使用组件传入具体值(父传子)

props有两种定义方式

props: [ ] - 只声明变量,不能类型校验

props: { } - 声明变量和校验类型规则 - 不对就会报错

数据获取

分析:

①:下载axios,在main,jsl入(以前是单独引入一个vue文件里面)

yarn add axios

②:配置基础地址,https:/www.escook.cn

③:axios挂载到Vue原型上,作为全局属性

④:App.vue的created中使用全局属性axios

⑤:接口地址为/api/cart

// 目标:请求数据 - 打印
// 1. 下载axios库,main.js - 全局绑定属性(所有 .vue 文件可以访问到axios方法)
import axios from 'axios'
// 2. 设置基础地址
axios.defaults.baseURL = 'https://www.escook.cn'
// 3. axios方法添加到原型上($axios这个名字是自定义的)
Vue.prototype.$axios = axios

数据铺设

需求:把数据使用MyGoods组件展示

分析:

①:App.vue把数据保存到data定义的变量上

②:使用v-for循环数组使用组件

③:分别给商品组件传入数据对象

④:商品组件接收后,使用对象里字段数据展示

商品选中

分析:

①:给v-model关联到小选框上,数据关联对象的goods_state

②:注意点图片用label关联的小选框

③:label的for值要和表单标签id一致,点label才触发小选框

④:id属性分别使用商品的id即可

  • label标签关联表单,点击label标签上,相当于点击表单
  • 对象传值赋值传的是引用类型的堆内存地址,多处使用共同的这个对象/数组

数量控制

分析:

①:给MyCount组件传入数据对象关联

②:输入框v-model关联对象里数量属性

③:增加或减少修改对象数量属性

④:控制商品最少1件

先控制按钮,然后侦听输入框值,强制覆盖

全选

分析:

①:v-model用计算属性,关联全选框

②:在set方法里,获取全选状态

③:回传到App.vue再同步给所有小选框

④:在get方法里,统计小选框给全选复制

全选和小选框,互相影响的思路:

  • 全选-关联计算属性-set方法-同步所有小选
  • 小选-触发计算属性的get方法-统计后返回全选状态

总数量

分析:

①:计算属性allCount变量

②:在统计数组里数据时,要判断勾选状态才累加数量(判断)

③:把累加好数量返回给allCount变量使用显示

// 核心代码-计算属性
allCount() {// reduce() 的计算方法return this.arr.reduce((sum, obj) => { //整体返回计算的结果值if (obj.goods_state == true) {// 选中商品才累加数量
          sum += obj.goods_count;}return sum //内部返回供下次使用}, 0)},

总价

分析:

①:计算属性allPrice变量

②:在统计数组里数据时,要判断勾选状态才累加

③:把价格和数量先想乘,再累加

④:累加好数据返回给allPrice变量使用显示

// 核心代码-计算属性allPrice() {return this.arr.reduce((sum, obj) => {if (obj.goods_state == true) {          sum += obj.goods_count * obj.goods_price}return sum}, 0)}

最终代码

App.vue:

<template><div><!-- 标签内属性加冒号是变量,不加是固定字符串 --><MyHeader background="skyblue" title="HB的购物车"></MyHeader><div class="main"><MyGoods v-for="obj in list" :key="obj.id" :obj="obj"></MyGoods></div><MyFooter style="boredr:10px" @changeAllFn="allFn" :arr="list"></MyFooter></div>
</template><script>
//目标:数据铺设到MyGoods组件上
//l.数据在data保存一下(页面只能用data里值)
//2.页面v-for循环MyGoods:组件
//3.分别传入obj数据对象(一对一关系)I
//4.内部使用数据对象值
import MyHeader from './components/MyHeader'
import MyGoods from './components/MyGoods';
import MyFooter from './components/MyFooter';export default {data() {return {list: [] // 商品所有数据}},components: {MyHeader,MyGoods,MyFooter,},created() {// 思考这个用法这是调用函数this.$axios({url: '/api/cart'}).then(res => {this.list = res.data.list //这里必须得用箭头函数才能这样用 thisconsole.log(this.list);})},methods: {allFn(val) {// this.list.goods_state = valthis.list.forEach(obj => obj.goods_state = val)// 把MyFooter内的全选状态值同步给所有小选框的关联属性上}}
}
</script><style scoped>
.main {padding: 45px 0 50px;
}
</style>

MyCount.vue:

<template><div class="my-counter"><!-- obj.goods_count > 1 && obj.goods_count-- 大于一才能减一操作 --><button type="button" class="btn btn-light" @click="obj.goods_count > 1 && obj.goods_count--":disabled='obj.goods_count==1'>-</button><input class="form-control inp" v-model.number="obj.goods_count"><button type="button" class="btn btn-light" @click="obj.goods_count++">+</button></div>
</template><script>
// 目标:商品数量 - 控制
// 1. 外部传入数据对象
// 2. v-model关联对象的goods_count属性和输入框(双向绑定!)
// 3. 商品按钮 +和- ,商品数量最小一件, 直接用表达式
// 4. 侦听数量改变,小于1,直接强制覆盖1
export default {props: {//  因为数量控制要通过对象“互相引用的关系”来影响外面对象里的数量值,所以最好传 对象进来obj: Object // 商品对象},watch: {obj: {deep: true,handler() {// 为啥三元表达不可?// this.obj.goods_count < 1 ? 1 : this.obj.goods_countif (this.obj.goods_count < 1) {this.obj.goods_count = 1}console.log(this.obj.goods_count);}}}
}
</script><style lang="less" scoped>
.my-counter {display: flex;.inp {width: 45px;text-align: center;margin: 0 10px;}.btn,.inp {transform: scale(0.9);}}
</style>

MyFooter.vue:

<template><!-- 底部 --><div class="my-footer"><!-- 全选 --><div class="custom-control custom-checkbox"><input type="checkbox" class="custom-control-input" id="footerCheck" v-model="isAll"><label class="custom-control-label" for="footerCheck">全选</label></div><!-- 合计 --><div><span>合计:</span><span class="price">¥ {{ allPrice }}</span></div><!-- 按钮 --><button type="button" class="footer-btn btn btn-primary">结算 ( {{ allCount }} )</button></div></template><script>
// 目标:全选
// 1. v-model 关联全选复选框(v-model后变量计算属性)
// 2. 页面(视图层)v(true) → 数据层(变量-) → 计算属性(完整写法)
// 3. 把全选的选中状态同步给所有的小选框的选中状态上// 小选
// 从App里面把数组传过来 ,
// 看数组里面的 选中状态是不是全部满足条件,用 every()方法
// 在计算属性的 get() 里面// 目标:总数量的统计
export default {props: {arr: Array,},computed: {isAll: {set(val) { // 所关联表单的值(true/false)console.log(val);this.$emit('changeAllFn', val)},get() {// 查找小选框关联的属性有没有不符合勾选的条件 读下面语句return this.arr.every(obj => obj.goods_state == true)}},// 只需要统计的话,不用完整写法也可以allCount() {// reduce() 的计算方法return this.arr.reduce((sum, obj) => { //整体返回计算的结果值if (obj.goods_state == true) {// 选中商品才累加数量sum += obj.goods_count;}return sum //内部返回供下次使用}, 0)},allPrice() {return this.arr.reduce((sum, obj) => {if (obj.goods_state == true) {sum += obj.goods_count * obj.goods_price}return sum}, 0)}}
}
</script><style lang="less" scoped>
.my-footer {position: fixed;z-index: 2;bottom: 0;width: 100%;height: 50px;border-top: 1px solid #ccc;display: flex;justify-content: space-between;align-items: center;padding: 0 10px;background: #fff;.price {color: red;font-weight: bold;font-size: 15px;}.footer-btn {min-width: 80px;height: 30px;line-height: 30px;border-radius: 25px;padding: 0;}
}
</style>

MyGoods.vue:

<template><div class="my-goods-item"><div class="left"><div class="custom-control custom-checkbox"><!-- 每个组件和选择状态都是独立的对象不一样,它的属性也不一样,渲染组件也就不一样了--><input type="checkbox" class="custom-control-input" :id="obj.id" v-model="obj.goods_state"><label class="custom-control-label" :for="obj.id"><img :src="obj.goods_img" alt=""></label></div></div><div class="right"><div class="top">{{ obj.goods_name }}</div><div class="bottom"><span class="price">¥{{ obj.goods_price}}</span><span><MyCount :obj="obj"></MyCount></span></div></div></div>
</template>
<script>
import MyCount from './MyCount';
export default {components: {MyCount},props: {obj: Object}
}
</script><style lang="less">
.my-goods-item {display: flex;padding: 10px;border-bottom: 1px solid #ccc;.left {img {width: 120px;height: 120px;margin-right: 8px;border-radius: 10px;}.custom-control-label::before,.custom-control-label::after {top: 50px;}}.right {flex: 1;display: flex;flex-direction: column;justify-content: space-between;.top {font-size: 14px;font-weight: 700;}.bottom {display: flex;justify-content: space-between;padding: 5px 0;align-items: center;.price {color: red;font-weight: bold;}}}
}
</style>

MyHeader.vue:

<template><!-- 像color,这样值和名一样,可以简写 color: color => color--><div class="my-header" :style="{ backgroundColor: background, color }">{{ title }}</div>
</template><script>
// 目标:让Header组件支持不同的项目 - 自定义
// 1. 分析那些可以自定义(背景色、颜色、文字内容)
// 2. ❤️可以对props的变量值,进行校验
// 3. 内部使用props变量值
// 4. 外部使用时,遵守变量名作为属性名,值得类型也要遵守
export default {props: {background: String,// 外部插入此变量的值,必须是字符串类型,否则报错color: {type: String,//  约束color的插入值类型default: '#FFF'// 默认的值(如果外部不传,就用默认值)},title: {type: String,required: true // 必须传入的值,没传就报错}}
}
</script><style lang="less" scoped>
.my-header {height: 45px;line-height: 45px;text-align: center;background-color: #1d7bff;color: #fff;position: fixed;top: 0;left: 0;width: 100%;z-index: 2;
}
</style>

Vue 购物车案例 黑马学院相关推荐

  1. vue购物车案例(源码)

    全部效果的代码: <!DOCTYPE html> <html lang="en"> <head><meta charset="U ...

  2. 简易版购物车案例(vue)

    简易版购物车案例(vue) <div id="app"><div v-if="books.length"><table>&l ...

  3. vue小案例(小黑记事本和购物车)

    vue小案例 小黑记事本小案例 <footer class="footer" ><span class="todo-count" v-if=& ...

  4. Vue基础案例(水果搜索,购物车,todolist,留言板,跑马灯)

    Vue基础案例(水果搜索,购物车,todolist,留言板,跑马灯) 01.水果搜索案例 思路以及运用知识点 通过computed计算 keyword与list ,算出findlist 如果list中 ...

  5. vue之购物车案例升级版、v-model之lazy、number、trim的使用、fetch和axios、计算属性、Mixins、虚拟dom与diff算法 key的作用及组件化开发

    文章目录 1.购物车案例升级版(含价格统计.全选/反选.商品增加减少) 2.v-model之lazy.number.trim的使用 3.fetch和axios 3.1.通过jquery+ajax实现v ...

  6. Vue实战之商品购物车案例

    学习Vue框架有一段时间了,所以找了个案例练练手,借此来巩固所学知识以及如何将其运用在实际生活场景,学以致用不就是这个意思嘛<_<.好了,废话不多说,切入正题. 该案例是利用Vue的计算属 ...

  7. 简单的VUE购物车应用

    简单的VUE购物车应用 这个项目主要运用了Vue的双向数据绑定,是一个很基础的小项目 文章目录 简单的VUE购物车应用 前言 一.项目实例 二.实现步骤 1.简单布局 2.数据操作 总结 前言 v-m ...

  8. JS9day(BOM对象模型,setTimeout定时器,JS单线程执行机制,location对象,swiper插件,localStorage本地存储,购物车案例升级版,学习信息案例(本地存储))

    文章目录 BOM简介 定时器-延时函数 5秒关闭广告案例 递归模拟setInterval函数 两种定时器对比 JS 执行机制 location对象 navigator对象 histroy对象(了解) ...

  9. vue——tabbar案例

    1.项目初始化 组件拆分: MyHeader.vue – 复用之前的 MyTabBar.vue – 底部导航 MyTable.vue – 封装表格 三个页面: - MyGoodsList.vue – ...

最新文章

  1. SAP WM初阶移动类型设置里的GR Date
  2. 如何在Rancher 2.2 Preview2上部署和管理多K8s集群应用
  3. 四、MySql七个查询命令中哪些命令执行效率过慢
  4. 魔兽世界怀旧服最新服务器开发时间,怀旧服开70最新消息汇总 魔兽怀旧服TBC开放时间几个阶段?...
  5. linux bjobs
  6. node.js http客户端
  7. 暴力 Codeforces Round #183 (Div. 2) A. Pythagorean Theorem II
  8. 【codevs1166】【noip07TG】矩阵取数游戏,新的开始
  9. 《ArcGIS Runtime SDK for Android开发笔记》——(15)、要素绘制Drawtools3.0工具DEMO
  10. python怎么清理垃圾_【原创】python实现清理本地缓存垃圾
  11. hacs增加源_基于病案首页加强对医院获得性问题的管理
  12. json获取key对应的值java_java 获取json字符串中key对应的值
  13. matlab下载安装教程
  14. 神经网络的5个应用场景,人工神经网络应用场景
  15. 安全删除硬件并弹出媒体的列表中出现内置硬盘的解决办法.
  16. ThreadFactory线程工厂
  17. At least one JAR was scanned for TLDs解决办法
  18. 大陆、港澳台身份证、护照、军官证、户口本的正则表达式
  19. IE浏览器极限提速完全攻略
  20. origin处理多组红外数据_【图文】用Origin作多组红外数据图

热门文章

  1. Hive-窗口函数/开窗函数(重点理解~~~)
  2. python123程序设计题答案第三周_智慧职教2020Python程序设计(深圳信息职业技术学院)题目及答案...
  3. 国产化之虚拟ARM64-CPU安装银河麒麟操作系统
  4. POJ 1269 求两直线交点
  5. SOUL音乐(安卓)
  6. C++ 笔记(待续)
  7. python 语音朗读软件-python 利用pyttsx3文字转语音过程详解
  8. “躺平家”出世,阿里做家装成不成?
  9. liunx内核配置说明/etc/sysctl.conf
  10. 网鼎杯玄武组部分web题解