案例 - 购物车

按照组件化方式实现业务需求

  • 根据业务功能进行组件化划分

    • 标题组件(展示文本)
    • 列表组件(列表展示、商品数量变更、商品删除)
    • 结算组件(计算商品总额)

功能实现步骤

  • 实现整体布局和样式效果
  • 划分独立的功能组件
  • 组合所有的子组件形成整体结构
  • 逐个实现各个组件功能
    • 标题组件
    • 列表组件
    • 结算组件

效果图展示

实现组件化布局

  • 先创建一个局部组件my-cart,在里面引入属性components,定义三个组件cart-title,cart-list,cart-total
var CartTitle = {template: ``
}
var CartList = {template: ``
}
var CartTotal = {template: ``
}Vue.component('my-cart',{template: ``,components: {'cart-title': CartTitle,'cart-list': CartList,'cart-total': CartTotal}
});
  • 把页面的静态结构转化为组件化的方式
var CartTitle = {template: `<div class="title">我的商品</div>`
}
var CartList = {template: `<div><div class="item"><img src="img/a.jpg"/><div class="name"></div><div class="change"><a href="">-</a><input type="text" class="num" /><a href="">+</a></div><div class="del">×</div></div><div class="item"><img src="img/b.jpg"/><div class="name"></div><div class="change"><a href="">-</a><input type="text" class="num" /><a href="">+</a></div><div class="del">×</div></div><div class="item"><img src="img/c.jpg"/><div class="name"></div><div class="change"><a href="">-</a><input type="text" class="num" /><a href="">+</a></div><div class="del">×</div></div><div class="item"><img src="img/d.jpg"/><div class="name"></div><div class="change"><a href="">-</a><input type="text" class="num" /><a href="">+</a></div><div class="del">×</div></div><div class="item"><img src="img/e.jpg"/><div class="name"></div><div class="change"><a href="">-</a><input type="text" class="num" /><a href="">+</a></div><div class="del">×</div></div></div>`
}
var CartTotal = {template: `<div class="total"><span>总价:123</span><button>结算</button></div>`
}Vue.component('my-cart',{template: `<div class='cart'><cart-title></cart-title><cart-list></cart-list><cart-total></cart-total></div>`,components: {'cart-title': CartTitle,'cart-list': CartList,'cart-total': CartTotal}
});
  • 在容器中利用<my-cart></my-cart>展示出效果
<div id="app"><div class="container"><my-cart></my-cart></div>
</div>

实现标题和结算组件功能

  • 用父组件传递标题的数据
var CartTitle = {props: ['uname'],template: `<div class="title">{{uname}}的动物园拍卖会</div>`
}
Vue.component('my-cart',{data: function() {return {uname: 'DG',}},template: `<div class='cart'><cart-title :uname='uname'></cart-title><cart-list></cart-list><cart-total></cart-total></div>`,
}
  • 接下来需要有数据提供
Vue.component('my-cart',{data: function() {return {uname: 'DG',list: [{id: 1,name: '熊猫',price: 1000,num: 1,img: 'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3726570454,3633557931&fm=26&gp=0.jpg'},{id: 2,name: '猴子',price: 1000,num: 1,img: 'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3524667055,2282983046&fm=26&gp=0.jpg'},{id: 3,name: '兔子',price: 1000,num: 1,img: 'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1173496453,597070384&fm=26&gp=0.jpg'},{id: 4,name: '老鼠',price: 1000,num: 1,img: 'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3570432866,2699104227&fm=26&gp=0.jpg'},{id: 5,name: '海豚',price: 1000,num: 2,img: 'https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=1113954919,3492262937&fm=26&gp=0.jpg'}]}}
  • 之后把数据传递给cart-total
template: `<div class='cart'><cart-title :uname='uname'></cart-title><cart-list></cart-list><cart-total :list='list'></cart-total></div>
`
  • 在传递完需要接受数据
var CartTotal = {props: ['list'],template: `<div class="total"><span>总价:{{total}}</span><button>结算</button></div>`
}
  • 利用计算属性实现结算功能
computed: {total: function() {// 计算商品的总价var t = 0;this.list.forEach(item => {t += item.price * item.num;});return t;}
}

实现列表组件删除功能

  • 传递和接受list

    • 传递
    template: `<div class='cart'><cart-title :uname='uname'></cart-title><cart-list :list='list'></cart-list><cart-total :list='list'></cart-total></div>
    `
    
    • 接受
    var CartList = {props: ['list'],template: `<div><div :key='item.id' v-for='item in list' class="item"><img :src="item.img"/><div class="name">{{item.name}}</div><div class="change"><a href="">-</a><input type="text" class="num" /><a href="">+</a></div><div class="del" @click='del(item.id)'>×</div></div></div>`
    }
    
  • 实现删除

methods: {del: function(id){// 把id传递给父组件this.$emit('cart-del', id);}
}
  • 找到对应的父组件
template: `<div class='cart'><cart-title :uname='uname'></cart-title><cart-list :list='list' @cart-del='delCart($event)'></cart-list><cart-total :list='list'></cart-total></div>
`
  • 根据id删除list中对应的数据
methods: {delCart: function(id) {// 1、找到id所对应数据的索引var index = this.list.findIndex(item=>{return item.id == id;});// 2、根据索引删除对应数据this.list.splice(index, 1);}
}

实现组件更新数据功能

  • 利用属性绑定的方式实现num呈现在前端页面中
var CartList = {props: ['list'],template: `<div><div :key='item.id' v-for='item in list' class="item"><img :src="item.img"/><div class="name">{{item.name}}</div><div class="change"><a href="">-</a><input type="text" class="num" :value='item.num' @blur='changeNum(item.id, $event)'/><a href="">+</a></div><div class="del" @click='del(item.id)'>×</div></div></div>`
}
  • 实现数字变更操作
methods: {changeNum: function(id, event){this.$emit('change-num', {id: id,num: event.target.value});},del: function(id){// 把id传递给父组件this.$emit('cart-del', id);}}
}
  • 在父组件中进行监听
template: `<div class='cart'><cart-title :uname='uname'></cart-title><cart-list :list='list' @change-num='changeNum($event)' @cart-del='delCart($event)'></cart-list><cart-total :list='list'></cart-total></div>
`
  • 定义函数
methods: {changeNum: function(val) {// 根据子组件传递过来的数据,跟新list中对应的数据this.list.some(item=>{if(item.id == val.id) {item.num = val.num;// 终止遍历return true;}});},
}
  • 实现加或减更改数值
template: `<div><div :key='item.id' v-for='item in list' class="item"><img :src="item.img"/><div class="name">{{item.name}}</div><div class="change"><a href="" @click.prevent='sub(item.id)'>-</a><input type="text" class="num" :value='item.num' @blur='changeNum(item.id, $event)'/><a href="" @click.prevent='add(item.id)'>+</a></div><div class="del" @click='del(item.id)'>×</div></div></div>
`
sub: function(id){this.$emit('change-num', {id: id,type: 'sub'});
},
add: function(id){this.$emit('change-num', {id: id,type: 'add'});
},
  • 输入域变更加号变更减号变更进行判断
methods: {changeNum: function(val) {// 分为三种情况:输入域变更、加号变更、减号变更if(val.type=='change') {// 根据子组件传递过来的数据,跟新list中对应的数据this.list.some(item=>{if(item.id == val.id) {item.num = val.num;// 终止遍历return true;}});}else if(val.type=='sub'){// 减一操作this.list.some(item=>{if(item.id == val.id) {item.num -= 1;// 终止遍历return true;}});}else if(val.type=='add'){// 加一操作this.list.some(item=>{if(item.id == val.id) {item.num += 1;// 终止遍历return true;}});}}
}

整体代码

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Document</title><style type="text/css">.container {}.container .cart {width: 300px;margin: auto;}.container .title {background-color: lightblue;height: 40px;line-height: 40px;text-align: center;/*color: #fff;*/}.container .total {background-color: #FFCE46;height: 50px;line-height: 50px;text-align: right;}.container .total button {margin: 0 10px;background-color: #DC4C40;height: 35px;width: 80px;border: 0;}.container .total span {color: red;font-weight: bold;}.container .item {height: 55px;line-height: 55px;position: relative;border-top: 1px solid #ADD8E6;}.container .item img {width: 45px;height: 45px;margin: 5px;}.container .item .name {position: absolute;width: 90px;top: 0;left: 55px;font-size: 16px;}.container .item .change {width: 100px;position: absolute;top: 0;right: 50px;}.container .item .change a {font-size: 20px;width: 30px;text-decoration:none;background-color: lightgray;vertical-align: middle;}.container .item .change .num {width: 40px;height: 25px;}.container .item .del {position: absolute;top: 0;right: 0px;width: 40px;text-align: center;font-size: 40px;cursor: pointer;color: red;}.container .item .del:hover {background-color: orange;}</style>
</head>
<body>
<div id="app"><div class="container"><my-cart></my-cart></div>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">var CartTitle = {props: ['uname'],template: `<div class="title">{{uname}}的动物园拍卖会</div>`}var CartList = {props: ['list'],template: `<div><div :key='item.id' v-for='item in list' class="item"><img :src="item.img"/><div class="name">{{item.name}}</div><div class="change"><a href="" @click.prevent='sub(item.id)'>-</a><input type="text" class="num" :value='item.num' @blur='changeNum(item.id, $event)'/><a href="" @click.prevent='add(item.id)'>+</a></div><div class="del" @click='del(item.id)'>×</div></div></div>`,methods: {changeNum: function(id, event){this.$emit('change-num', {id: id,type: 'change',num: event.target.value});},sub: function(id){this.$emit('change-num', {id: id,type: 'sub'});},add: function(id){this.$emit('change-num', {id: id,type: 'add'});},del: function(id){// 把id传递给父组件this.$emit('cart-del', id);}}}var CartTotal = {props: ['list'],template: `<div class="total"><span>总价:{{total}}</span><button>结算</button></div>`,computed: {total: function() {// 计算商品的总价var t = 0;this.list.forEach(item => {t += item.price * item.num;});return t;}}}Vue.component('my-cart',{data: function() {return {uname: 'DG',list: [{id: 1,name: '熊猫',price: 1000,num: 1,img: 'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3726570454,3633557931&fm=26&gp=0.jpg'},{id: 2,name: '猴子',price: 1000,num: 1,img: 'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3524667055,2282983046&fm=26&gp=0.jpg'},{id: 3,name: '兔子',price: 1000,num: 1,img: 'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1173496453,597070384&fm=26&gp=0.jpg'},{id: 4,name: '老鼠',price: 1000,num: 1,img: 'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3570432866,2699104227&fm=26&gp=0.jpg'},{id: 5,name: '海豚',price: 1000,num: 2,img: 'https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=1113954919,3492262937&fm=26&gp=0.jpg'}]}},template: `<div class='cart'><cart-title :uname='uname'></cart-title><cart-list :list='list' @change-num='changeNum($event)' @cart-del='delCart($event)'></cart-list><cart-total :list='list'></cart-total></div>`,components: {'cart-title': CartTitle,'cart-list': CartList,'cart-total': CartTotal},methods: {changeNum: function(val) {// 分为三种情况:输入域变更、加号变更、减号变更if(val.type=='change') {// 根据子组件传递过来的数据,跟新list中对应的数据this.list.some(item=>{if(item.id == val.id) {item.num = val.num;// 终止遍历return true;}});}else if(val.type=='sub'){// 减一操作this.list.some(item=>{if(item.id == val.id) {item.num -= 1;// 终止遍历return true;}});}else if(val.type=='add'){// 加一操作this.list.some(item=>{if(item.id == val.id) {item.num += 1;// 终止遍历return true;}});}},delCart: function(id) {// 根据id删除list中对应的数据// 1、找到id所对应数据的索引var index = this.list.findIndex(item=>{return item.id == id;});// 2、根据索引删除对应数据this.list.splice(index, 1);}}});var vm = new Vue({el: '#app',data: {}});</script>
</body>
</html>

[Vue.js] 深入 -- 案例 - 购物车相关推荐

  1. Vue.js 实现简易购物车(商品的增加删除,价格的小计和总计)

    使用方法 : toFixed(2) 保留俩位小数 splice(index,howmany) 删除商品 index 规定添加删除的位置 ,howmany 删除几个 border-collapse: c ...

  2. [Vue.js] 基础 -- 案例之Tab选项卡

    实现效果 实现步骤 实现静态UI效果 用传统的方式实现标签结构和样式 基于数据重构UI效果 将静态的结构和样式重构为基于Vue模板语法的形式 处理事件绑定和js控制逻辑 声明式编程 模板的结构和最终显 ...

  3. (22)Vue.js 综合案例:TodoMVC

    一.TodoMVC介绍 TodoMVC 是一个经典项目,让开发者快速实践到框架开发方式. 官网地址:http://todomvc.com/ TodoMVC一句话评价:功能完备不冗余,多样实现引深思. ...

  4. Vue.js 入门案例

    理解MVVM模型 <!DOCTYPE html> <html lang="en"> <head><meta charset="U ...

  5. vue.js 入门案例,双向绑定实现任务清单

    vue.js 开发环境安装成功. http://localhost:8080/ 使用vue.js双向绑定实现类似这样一个任务清单页面. 下面是我的学习笔记. //app.vue页面 <templ ...

  6. Vue.js小案例(2)

    即时搜索 这个例子主要应用了vue.js的自定义过滤器,可以通过 Vue.filter() 注册一个全局过滤器,具体用法可以参考 这里,vue.js也提供了一些 内置过滤器. CSS代码: [v-cl ...

  7. Vue.js视频教程

    Vue.js 1.0 免费中文视频教程在线观看和网盘下载地址收集 原文地址:http://phpecshop.blog.51cto.com/6296699/1834208 NideShop:基于Nod ...

  8. Vue笔记:图书购物车案例

    BookShop案例: 一.搭建 使用了semantic-ui框架,搭建整个页面 <!DOCTYPE html> <html><head><meta char ...

  9. Vue第二天学习总结—— Vue全家桶之组件化开发(组件化开发思想、组件注册、Vue调试工具用法、组件间数据交互传递、组件插槽、基于组件的案例——购物车)

    (一) 组件化开发思想 1. 现实中的组件化思想体现 组件化即是对某些可以进行复用的功能进行封装的标准化工作 标准:要想组件能够成功组合在一起,每个组件必须要有标准 分治:将不同的功能封装到不同的组件 ...

最新文章

  1. Python20-Day02
  2. Kaggle心得(二)
  3. java 代码性能优化_Java代码性能优化(四)
  4. 总结开发Silverlight项目准则(转)
  5. 漫谈数据库索引 | 脚印 footprint(转载)
  6. volatile、const的用法
  7. linux 设置ssh免密登录
  8. C/C++编程语言中指针(pointer)介绍
  9. Android studio 老虎机小游戏
  10. R语言绘制韦布尔分布图和泊松(Poisson)分布图,并为二项分布(泊松分布)绘制不同颜色
  11. Photoshop CS6 破解安装
  12. 费马大定理四分之一解决
  13. Photon网络游戏开发——PUN2简介
  14. (据说是)鏼爷和吴凯路爷爷出的NOIP模拟神题集锦
  15. lineageos信号叉号_安卓手机刷lineageOS后电信卡不能通话解决办法
  16. 还不知道什么是分布式存储?赶紧来学习一下FusionStorage吧。
  17. 中企动力牵手七鑫易维 以眼球追踪技术剔除建站顽疾
  18. CPU 寄存器 和内存三者之间的关系
  19. BetaFlight深入传感设计之三:IMU传感模块
  20. 2019关于闪存芯片NAND FLASH的封装介绍

热门文章

  1. 源码安装mysql 5.1_Linux环境下源码编译安装MySQL5.1
  2. python 柱形图_Python 写入 Excel III 详解图形生成-柱形图
  3. SpringBoot+EHcache实现缓存
  4. 是谁干的 linux找嫌疑人
  5. python参数估计置信区间_python中分布参数的置信区间估计
  6. 信安教程第二版-第11章网络物理隔离技术原理与应用
  7. JAVA8的新特性之Stream
  8. Java基础---接口的使用
  9. ES6-symbol-使用symbol
  10. 小汤学编程之MySQL(二)——数据库操作、表结构操作、表数据操作、查询数据和数据类型