经过几天vue框架的学习,综合基础知识做的一个购物车项目练习,整体项目的效果图如下:
上述效果图实现的功能有 数据绑定、物品的添加和删除、结算、商品数量输入等,以下为在此次项目练习中功能实现的问题。
一、使用vue.js渲染数据,布局可以优化很多代码,例如上面的推荐商品的表格的布局做法可以使用v-for来渲染,代码如下:
<table class="table">
<tr v-for='(item,index) in arr[0]'>
<td>
<a href="#">{{item.tradeName}}</a>
</td>
<td>¥{{item.originalCost}}</td>
<td>¥{{item.discountPrice}}</td>
<td>
<a href="#" @click="addTrade(item)">购买</a>
</td>
</tr>
</table>
渲染的数据都定义在js文件Vue的实例中的data里的arr二维数组中,代码如下:
data:{
arr:[
[{tradeName:'·JavaScript DOM编程艺术',originalCost:39.00,discountPrice:29.30},
{tradeName:'·解禁(当当网独家首发)',originalCost:28.00,discountPrice:19.40},
{tradeName:'·地王之王(金融危机下房地产行...',originalCost:32.80,discountPrice:25.10},
{tradeName:'·逃庄',originalCost:36.00,discountPrice:27.70,purchase:'购买' }],
[{tradeName:'·深入浅出MySQL数据库开发、优...',originalCost:59.00,discountPrice:47.20},
{tradeName:'·大玩家(马未都、王刚推荐!央...',originalCost:34.80,discountPrice:20.6},
{tradeName:'·都市风水师--官场风水小说:一...',originalCost:39.80,discountPrice:30.50},
{tradeName:'·国戏(以麻将术语解读宦海沉浮...',originalCost:25.00,discountPrice:17.30},],
[{tradeName:'私募(首部披露资本博弈秘密的金融...',integral:189,originalCost:32.00,discountPrice:18.90,discount:'59折',num:1},
{tradeName:'小团圆(张爱玲最神秘小说遗稿)',integral:173,originalCost:28.00,discountPrice:17.30,discount:'62折',num:1},
{tradeName:'不抱怨的世界(畅销全球80国的世界...',integral:154,originalCost:24.80,discountPrice:15.40,discount:'62折',num:1},
{tradeName:'福玛特双桶洗衣机XPB20-07S',integral:3580,originalCost:458.00,discountPrice:358.00,discount:'78折',num:1},
{tradeName:'PHP和MySQL Web开发 (原书第4版)',integral:712,originalCost:95.00,discountPrice:71.20,discount:'75折',num:1},
{tradeName:'法布尔昆虫记(再买¥68.30即可参加“满199元减10元现金”活动)',integral:1307,originalCost:198.00,discountPrice:130.70,discount:'66折',num:1},
],
],
bool:true,
up:'bootstrap/img/shopping_arrow_up.gif',
},
二.购买添加时同一物品的判断
购买添加物品呢主要就是利用数组的arr[2].push()方法。遇到的问题是,当我们的物品存在时,只添加数量,而不是添加新的物品。解决的方法是在点击购买的方法中把v-for循环中的item对象当作参数传回去,方法中声明一个布尔用来判断下面是否添加,利用循环判断,先循环第三个数组,在判断传过来的item.tradeName与第三个数组对象中的tradeName匹配,商品名相等则代表存在,即数量加1。否则在循环外面添加新的物品(即在第三个数组的末尾添加一个对象)示例代码如下:
//添加已选商品
addTrade(item){
var bool=true;//声明布尔变量用于判断和结束循环
for (i of this.arr[2]) {
if(item.tradeName==i.tradeName){//根据商品名称判断购买的商品是否已在购物车,如果已在购物车则数量+1
i.num++;//商品数量+1
bool=false;//结束循环
}
}
if(bool){
//声明变量接收折扣
var zk=Math.ceil(((item.discountPrice)/(item.originalCost)*100));//向上取整 折扣=折扣价/原价*100
//在数组末尾追加对象
this.arr[2].push({tradeName:item.tradeName,integral:(item.discountPrice)*10,originalCost:item.originalCost,discountPrice:item.discountPrice,discount:zk,num:1});
}
},
三、删除 根据索引删除物品
根据索引删除物品使用数组splice()方法,代码如下:
//根据下标删除商品
indexDelete(index){//根据传过来的下标删除商品
this.arr[2].splice(index,1);//删除arr[2]数组里的某个对象(商品)
},
四、商品的结算
结算的逻辑代码都在写在computed对象中,如下:
//计算属性
computed:{
//总积分=单品积分*单品数量
sumIntegral(){
var zjf=0;//总积分
for (i of this.arr[2]) {//循环arr二维数组里索引为2的数组 (循环购物车里的商品)
// zjf+=i.discountPrice*i.num;
zjf+=i.integral*i.num;//总积分+=单品积分*单品数量 (积分累加)
}
return zjf;//zjf*10 //返回总积分
},
//总节省金额=(市场价-折扣价)*单品数量
save(){
var jsje=0;//节省金额
for(i of this.arr[2]){//循环arr二维数组里索引为2的数组 (循环购物车里的商品)
jsje+=((i.originalCost)-(i.discountPrice))*i.num;//总节省金额+=(市场价-折扣价)*单品数量 (节省金额累加)
}
return jsje.toFixed(2);//返回总节省金额保留两位小数
},
//总金额=折扣价*单品数量
totalMoney(){
var zje=0;//总金额
for(i of this.arr[2]){//循环arr二维数组里索引为2的数组 (循环购物车里的商品)
zje+=(i.discountPrice)*i.num;//总金额+=折扣价*单品数量 (购物车商品金额累加)
}
return zje.toFixed(2);//返回总金额保留两位小数
}
}
下面为整个项目练习的代码
html代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>购物车管理</title>
<link rel="stylesheet" type="text/css" href="bootstrap/css/bootstrap.css"/>
<script src="../../js/vue.js"></script>
<!--兼容低版本浏览器-->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<link rel="stylesheet" type="text/css" href="bootstrap/css/index.css"/>
</head>
<body>
<div id="app">
<div class="container">
<div id="head">
<img src="bootstrap/img/shopping_myshopping.gif"/>
<a>全场免运费活动</a>
</div>
<div class="panel panel-default" >
<div class="panel-heading clearfix">根据您挑选的商品,当当为您推荐
<a href="#" class="pull-right">
<img v-bind:src="up" @click="show()"/>
</a>
</div>
<div class="panel-body caption" style="height: 179px;" v-show="bool">
<div class="panel-left pull-left panel panel-default">
<table class="table">
<tr v-for='(item,index) in arr[0]'>
<td>
<a href="#">{{item.tradeName}}</a>
</td>
<td>¥{{item.originalCost}}</td>
<td>¥{{item.discountPrice}}</td>
<td>
<a href="#" @click="addTrade(item)">购买</a>
</td>
</tr>
</table>
</div>
<div class="panel-center pull-left"><p></p></div>
<div class="panel-rigth pull-right panel panel-default">
<table class="table">
<tr v-for='(item,index) in arr[1]'>
<td>
<a href="#">{{item.tradeName}}</a>
</td>
<td>¥{{item.originalCost}}</td>
<td>¥{{item.discountPrice}}</td>
<td>
<a href="#" @click="addTrade(item)">购买</a>
</td>
</tr>
</table>
</div>
</div>
</div>
<!--已选购商品-->
<h4>您已选购以下商品</h4>
<div class="panel panel-default" id="selected">
<table class="table">
<tr>
<th>商品名</th>
<th>单品积分 </th>
<th>市场价 </th>
<th>当当价 </th>
<th>数量 </th>
<th>删除 </th>
</tr>
<tr v-for='(item,index) in arr[2]'>
<td>
<a href="#">{{item.tradeName}}</a>
</td>
<td>{{item.integral}}</td>
<td>¥{{item.originalCost}}</td>
<td>
<span>¥{{item.discountPrice}}</span>
<span>({{item.discount}}折)</span>
</td>
<td>
<input type="text" @blur="value(item)" v-model="item.num<=0?item.num=1:item.num"/>
</td>
<td>
<a href="#" @click="indexDelete(index)">删除</a>
</td>
</tr>
</table>
<div class="panel-footer clearfix">
<ul class=" pull-right">
<li class="pull-left">
您共节省:<span>¥{{save}}</span><br />
可获商品积分:<span>{{sumIntegral}}</span>
</li>
<li class="pull-left">
<strong>商品金额总计:<span>¥{{totalMoney}}</span></strong>
</li>
<li class="pull-left">
<img src="bootstrap/img/shopping_balance.gif"/>
</li>
</ul>
</div>
</div>
</div>
</div>
<script src="bootstrap/js/jquery.js" type="text/javascript" charset="utf-8"></script>
<script src="bootstrap/js/bootstrap.js" type="text/javascript" charset="utf-8"></script>
<script src="bootstrap/js/index.js" type="text/javascript" charset="utf-8"></script>
</body>
</html>
css样式如下:
*{list-style: none;}
#head{
line-height: 20px;
margin-top: 30px;
}
#head img{
vertical-align: initial;
margin-left: 20px;
}
#head a{
font-size: 10px;
}
.panel-heading{background: #FEFAEE!important;}
.panel-left{
width: 48%;
margin-bottom: 0px;
}
.panel-center{
width: 4%;
height: 100%;
margin-bottom: 0px;
}
.panel-left td:nth-child(2){
text-decoration: line-through;
color: #C0C0C0;
}
.panel-left td:last-child a{
color: darkorange;
}
.panel-rigth td:nth-child(2){
text-decoration: line-through;
color: #C0C0C0;
}
.panel-rigth td:last-child a{
color: darkorange;
}
.panel-rigth{
width: 48%;
margin-bottom: 0px;
}
.panel-center p{
width: 1px;
border-left: 1px dashed #CCCCCC;
margin: auto;
height: 100%;
}
#selected input{
width: 30px;
height: 20px;
text-align: center;
}
#selected tr:nth-child(1){
background: #D8E4C6;
}
#selected .panel-footer{
background: #D8E4C6;
}
#selected .panel-footer ul{
margin-bottom: 0px;
}
#selected .panel-footer li{
padding: 0px 10px;
}
#selected .panel-footer li span{
color: darkorange;
}
#selected .panel-footer li:nth-child(1){
border-right:1px solid ;
}
#selected .panel-footer li:nth-child(2){
line-height: 40px;
}
js代码如下:
var vm=new Vue({
el:'#app',
data:{
arr:[
[{tradeName:'·JavaScript DOM编程艺术',originalCost:39.00,discountPrice:29.30},
{tradeName:'·解禁(当当网独家首发)',originalCost:28.00,discountPrice:19.40},
{tradeName:'·地王之王(金融危机下房地产行...',originalCost:32.80,discountPrice:25.10},
{tradeName:'·逃庄',originalCost:36.00,discountPrice:27.70,purchase:'购买' }],
[{tradeName:'·深入浅出MySQL数据库开发、优...',originalCost:59.00,discountPrice:47.20},
{tradeName:'·大玩家(马未都、王刚推荐!央...',originalCost:34.80,discountPrice:20.6},
{tradeName:'·都市风水师--官场风水小说:一...',originalCost:39.80,discountPrice:30.50},
{tradeName:'·国戏(以麻将术语解读宦海沉浮...',originalCost:25.00,discountPrice:17.30},],
[{tradeName:'私募(首部披露资本博弈秘密的金融...',integral:189,originalCost:32.00,discountPrice:18.90,discount:'59折',num:1},
{tradeName:'小团圆(张爱玲最神秘小说遗稿)',integral:173,originalCost:28.00,discountPrice:17.30,discount:'62折',num:1},
{tradeName:'不抱怨的世界(畅销全球80国的世界...',integral:154,originalCost:24.80,discountPrice:15.40,discount:'62折',num:1},
{tradeName:'福玛特双桶洗衣机XPB20-07S',integral:3580,originalCost:458.00,discountPrice:358.00,discount:'78折',num:1},
{tradeName:'PHP和MySQL Web开发 (原书第4版)',integral:712,originalCost:95.00,discountPrice:71.20,discount:'75折',num:1},
{tradeName:'法布尔昆虫记(再买¥68.30即可参加“满199元减10元现金”活动)',integral:1307,originalCost:198.00,discountPrice:130.70,discount:'66折',num:1},
],
],
bool:true,
up:'bootstrap/img/shopping_arrow_up.gif',
},
//方法
methods:{
//隐藏和显示推荐商品
show(){//判断显示或隐藏,显示的则隐藏,隐藏则给它显示
if(this.up=='bootstrap/img/shopping_arrow_up.gif'){
this.up='bootstrap/img/shopping_arrow_down.gif';
this.bool=!this.bool;//取反为false 隐藏
}else{
this.up='bootstrap/img/shopping_arrow_up.gif';
this.bool=!this.bool;//取反为true 显示
}
},
//根据下标删除商品
indexDelete(index){//根据传过来的下标删除商品
this.arr[2].splice(index,1);//删除arr[2]数组里的某个对象(商品)
},
//添加已选商品
addTrade(item){
var bool=true;//声明布尔用于判断和结束循环
for (i of this.arr[2]) {
if(item.tradeName==i.tradeName){//根据商品名称判断购买的商品是否已在购物车,如果已在购物车则数量+1
i.num++;//商品数量+1
bool=false;//结束循环
}
}
if(bool){
//声明变量接收折扣
var zk=Math.ceil(((item.discountPrice)/(item.originalCost)*100));//向上取整 折扣=折扣价/原价*100
//在数组末尾追加对象
this.arr[2].push({tradeName:item.tradeName,integral:(item.discountPrice)*10,originalCost:item.originalCost,discountPrice:item.discountPrice,discount:zk,num:1});
}
},
//单品数量输入框
value(item){
var zz=/^[1-9][0-9]{0,}$/;//正则表达式 以1-9数字开头后面为0-9任意数字,位数不限
if(!zz.test(item.num)){//判断取反 如果传参过来的输入框的值不匹配正则表达式则输入框的值赋值为1
item.num=1;//传参对象的输入框的值赋值为1
}
}
},
//计算属性
computed:{
//总积分=单品积分*单品数量
sumIntegral(){
var zjf=0;//总积分
for (i of this.arr[2]) {//循环arr二维数组里索引为2的数组 (循环购物车里的商品)
// zjf+=i.discountPrice*i.num;
zjf+=i.integral*i.num;//总积分+=单品积分*单品数量 (积分累加)
}
return zjf;//zjf*10 //返回总积分
},
//总节省金额=(市场价-折扣价)*单品数量
save(){
var jsje=0;//节省金额
for(i of this.arr[2]){//循环arr二维数组里索引为2的数组 (循环购物车里的商品)
jsje+=((i.originalCost)-(i.discountPrice))*i.num;//总节省金额+=(市场价-折扣价)*单品数量 (节省金额累加)
}
return jsje.toFixed(2);//返回总节省金额保留两位小数
},
//总金额=折扣价*单品数量
totalMoney(){
var zje=0;//总金额
for(i of this.arr[2]){//循环arr二维数组里索引为2的数组 (循环购物车里的商品)
zje+=(i.discountPrice)*i.num;//总金额+=折扣价*单品数量 (购物车商品金额累加)
}
return zje.toFixed(2);//返回总金额保留两位小数
}
}
});