前端Vue學(xué)習(xí)之購(gòu)物車項(xiàng)目實(shí)戰(zhàn)記錄
1. json-server,生成后端接口
全局安裝json-server,json-server官網(wǎng)為:json-server
npm install json-server -g // 全局安裝
安裝之后啟動(dòng)可能存在json-server與node版本不兼容導(dǎo)致的問(wèn)題,為此,建議指定一個(gè)json-sever版本。
需要準(zhǔn)備一個(gè)json文件,然后在json文件中寫入json數(shù)據(jù),利用json-server,就可以實(shí)現(xiàn)增刪改查功能。
{
"books":[
{"id":1,"bookName":"三國(guó)演義","price":23},
{"id":2,"bookName":"西游記","price":43},
{"id":3,"bookName":"水滸傳","price":33}
]
}
在這個(gè)json文件的目錄下執(zhí)行下述命令,


2. 購(gòu)物車項(xiàng)目 - 實(shí)現(xiàn)效果

就是更改對(duì)應(yīng)書本的購(gòu)買數(shù)量,下面顯示共計(jì)多少本書,以及需要多少錢實(shí)時(shí)更新。界面上構(gòu)建了兩個(gè)組件,分別為單個(gè)書本組件和下面總計(jì)組件。狀態(tài)控制使用vuex.store來(lái)進(jìn)行管理。
3. 參考代碼 - Vuex
使用模塊化對(duì)這個(gè)界面需要用到store進(jìn)行封裝,命名為books.js,代碼如下:
import axios from 'axios'
const state = {
books2:[]
};
const mutations = {
updateBooks(state,newBooks){
state.books2 = newBooks;
},
updateCount(state,obj){
const book = state.books2.find(item => item.id == obj.id);
book.count = obj.newCount;
}
};
const actions = {
async getBooks(context){
const res = await axios.get('http://localhost:3000/books');
context.commit('updateBooks',res.data);
},
async updateBooks(context,obj){
await axios.patch(`http://localhost:3000/books/${obj.id}`,{
count:obj.newCount
})
// 后臺(tái)修改數(shù)據(jù)
context.commit('updateCount',{
id:obj.id,
newCount:obj.newCount
});
// 前端頁(yè)面顯示
}
};
const getters = {
totalCount(state) {
return state.books2.reduce((sum, item) => sum + item.count,0);
},
totalPrice(state) {
return state.books2.reduce((sum, item) => sum + item.count * item.price,0);
}
};
export default {
namespaced:true,
state,
mutations,
actions,
getters
}在store目錄下index.js文件引入這個(gè)模塊即可。
import books from './modules/books'
export default new Vuex.Store({
...,
modules:{
books
}
})
App.vue代碼如下:
<template>
<div id="app">
<ul>
<li v-for="item in books2" :key="item.id" class="sp">
<Cart :item="item"></Cart>
</li>
</ul>
<TotalPrice class="total-price-position"></TotalPrice>
</div>
</template>
<script>
import {mapState} from 'vuex'
import Cart from './components/Cart.vue';
import TotalPrice from './components/TotalPrice.vue';
export default {
name: 'App',
components: {
Cart,TotalPrice
},
async created(){
this.$store.dispatch('books/getBooks');
},
computed:{
...mapState('books',['books2'])
}
}
</script>
<style lang="less" scoped>
#app{
position: relative;
width: 100%;
height: 700px;
.total-price-position{
position: absolute;
bottom: 0;
left: 0;
}
}
.sp{
height: 100px;
margin-top: 5px;
border-bottom: 1px solid yellow;
}
</style>
當(dāng)個(gè)書本組件代碼如下:Cart.vue
<template>
<div class="sp-item">
<!-- <img :src="require('@/static/'+item.bookName+'.png')" alt=""> -->
<img src="@/static/水滸傳.png" alt="">
<p class="sp-name">{{item.bookName}}</p>
<p class="sp-price">¥{{item.price}}</p>
<div class="sp-btn">
<button class="sp-l-btn" @click="btnClick(-1)">-</button>
<p class="sp-count">{{item.count}}</p>
<button class="sp-r-btn" @click="btnClick(1)">+</button>
</div>
</div>
</template>
<script>
export default {
name:'Cart',
props:{
item:Object
},
methods:{
btnClick(step){
const newCount = this.item.count + step;
const id = this.item.id;
if(newCount < 1)
return
this.$store.dispatch('books/updateBooks',{
id,
newCount
})
}
}
}
</script>
<style lang="less" scoped>
.sp-item{
width: 100%;
height: 100%;
position: relative;
>*{
position: absolute;
}
img{
width: 100px;
top: 50%;
left: 0;
transform: translateY(-50%);
}
.sp-name{
top: 6px;
left: 104px;
font-size: 18px;
}
.sp-price{
bottom: 4px;
left: 104px;
color: red;
font-weight: 600;
}
.sp-btn{
bottom: 4px;
right: 2px;
>*{
display: inline-block;
width: 20px;
height: 20px;
line-height: 20px;
text-align: center;
}
}
}
</style>
總計(jì)組件代碼如下:TotalPrice.vue
<template>
<div class="total-price-div">
<span class="z-span"></span>
共<span>{{totalCount}}</span>本,總共<span class="total-price">{{totalPrice}}</span>元
<button>結(jié)算</button>
</div>
</template>
<script>
import {mapGetters} from 'vuex';
export default {
name:"TotalPrice",
computed:{
...mapGetters('books',['totalCount','totalPrice'])
}
}
</script>
<style scoped lang="less">
.total-price-div{
height: 60px;
width: 100%;
line-height: 60px;
padding: 2px;
background-color: #e1dcdc;
}
.total-price{
color: red;
}
.z-span{
width: 146px;
display: inline-block;
}
button{
color: white;
background-color: green;
border-radius: 6px;
width: 60px;
height: 40px;
line-height: 40px;
}
</style>
項(xiàng)目中需要用到axios、less、vuex。
總結(jié)
到此這篇關(guān)于前端Vue學(xué)習(xí)之購(gòu)物車項(xiàng)目的文章就介紹到這了,更多相關(guān)前端Vue購(gòu)物車項(xiàng)目?jī)?nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 基于Vuejs實(shí)現(xiàn)購(gòu)物車功能
- Vue實(shí)現(xiàn)購(gòu)物車功能
- Vuejs實(shí)現(xiàn)購(gòu)物車功能
- vue實(shí)現(xiàn)商城購(gòu)物車功能
- vuex實(shí)現(xiàn)的簡(jiǎn)單購(gòu)物車功能示例
- Vue實(shí)現(xiàn)購(gòu)物車詳情頁(yè)面的方法
- vue實(shí)現(xiàn)購(gòu)物車小案例
- vue 實(shí)現(xiàn)購(gòu)物車總價(jià)計(jì)算
- vue.js實(shí)現(xiàn)簡(jiǎn)單購(gòu)物車功能
- vue實(shí)現(xiàn)購(gòu)物車功能(親測(cè)可用)
相關(guān)文章
vuex中使用對(duì)象展開(kāi)運(yùn)算符的示例
本篇文章主要介紹了vuex中使用對(duì)象展開(kāi)運(yùn)算符的示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09
vue實(shí)現(xiàn)簡(jiǎn)單的星級(jí)評(píng)分組件源碼
這篇文章主要介紹了vue星級(jí)評(píng)分組件源碼,代碼簡(jiǎn)單易懂非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-11-11
Vue2.0仿餓了么webapp單頁(yè)面應(yīng)用詳細(xì)步驟
本篇文章給大家分享了Vue2.0仿餓了么webapp單頁(yè)面應(yīng)用詳細(xì)步驟,有興趣的朋友可以跟著操作下。2018-07-07
vue?懸浮窗且?guī)ё詣?dòng)吸附功能實(shí)現(xiàn)demo
這篇文章主要為大家介紹了vue?懸浮窗且?guī)ё詣?dòng)吸附功能實(shí)現(xiàn)demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
基于Vue+ECharts實(shí)現(xiàn)地圖展示與交互
這篇文章中,我將逐步介紹如何使用 Vue 和 ECharts 實(shí)現(xiàn)一個(gè)互動(dòng)式的地圖展示組件,其中支持返回上一層地圖、點(diǎn)擊查看不同城市的詳細(xì)信息,以及根據(jù)數(shù)據(jù)動(dòng)態(tài)展示不同的統(tǒng)計(jì)信息,感興趣的小伙伴跟著小編一起來(lái)看看吧2025-02-02
vue.js實(shí)現(xiàn)點(diǎn)擊后動(dòng)態(tài)添加class及刪除同級(jí)class的實(shí)現(xiàn)代碼
這篇文章主要介紹了vue.js實(shí)現(xiàn)點(diǎn)擊后動(dòng)態(tài)添加class及刪除同級(jí)class的相關(guān)資料,需要的朋友可以參考下2018-04-04
Vue單頁(yè)及多頁(yè)應(yīng)用全局配置404頁(yè)面實(shí)踐記錄
無(wú)論單頁(yè)還是多頁(yè),我的實(shí)現(xiàn)思路是總體配置404頁(yè)面的思路就是在前端路由表中添加一個(gè) path: '/404' 的路由,渲染相應(yīng)的404頁(yè)面。這篇文章主要介紹了Vue單頁(yè)及多頁(yè)應(yīng)用全局配置404頁(yè)面實(shí)踐,需要的朋友可以參考下2018-05-05

