vuex mysql_vuex + koa + mysql实现购物车功能(一)
雙十一剛過去的你是不是又要開始準(zhǔn)備雙十二了呢?🤔談到購物就離不開購物車,那購物車功能如何實(shí)現(xiàn)呢?就小米商城購物車,我們來談一談
效果圖如下(基本是我們見過的購物車的效果):
動(dòng)手前思考
1.數(shù)據(jù)庫需要建兩個(gè)表:?所有商品表(cart),?購物車商品表(cartselected)
2.cart表: id(主鍵,自增),img,title,price,recommend
cartselected表:id(與cart表id關(guān)聯(lián)),img,title,price,recommend,num,checked(是否選中狀態(tài),只有0和1兩個(gè)值)
3.axios請(qǐng)求在actions中進(jìn)行,請(qǐng)求回來的數(shù)據(jù)放入state中,相關(guān)計(jì)算在getters中進(jìn)行
4.axios需要多次用到,可以進(jìn)行封裝
5.商品欄展示cart表數(shù)據(jù),購物車欄展示cartselected表數(shù)據(jù)
準(zhǔn)備工具
vscode
navicat
mysql
數(shù)據(jù)庫表結(jié)構(gòu)如下:
接下來讓我們一個(gè)一個(gè)功能分別實(shí)現(xiàn)吧!😀
實(shí)現(xiàn)功能
1.搭建后臺(tái)服務(wù)、連接mysql
// 配置數(shù)據(jù)庫連接
const config = {
database: {
DATEBASE: 'xiaomi',
USERNAME: 'root',
PASSWORD: '******',
PORT: '3306',
HOST: 'localhost'
}
}
// 創(chuàng)建連接池
var pool = mysql.createPool({
host: config.database.HOST,
user: config.database.USERNAME,
password: config.database.PASSWORD,
database: config.database.DATEBASE,
port: config.database.PORT
})
// 統(tǒng)一連接數(shù)據(jù)庫的方法
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() // 釋放連接池
})
}
})
})
}
}
復(fù)制代碼
連接成功后可以用postman,或者直接瀏覽器測(cè)試一下(這里就不測(cè)試?yán)?
2.細(xì)講每一個(gè)功能實(shí)現(xiàn)(按照sql語句 -> 后端接口 -> vuex -> 具體component方式)
隨機(jī)查詢
場(chǎng)景:當(dāng)購物車為空時(shí),頁面顯示20件商品,當(dāng)購物車有商品時(shí),則顯示10件商品
let findallgoods = function (num) { // 隨機(jī)查詢num數(shù)量的商品信息
let _sql = `select * from cart order by rand() limit ${num} ;`
return allServies.query(_sql)
}
復(fù)制代碼
后端路由:
router.post('/allcart', async (ctx, next) => {
let _num = ctx.request.body.num
await userService.findallgoods(_num).then((res) => {
ctx.body = {
data: res
}
})
})
復(fù)制代碼
前端訪問
data () {
return {
allcart: [] // 返問后拿到的數(shù)據(jù)
}
},
methods: {
requestGoods (nums) { // 請(qǐng)求接口返回?cái)?shù)據(jù)
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: { // 監(jiān)聽cart長(zhǎng)度從而判斷請(qǐng)求幾條數(shù)據(jù)(10條還是20條)
cart (newval, old) {
if (newval.length == 0 && old.length != 0) {
this.requestGoods(20)
} else {
this.requestGoods(10)
}
}
},
復(fù)制代碼
加入購物車及移出購物車
// 從購物車中查找某一件商品
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)
}
// 根據(jù)id刪除購物車某一件商品
let deletegoods = function (value) {
let _sql = `delete from cartselected where id=?`
return allServies.query(_sql, value)
}
復(fù)制代碼// 購物車所有商品
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
}
})
})
復(fù)制代碼
vuex 的actions:
getcart ({commit}, status) { // 獲取購物車表的數(shù)據(jù)
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'); // 再次請(qǐng)求購物車數(shù)據(jù)
} 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')
})
}
復(fù)制代碼
component:
addcart (id, title, price, recommend, img, num, checked) { // 點(diǎn)擊加入購物車
this.$store.dispatch('addcart', {id, title, price, recommend, img, num, checked})
},
deletecart (id) { // 刪除購物車的商品
this.$store.dispatch('deletecart', id)
}
復(fù)制代碼
增加減少數(shù)量
// 購物車數(shù)量增加
let _sql = `update cartselected set num=num+1 where id="${id}"`
// 購物車數(shù)量減少
let _sql = `update cartselected set num=num-1 where id="${id}" and num >= 2`
// num > 2是因?yàn)閿?shù)量不能減少到0復(fù)制代碼
后端接口
// 增加購物車某個(gè)商品數(shù)量
router.post('/addcartnum', async (ctx, next) => {})
// 減少購物車某個(gè)商品數(shù)量
router.post('/reducecartnum', async (ctx, next) => {})
復(fù)制代碼
vuex:
addcartnum ({dispatch}, params) {}) // 增加數(shù)量
reducecartnum ({dispatch}, params) {}) // 減少數(shù)量
復(fù)制代碼
component:
add (id) { // 增加商品數(shù)量
this.$store.dispatch('addcartnum', id)
},
reduce (id) { // 減少商品數(shù)量
this.$store.dispatch('reducecartnum', id)
}
復(fù)制代碼
全選與單選
// 設(shè)置全不選
let allfalse = function () {
let _sql = `update cartselected set checked=0`
return allServies.query(_sql)
}
// 設(shè)置全選
let alltrue = function () {
let _sql = `update cartselected set checked=1`
return allServies.query(_sql)
}
// 根據(jù)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)
}
復(fù)制代碼
后端接口:
// 設(shè)置全選
router.post('/alltrue', async (ctx, next) => {})
// 設(shè)置全不選
router.post('/allfalse', async (ctx, next) => {})
// 根據(jù)id切換該商品選中還是不選中
router.post('/singleselect', async (ctx, next) => {})
復(fù)制代碼
vuex:
allfalse ({dispatch}, status) {})
alltrue ({dispatch}, status) {})
singleselect ({dispatch}, status) {})
復(fù)制代碼
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
}
}
復(fù)制代碼
相關(guān)計(jì)算
getters
const getters = {
cart: state => state.cart,
littletotalPrice (state) { // 小計(jì)
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) { // 總計(jì)
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) { // 選中的數(shù)量
let selected = state.cart.filter(function(elem) {
return elem.checked == 1
})
return selected.length
},
totalnum (state) { // 商品數(shù)
let sum = 0
for (let i = 0; i < state.cart.length; i++) {
sum = sum + state.cart[i].num
}
return sum
}
}
復(fù)制代碼
這樣購物車功能及基本實(shí)現(xiàn)了(心里不免哀嘆一聲:好像都是在搬磚😪,有沒有更簡(jiǎn)單的方法呢?)
總結(jié)
每一個(gè)方法都要請(qǐng)求一次甚至更多次后端接口,對(duì)后端造成巨大壓力,由于對(duì)數(shù)據(jù)的操作大部分靠sql語句驅(qū)動(dòng),對(duì)于sql語句不熟練的同學(xué)就不太友好了,因此需要更好的方法來解決。
后續(xù)
下次我們將改善我們購物車功能的實(shí)現(xiàn),接口值訪問一次,功能全在vuex中實(shí)現(xiàn)
總結(jié)
以上是生活随笔為你收集整理的vuex mysql_vuex + koa + mysql实现购物车功能(一)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: wincc 报警记录 mysql_win
- 下一篇: linux cmake编译源码,linu