vue.js (购物车项目练习)

vue.js 段金标
文章标签: vue.js

经过几天vue框架的学习,综合基础知识做的一个购物车项目练习,整体项目的效果图如下:

2.PNG

上述效果图实现的功能有 数据绑定、物品的添加和删除、结算、商品数量输入等,以下为在此次项目练习中功能实现的问题。

一、使用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);//返回总金额保留两位小数
		}
	}
	
});

还能输出{{restrictNumber}}个字符  
  • {{reply.author}}

    {{CommonUtil.formateDate(reply.ac_CommentDate).shortTime}}
  • 回复了{{Comments.author}} :