我用兩種方法構(gòu)建了購(gòu)物車頁(yè)面哮针,分別是jquery和vue。
1. 分析頁(yè)面邏輯
1.1 設(shè)計(jì)圖如下:
圖1:image.png
image.png
image.png
可以整理出功能有這些:
- 基礎(chǔ)的頁(yè)面渲染,將商品列表渲染到頁(yè)面上淤年,這步不贅述啦
- 點(diǎn)擊商品條目中的+,-號(hào):商品【數(shù)量增減】蜡豹,(且注意數(shù)量不能減為0)麸粮,下端總價(jià)和總數(shù)實(shí)時(shí)更新
- 點(diǎn)擊商品條目的input:* 商品【選中】,下端總價(jià)和總數(shù)實(shí)時(shí)更新镜廉,存儲(chǔ)選中的商品id弄诲;
(若有商品被選中,右下按鈕變色娇唯,可被點(diǎn)擊) - 點(diǎn)擊頁(yè)面圖1右上角【編輯】:右下角的下單按鈕變成刪除齐遵,進(jìn)入編輯狀態(tài)
- 點(diǎn)擊右下按鈕,【刪除】或【下單】:需設(shè)置狀態(tài)變量state塔插,判斷頁(yè)面是否處于編輯狀態(tài)梗摇,再調(diào)用相應(yīng)接口
1.2 終上所述,我們需要定義的全局變量有:
goods: [], //暫存接口返回的商品列表想许,用于渲染頁(yè)面
state: 0, //0:商品選擇狀態(tài)伶授,1:編輯狀態(tài)
selectIds: [], //被選中的商品id列表,用于傳給下單或刪除接口伸刃。
readyToOrder: 0, //有選中的商品谎砾,可以下單
totPrice: 0.00, //選中商品總價(jià)
totNum: 0 //選中商品總數(shù)
2. vue構(gòu)建方法
2.1 商品數(shù)量增減
這里用商品數(shù)量減少做例子,首先在html中用【v-on:click】(簡(jiǎn)寫成@click)屬性在-的div上綁定 minus()方法捧颅,并傳商品id進(jìn)函數(shù)景图。
如果對(duì)v-on事件處理不熟悉闊以點(diǎn)這里
<div class="good-num">
<div class="add" @click="add(good.id)">+</div>
<div class="num" goodId="">{{good.goodsNum}}</div>
<div class="minus" @click="minus(good.id)">-</div>
</div>
再來(lái)進(jìn)入js部分,我將minus方法的代碼分成前端后端兩部分碉哑。
前端部分即前端保存的商品列表中該商品數(shù)量的減少挚币,
后端部分即與后端交互,調(diào)用數(shù)量更新接口扣典,改動(dòng)數(shù)據(jù)庫(kù)中該用戶購(gòu)物車中該商品的數(shù)量妆毕。
/*
*商品數(shù)量減少
*/
minus(id) {
/* front-end */
var num = 0; //改后的數(shù)量
for(var i=0;i<this.goods.length;i++) {
if(this.goods[i].id == id) {
this.goods[i].goodsNum--;
this.totNum--;
this.totPrice -= this.goods[i].price;
num = this.goods[i].goodsNum;
}
}
/* back-end */
var numObject = {
id: id,
goodsNum: num
};
this.$http.post('/shoppingCart/shoppingCartUpdate', numObject).then(res => {
console.log(res);
}).catch(error => {
console.log(error);
});
},
未完待續(xù)嗷嗷.................
2.2
2.3
2.4
2.x 完整的【購(gòu)物車組件】代碼
<template>
<div id="purchasingShoppingCart">
<header>
<p>購(gòu)物車</p>
<div v-if="this.state==0"
class="edit"
@click="edit()">編輯
</div>
<div v-else class="edit"
@click="edit()">完成
</div>
</header>
<ul class="good-list">
<li v-for="(good,index) in goods" :key="index">
<label class="ql-ipt">
<input type="checkbox"
class="comman-ipt"
@click="select(good.id)"><i></i></input>
</label>
<a @click="toDetail(good.id)">
<img class="good-img"
v-bind:src="'http://120.78.133.190'+good.pic"></img>
<div class="good-info">
<p class="good-title">{{good.name}}</p>
<p class="good-detail">{{good.description}}</p>
<p class="good-price">¥{{good.price}}</p>
</div>
</a>
<div class="good-num-container">
<div class="good-num">
<div class="add" @click="add(good.id)">+</div>
<div class="num" goodId="">{{good.goodsNum}}</div>
<div class="minus" @click="minus(good.id)">-</div>
</div>
</div>
</li>
</ul>
<div class="bottom">
<!--label class="ql-ipt final-input">
<input type="checkbox" class="fin-ipt"><i></i></input>
</label-->
<p class="bottom-text">已選 ( <span class="bottom-span">{{totNum}}</span> )</p>
<p class="tot-price">¥<span class="bottom-price">{{totPrice}}</span></p>
<button v-if="this.state==0"
class="sub-btn"
v-bind:class="{ green: selectIds.length }"
@click="subOrDel()">下單
</button>
<button v-else
class="sub-btn"
v-bind:class="{ green: selectIds.length }"
@click="subOrDel()">刪除所選
</button>
</div>
</div>
</template>
<script>
import Vue from 'vue'
export default {
name: 'purchasingShoppingCart',
data () {
return {
goods: [],
state: 0, //0:選擇狀態(tài),1:編輯狀態(tài)
selectIds: [],
readyToOrder: 0, //有選中的商品贮尖,可以下單
totPrice: 0.00,
totNum: 0
}
},
created () {
/**
*請(qǐng)求購(gòu)物車列表
*/
var cartObject = {
"buyerId": 1
};
this.$http.post('/shoppingCart/shoppingCartList', cartObject).then(res => {
console.log(res);
this.goods = res.data.shoppingCartList;
// 為商品賦選中狀態(tài)初始值
this.goods.forEach(function(element) {
Vue.set(element,'selected',0);
});
}).catch(error => {
console.log(error);
});
},
methods: {
/*
*點(diǎn)擊購(gòu)物車條目跳轉(zhuǎn)至商品詳情
*/
toDetail(id) {
this.$router.push({
path: "/storeDetail",
query: {
goodId: id
}
})
},
/**
*選中一件商品
*/
select(id) {
var index = 0;
/* 記錄該商品在goods中的下標(biāo)*/
for(var i=0;i<this.goods.length;i++) {
if(this.goods[i].id == id) {
index = i;
}
}
/* 記錄selectIds */
if(this.goods[index].selected == 0) {
this.selectIds.push(id);
console.log(this.selectIds);
this.goods[index].selected = 1;
this.totNum += this.goods[index].goodsNum;
this.totPrice += this.goods[index].goodsNum * this.goods[index].price;
} else {
var j = this.selectIds.indexOf(id);
this.selectIds.splice(j, 1);
console.log(this.selectIds);
this.goods[index].selected = 0;
this.totNum -= this.goods[index].goodsNum;
this.totPrice -= this.goods[index].goodsNum * this.goods[index].price;
}
},
/*
*商品數(shù)量減少
*/
minus(id) {
/* front-end */
var num = 0; //改后的數(shù)量
for(var i=0;i<this.goods.length;i++) {
if(this.goods[i].id == id) {
this.goods[i].goodsNum--;
this.totNum--;
this.totPrice -= this.goods[i].price;
num = this.goods[i].goodsNum;
}
}
/* back-end */
var numObject = {
id: id,
goodsNum: num
};
this.$http.post('/shoppingCart/shoppingCartUpdate', numObject).then(res => {
console.log(res);
}).catch(error => {
console.log(error);
});
},
/*
*商品數(shù)量增加
*/
add(id) {
/* front-end */
var num = 0; //改后的數(shù)量
for(var i=0;i<this.goods.length;i++) {
if(this.goods[i].id == id) {
this.goods[i].goodsNum++;
this.totNum++;
this.totPrice += this.goods[i].price;
num = this.goods[i].goodsNum;
}
}
/* back-end */
var numObject = {
id: id,
goodsNum: num
};
this.$http.post('/shoppingCart/shoppingCartUpdate', numObject).then(res => {
console.log(res);
}).catch(error => {
console.log(error);
});
},
/**
*點(diǎn)擊編輯按鈕
*/
edit() {
/* 編輯/編輯完成 */
if(this.state == 0) {
this.state = 1;
} else {
this.state = 0;
}
},
/**
*底部按鈕
*刪除或下單
*/
subOrDel() {
var sidObject ={
ids: JSON.parse(JSON.stringify(this.selectIds).replace(/\"/g, ""))
};
if(this.state == 0) {
this.$http.post('/shoppingCart/placeOrder', sidObject).then(res => {
console.log(res);
//下單商品暫存
localStorage.setItem("goods",JSON.stringify(res.data.data));
localStorage.setItem("price",this,totPrice);
}).catch(error => {
console.log(error);
});
} else {
this.$http.post('/shoppingCart/shoppingCartRemove', sidObject).then(res => {
console.log(res);
}).catch(error => {
console.log(error);
});
}
/* 重新請(qǐng)求商品列表 */
var cartObject = {
"buyerId": 1
};
this.$http.post('/shoppingCart/shoppingCartList', cartObject).then(res => {
console.log(res);
this.goods = res.data.shoppingCartList;
// 為商品賦選中狀態(tài)初始值
this.goods.forEach(function(element) {
Vue.set(element,'selected',0);
});
/*
*局部刷新?
*清空input的記錄笛粘,恢復(fù)到一切都不選中的狀態(tài)
*總價(jià)總數(shù)恢復(fù)0
*
*/
this.$router.push({
path: "/purchasingOrder",
query: {
}
})
}).catch(error => {
console.log(error);
});
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
#purchasingShoppingCart {
background-color: #fafafa;
}
/* header */
header {
height:0.74rem;
width: 100%;
color: #ffffff;
position: fixed;
top:0;
font-size: 0.26rem;
z-index: 2; /*使fixed覆蓋在absolute上層,一直可見(jiàn)*/
background-color: #5f6d61;
}
header p {
text-align: center;
padding-top: 0.24rem;
}
.edit {
position: absolute;
right: 0;
top: 0.24rem;
right: 0.28rem;
}
/* 商品列表 */
.good-list {
width: 100%;
position: absolute;
top: 0.74rem;
background-color: #fafafa;
margin-bottom: 1.74rem;
}
.good-list li {
height: 1.96rem;
width: 100%;
background-color: #ffffff;
border-bottom: 0.02rem solid #dddddd;
margin-bottom: 0.12rem;
}
.good-img {
box-sizing: border-box;
height: 1.12rem;
width: 1.26rem;
position: absolute;
left: 0.70rem;
margin-top: 0.36rem;
border: 0.02rem solid #dddddd;
}
.good-info {
position: absolute;
left: 2.22rem;
margin-top: 0.36rem;
width: 2.50rem;
height: 1.12rem;
}
.good-title {
font-size: 0.24rem;
position: absolute;
top: 0;
margin-bottom: 0.14rem;
}
.good-detail{
color: #cccccc;
font-size: 0.16rem;
position: absolute;
top: 0.45rem;
}
.good-price {
color: #e51a19;
font-size: 0.16rem;
position: absolute;
bottom: 0;
}
.good-num-container {
position: absolute;
right: 0.44rem;
margin-top: 0.36rem;
width: 1.3rem;
height: 1.12rem;
}
.good-num {
box-sizing: border-box;
width: 1.20rem;
height:0.30rem;
position: absolute;
bottom: 0;
margin-top: 1.22rem;
border: 0.01rem solid #8e8561;
text-align: center;
}
.add {
position: absolute;
right: 0;
width: 0.36rem;
}
.add span {
color: #8e8561;
font-size: 0.28rem;
position: absolute;
bottom: -0.32rem;
right:0.08rem;
text-align: center;
}
.num {
height:0.28rem;
box-sizing: border-box;
position: absolute;
right: 0.36rem;
border-left: 0.01rem solid #8e8561;
border-right: 0.01rem solid #8e8561;
width: 0.48rem;
}
.minus {
position: absolute;
right: 0.84rem;
width: 0.36rem;
}
.minus span {
color: #8e8561;
font-size: 0.28rem;
position: absolute;
bottom: -0.32rem;
right:0.10rem;
text-align: center;
}
/* input */
.ql-ipt input[type='radio'] + i, input[type='checkbox'] + i {
position: absolute;
left: 0.18rem;
margin-top: 0.72rem;
}
.ql-ipt input[type='radio']:checked + i,
input[type='checkbox']:checked + i {
/* background-color: #8e8561;; */
background-position: 0 0;
}
.final-input input[type='checkbox'] + i {
margin-top: 0.38rem;
}
/* bottom part 即下單處 */
.bottom {
height: 1.06rem;
width: 100%;
border-top: 0.02rem solid #dddddd;
position: fixed;
bottom: 0rem;
background-color: #ffffff;
}
.bottom-text {
position: absolute;
left: 0.70rem;
margin-top: 0.40rem;
font-size: 0.26rem;
}
.bottom-text span {
font-size: 0.26rem;
}
.tot-price {
margin-top: 0.40rem;
position: absolute;
right: 2.00rem;
color: #e51a19;
}
.sub-btn {
width: 1.76rem;
height: 1.06rem;
background-color: #dee2de; /*#8e8561*/
border: none;
position: absolute;
right: 0;
color: #ffffff;
font-size: 0.24rem;
}
.green {
background-color: #8e8561;
}
/* 字體大小 */
.cd-f1 {
font-size: 0.32rem; /* 32/640 */
}
.cd-f2 {
font-size: 0.3rem; /* 30/640 */
}
.cd-f3 {
font-size: 0.28rem; /* 28/640 */
}
.cd-f4 {
font-size: 0.26rem; /* 26/640 */
}
.cd-f5 {
font-size: 0.24rem; /* 24/640 */
}
.cd-f6 {
font-size: 0.22rem; /* 22/640 */
}
.cd-fmin {
font-size: 0.20rem;
}
/* 顏色 */
.answer-right {
background-color: #003814;
}
.answer-wrong {
background-color: #570100;
}
.answer-no-choice {
background-color: #929292;
}
.color-base {
color: #bfa355;
}
/* button */
.ql-btn {
display: block;
width: 1.46rem;
height: 0.44rem;
line-height: 0.44rem;
font-size: 0.24rem;
margin-left: 0.4rem;
text-align: center;
border-radius: 0.04rem;
/* border: 0.01rem solid #f2f2f2; */
background-color: transparent;
border: none;
outline: none;
}
.ql-btn:focus {
color: #adaaaa;
}
.ql-btn-default {
color: #fff;
border: none;
/* background-color: #bfa355; */
background-color: #564932;
}
/* radio & checkbox */
.ql-ipt input[type='radio'], .ql-ipt input[type='checkbox'] {
position: absolute;
left: -555em;
}
.ql-ipt input[type='radio'] + i, .ql-ipt input[type='checkbox'] + i {
display: inline;
float: left;
width: 0.38rem;
height: 0.38rem;
background: url('../../assets/images/icon_input.png') no-repeat;
background-size: auto 0.38rem;
background-position: -0.39rem 0;
}
.ql-ipt input[type='radio']:checked + i,
.ql-ipt input[type='checkbox']:checked + i {
/* background-color: #8e8561;; */
background-position: 0 0;
}
</style>