雙十一剛過去的你是否是又要開始準備雙十二了呢?🤔談到購物就離不開購物車,那購物車功能如何實現呢?就小米商城購物車,咱們來談一談
前端
效果圖以下(基本是咱們見過的購物車的效果): vue
1.數據庫須要建兩個表: 全部商品表(cart), 購物車商品表(cartselected)node
2.cart表: id(主鍵,自增),img,title,price,recommendmysql
cartselected表:id(與cart表id關聯),img,title,price,recommend,num,checked(是否選中狀態,只有0和1兩個值)ios
3.axios請求在actions中進行,請求回來的數據放入state中,相關計算在getters中進行sql
4.axios須要屢次用到,能夠進行封裝vuex
5.商品欄展現cart表數據,購物車欄展現cartselected表數據數據庫
// 配置數據庫鏈接
const config = {
database: {
DATEBASE: 'xiaomi',
USERNAME: 'root',
PASSWORD: '******',
PORT: '3306',
HOST: 'localhost'
}
}
// 建立鏈接池
var pool = mysql.createPool({
host: config.database.HOST,
user: config.database.USERNAME,
password: config.database.PASSWORD,
database: config.database.DATEBASE,
port: config.database.PORT
})
// 統一鏈接數據庫的方法
let allServies = {
query: function (sql, values) {
return new Promise((resolve, reject) => {
pool.getConnection(function (err, connection) {
if (err) {
reject(err)
} else {
connection.query(sql, values, (err, rows) => {
if (err) {
reject(err)
} else {
resolve(rows)
}
connection.release() // 釋放鏈接池
})
}
})
})
}
}
複製代碼
鏈接成功後能夠用postman,或者直接瀏覽器測試一下(這裏就不測試啦)axios
場景:當購物車爲空時,頁面顯示20件商品,當購物車有商品時,則顯示10件商品後端
let findallgoods = function (num) { // 隨機查詢num數量的商品信息
let _sql = `select * from cart order by rand() limit ${num} ;`
return allServies.query(_sql)
}
複製代碼
後端路由:
router.post('/allcart', async (ctx, next) => {
let _num = ctx.request.body.num
await userService.findallgoods(_num).then((res) => {
ctx.body = {
data: res
}
})
})
複製代碼
前端訪問
data () {
return {
allcart: [] // 返問後拿到的數據
}
},
methods: {
requestGoods (nums) { // 請求接口返回數據
axios({
url: 'http://localhost:3000/users/allcart',
method: 'post',
data: {
num: nums
}
}).then(res => {
this.allcart = res.data.data
}).catch(err => {
console.log(err)
})
}
},
watch: { // 監聽cart長度從而判斷請求幾條數據(10條仍是20條)
cart (newval, old) {
if (newval.length == 0 && old.length != 0) {
this.requestGoods(20)
} else {
this.requestGoods(10)
}
}
},
複製代碼
// 從購物車中查找某一件商品
let findcart = function (id) {
let _sql = `select * from cartselected where id="${id}";`
return allServies.query(_sql)
}
// 查找購物車全部商品
let findallcart = function () {
let _sql = `select * from cartselected;`
return allServies.query(_sql)
}
// 插入購物車(id, title, price, recommend, img, num, checked)
let insertgoods = function (value) {
let _sql = `insert into cartselected set id=?,title=?,price=?,recommend=?,img=?,num=?,checked=?`
return allServies.query(_sql, value)
}
// 根據id刪除購物車某一件商品
let deletegoods = function (value) {
let _sql = `delete from cartselected where id=?`
return allServies.query(_sql, value)
}
複製代碼
// 購物車全部商品
router.post('/allcarts', async (ctx, next) => {
await userService.findallcart().then((res) => {
ctx.body = {
data: res
}
})
})
// 加入購物車
router.post('/insertcart', async (ctx, next) => {
let _id = ctx.request.body.id
let _title = ctx.request.body.title
let _price = ctx.request.body.price
let _recommend = ctx.request.body.recommend
let _img = ctx.request.body.img
let _num = ctx.request.body.num
let _checked = ctx.request.body.checked
if (!_id) {
return
} else {
let cart = {
id: _id,
title: _title,
price: _price,
recommend: _recommend,
img: _img,
num: _num,
checked: _checked
}
await userService.findcart(cart.id).then(async (res) => {
if (res.length) {
try {
throw Error('購物車中已存在')
} catch (error) {
console.log(error)
}
ctx.body = {
code: '800003',
data: 'err',
mess: '購物車已存在該商品'
}
} else {
await userService.insertgoods([cart.id, cart.title, cart.price, cart.recommend, cart.img, cart.num, cart.checked]).then(async (res) => {
let r = ''
if (res.affectedRows !== 0) {
await userService.findcartgoods(cart.id).then((res1) => {
ctx.body = {
code: '800000',
data: res1,
mess: '增長購物車成功'
}
})
} else {
r = 'error'
ctx.body = {
code: '800004',
data: r,
mess: '增長購物車失敗'
}
}
})
}
})
}
})
// 刪除購物車某一件商品
router.post('/deletegood', async (ctx, next) => {
let _id = ctx.request.body.id
await userService.deletegoods(_id).then(res => {
ctx.body = {
code: '800000',
data: res,
mess: '刪除成功'
}
}).catch(err => {
ctx.body = {
code: '800002',
data: err
}
})
})
複製代碼
vuex 的actions:
getcart ({commit}, status) { // 獲取購物車表的數據
axios({
url: 'http://localhost:3000/users/allcarts',
method: 'post',
data: {}
}).then(res => {
commit('setcart', res.data.data) // commit方法給mutations,給state的cart賦值
}).catch(err => {
console.log(err)
})
},
addcart ({dispatch}, {id, title, price, recommend, img, num, checked}) { // 加入購物車
axios({
url: 'http://localhost:3000/users/insertcart',
method: 'post',
data: {
id: id,
title: title,
price: price,
recommend: recommend,
img: img,
num: num,
checked: checked
}
}).then(res => {
if (res.data.code === '800000') {
dispatch('getcart'); // 再次請求購物車數據
} else {
console.log('增長購物車失敗')
}
}).catch(err => {
console.log(err)
})
},
deletecart ({dispatch}, id) { // 刪除購物車某件商品
axios({
url: 'http://localhost:3000/users/deletegood',
method: 'post',
data: {
id: id
}
}).then (res => {
dispatch('getcart')
})
}
複製代碼
component:
addcart (id, title, price, recommend, img, num, checked) { // 點擊加入購物車
this.$store.dispatch('addcart', {id, title, price, recommend, img, num, checked})
},
deletecart (id) { // 刪除購物車的商品
this.$store.dispatch('deletecart', id)
}
複製代碼
// 購物車數量增長
let _sql = `update cartselected set num=num+1 where id="${id}"` // 購物車數量減小 let _sql = `update cartselected set num=num-1 where id="${id}" and num >= 2` // num > 2是由於數量不能減小到0 複製代碼
後端接口
// 增長購物車某個商品數量
router.post('/addcartnum', async (ctx, next) => {})
// 減小購物車某個商品數量
router.post('/reducecartnum', async (ctx, next) => {})
複製代碼
vuex:
addcartnum ({dispatch}, params) {}) // 增長數量
reducecartnum ({dispatch}, params) {}) // 減小數量
複製代碼
component:
add (id) { // 增長商品數量
this.$store.dispatch('addcartnum', id)
},
reduce (id) { // 減小商品數量
this.$store.dispatch('reducecartnum', id)
}
複製代碼
// 設置全不選
let allfalse = function () {
let _sql = `update cartselected set checked=0`
return allServies.query(_sql)
}
// 設置全選
let alltrue = function () {
let _sql = `update cartselected set checked=1`
return allServies.query(_sql)
}
// 根據id切換該商品選中仍是不選中
let singleselect = function (id) {
let _sql = `update cartselected set checked=(case when checked=0 then 1 else checked=0 end) where id="${id}"`
return allServies.query(_sql)
}
複製代碼
後端接口:
// 設置全選
router.post('/alltrue', async (ctx, next) => {})
// 設置全不選
router.post('/allfalse', async (ctx, next) => {})
// 根據id切換該商品選中仍是不選中
router.post('/singleselect', async (ctx, next) => {})
複製代碼
vuex:
allfalse ({dispatch}, status) {})
alltrue ({dispatch}, status) {})
singleselect ({dispatch}, status) {})
複製代碼
component
data () {
return {
allcheked: false //是否全選
}
},
methods: {
allselect () { // 全選
if (this.allcheked) {
this.$store.dispatch('allfalse')
} else {
this.$store.dispatch('alltrue')
}
},
singleselected (id) { // 單選
this.$store.dispatch('singleselect', id)
}
},
computed: {
...mapGetters([
'cart'
])
},
watch: {
cart: {
handler(newValue, oldValue) {
for (let i = 0; i < newValue.length; i++) {
console.log(newValue[i].checked)
if (newValue[i].checked == 0) {
this.allcheked = false
return
}
this.allcheked = true
}
},
deep: true
}
}
複製代碼
getters
const getters = {
cart: state => state.cart,
littletotalPrice (state) { // 小計
let money = []
if (state.cart.length != 0) {
state.cart.forEach((item) => {
console.log(item)
let price = item.price.substring(0, item.price.indexOf('元'))
money.push(price * item.num)
})
return money
} else {
return []
}
},
totalPrice (state) { // 總計
let selected = state.cart.filter(function(elem) {
return elem.checked == 1
})
let totalprice = 0
for (let i = 0; i < selected.length; i++) {
let price1 = selected[i].price.substring(0, selected[i].price.indexOf('元'))
let price2 = price1 * selected[i].num
totalprice += price2
}
return totalprice
},
selectednum (state) { // 選中的數量
let selected = state.cart.filter(function(elem) {
return elem.checked == 1
})
return selected.length
},
totalnum (state) { // 商品數
let sum = 0
for (let i = 0; i < state.cart.length; i++) {
sum = sum + state.cart[i].num
}
return sum
}
}
複製代碼
每個方法都要請求一次甚至更屢次後端接口,對後端形成巨大壓力,因爲對數據的操做大部分靠sql語句驅動,對於sql語句不熟練的同窗就不太友好了,所以須要更好的方法來解決。
下次咱們將改善咱們購物車功能的實現,接口值訪問一次,功能全在vuex中實現