Vue 购物车案例 黑马学院
项目初始化:
需求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 购物车案例 黑马学院相关推荐
- vue购物车案例(源码)
全部效果的代码: <!DOCTYPE html> <html lang="en"> <head><meta charset="U ...
- 简易版购物车案例(vue)
简易版购物车案例(vue) <div id="app"><div v-if="books.length"><table>&l ...
- vue小案例(小黑记事本和购物车)
vue小案例 小黑记事本小案例 <footer class="footer" ><span class="todo-count" v-if=& ...
- Vue基础案例(水果搜索,购物车,todolist,留言板,跑马灯)
Vue基础案例(水果搜索,购物车,todolist,留言板,跑马灯) 01.水果搜索案例 思路以及运用知识点 通过computed计算 keyword与list ,算出findlist 如果list中 ...
- 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 ...
- Vue实战之商品购物车案例
学习Vue框架有一段时间了,所以找了个案例练练手,借此来巩固所学知识以及如何将其运用在实际生活场景,学以致用不就是这个意思嘛<_<.好了,废话不多说,切入正题. 该案例是利用Vue的计算属 ...
- 简单的VUE购物车应用
简单的VUE购物车应用 这个项目主要运用了Vue的双向数据绑定,是一个很基础的小项目 文章目录 简单的VUE购物车应用 前言 一.项目实例 二.实现步骤 1.简单布局 2.数据操作 总结 前言 v-m ...
- JS9day(BOM对象模型,setTimeout定时器,JS单线程执行机制,location对象,swiper插件,localStorage本地存储,购物车案例升级版,学习信息案例(本地存储))
文章目录 BOM简介 定时器-延时函数 5秒关闭广告案例 递归模拟setInterval函数 两种定时器对比 JS 执行机制 location对象 navigator对象 histroy对象(了解) ...
- vue——tabbar案例
1.项目初始化 组件拆分: MyHeader.vue – 复用之前的 MyTabBar.vue – 底部导航 MyTable.vue – 封装表格 三个页面: - MyGoodsList.vue – ...
最新文章
- SAP WM初阶移动类型设置里的GR Date
- 如何在Rancher 2.2 Preview2上部署和管理多K8s集群应用
- 四、MySql七个查询命令中哪些命令执行效率过慢
- 魔兽世界怀旧服最新服务器开发时间,怀旧服开70最新消息汇总 魔兽怀旧服TBC开放时间几个阶段?...
- linux bjobs
- node.js http客户端
- 暴力 Codeforces Round #183 (Div. 2) A. Pythagorean Theorem II
- 【codevs1166】【noip07TG】矩阵取数游戏,新的开始
- 《ArcGIS Runtime SDK for Android开发笔记》——(15)、要素绘制Drawtools3.0工具DEMO
- python怎么清理垃圾_【原创】python实现清理本地缓存垃圾
- hacs增加源_基于病案首页加强对医院获得性问题的管理
- json获取key对应的值java_java 获取json字符串中key对应的值
- matlab下载安装教程
- 神经网络的5个应用场景,人工神经网络应用场景
- 安全删除硬件并弹出媒体的列表中出现内置硬盘的解决办法.
- ThreadFactory线程工厂
- At least one JAR was scanned for TLDs解决办法
- 大陆、港澳台身份证、护照、军官证、户口本的正则表达式
- IE浏览器极限提速完全攻略
- origin处理多组红外数据_【图文】用Origin作多组红外数据图
热门文章
- Hive-窗口函数/开窗函数(重点理解~~~)
- python123程序设计题答案第三周_智慧职教2020Python程序设计(深圳信息职业技术学院)题目及答案...
- 国产化之虚拟ARM64-CPU安装银河麒麟操作系统
- POJ 1269 求两直线交点
- SOUL音乐(安卓)
- C++ 笔记(待续)
- python 语音朗读软件-python 利用pyttsx3文字转语音过程详解
- “躺平家”出世,阿里做家装成不成?
- liunx内核配置说明/etc/sysctl.conf
- 网鼎杯玄武组部分web题解