文章目錄
- 0.實現需求
- 1.新建購物車模塊cart
- 2.使用json-server模擬向后端請求數據
- 3.在vuex請求獲取并存入數據,并映射到組件中,在組件中渲染【重點】
- 3.1.安裝axios
- 3.2.準備actions和mutations,獲取和存入數據到vuex中
- 3.3.動態渲染:先用mapState映射list到組件頁面
- 4.點擊修改數量并同步前后端【重點】
- 4.1.要求和思路
- 4.2.代碼
- 5.使用getters完成總價和總數量數據的同步
- 5.1.先提供CartFooter.vue的結構和樣式
- 5.2.提供getters
- 5.3. 使用getters
- 其他
- 1.為什么在axios在項目中要局部安裝
- 2.Axios PATCH 方法的功能與使用
0.實現需求
- 請求動態渲染購物車,數據存放在vuex中
- 使用數字框修改數據
- 動態計算總價和總數量
購物車的商品數量,商品價格以及下方的總價,總數量,是共用一個數據,
顯然,此處可以用到vuex,這也是Vuex在Vue項目中常見的使用場景之一
1.新建購物車模塊cart
- step1:新建store/modules/cart.js
export default{namespaced:true,//state寫成這種形式的原因和data一樣:保證組件實例化后的數據獨立state(){//上面就不要const state={}了,會報錯return{list:[]}}
}
- step2:掛載到vuex倉庫上
import cart from "@/store/modules/cart"
const store = new Vue.Store({modules:{cart}
})
驗證配置是否成功:控制臺>vue>Root>cart>namespaced
2.使用json-server模擬向后端請求數據
- 安裝json-server
npm install json-server -g
- 準備json數據
在vue根目錄下創建db/db.json(數據可以讓deepseek模擬)
{"cart": [{"id": 1,"name": "Wireless Keyboard","price": 49.99,"count": 2,"thumb":"https://img14.360buyimg.com/n7/jfs/t1/141271/22/14881/70446/5fb4a985E1cce213e/beb55f6d1d3221b5.jpg"},{"id": 2,"name": "Gaming Mouse","price": 59.99,"count": 1,"thumb":"https://img14.360buyimg.com/n7/jfs/t1/141271/22/14881/70446/5fb4a985E1cce213e/beb55f6d1d3221b5.jpg"},{"id": 3,"name": "External Hard Drive","price": 89.99,"count": 1,"thumb":"https://img14.360buyimg.com/n7/jfs/t1/141271/22/14881/70446/5fb4a985E1cce213e/beb55f6d1d3221b5.jpg"},{"id": 4,"name": "Bluetooth Speaker","price": 79.99,"count": 1,"thumb":"https://img14.360buyimg.com/n7/jfs/t1/141271/22/14881/70446/5fb4a985E1cce213e/beb55f6d1d3221b5.jpg"},{"id": 5,"name": "Smartphone Case","price": 19.99,"count": 3,"thumb":"https://img14.360buyimg.com/n7/jfs/t1/141271/22/14881/70446/5fb4a985E1cce213e/beb55f6d1d3221b5.jpg"},{"id": 6,"name": "Laptop Backpack","price": 39.99,"count": 1,"thumb":"https://img14.360buyimg.com/n7/jfs/t1/141271/22/14881/70446/5fb4a985E1cce213e/beb55f6d1d3221b5.jpg"},{"id": 7,"name": "USB Flash Drive","price": 14.99,"count": 5,"thumb":"https://img14.360buyimg.com/n7/jfs/t1/141271/22/14881/70446/5fb4a985E1cce213e/beb55f6d1d3221b5.jpg"},{"id": 8,"name": "Headphones","price": 69.99,"count": 1,"thumb":"https://img14.360buyimg.com/n7/jfs/t1/141271/22/14881/70446/5fb4a985E1cce213e/beb55f6d1d3221b5.jpg"},{"id": 9,"name": "Monitor Stand","price": 29.99,"count": 1,"thumb":"https://img14.360buyimg.com/n7/jfs/t1/141271/22/14881/70446/5fb4a985E1cce213e/beb55f6d1d3221b5.jpg"},{"id": 10,"name": "Desk Lamp","price": 24.99,"count": 1,"thumb":"https://img14.360buyimg.com/n7/jfs/t1/141271/22/14881/70446/5fb4a985E1cce213e/beb55f6d1d3221b5.jpg"}],"friends": [{"userID": 101,"name": "Alice Johnson","age": 28},{"userID": 102,"name": "Bob Smith","age": 34},{"userID": 103,"name": "Charlie Brown","age": 22}]
}
- 啟動
在db目錄下打開CMD:
json-server db.json
踩坑:遇到了端口號被占用的報錯
\db>json-server db.json
node:internal/errors:478ErrorCaptureStackTrace(err);^
RangeError [ERR_SOCKET_BAD_PORT]: options.port should be >= 0 and < 65536.
解決方法:指定端口號:json-server db.json --port:3008
3.在vuex請求獲取并存入數據,并映射到組件中,在組件中渲染【重點】
3.1.安裝axios
全局安裝:npm install axios -g
局部安裝:npm installl axios --save
踩坑:錯誤地使用了全局安裝,導致在package.json中找不到axios依賴,也就調用不成功
3.2.準備actions和mutations,獲取和存入數據到vuex中
過程:actions使用axios發起異步get請求獲取數據,提交,觸發mutations中的函數,該函數更新state的狀態,
即:讓空數組list存放返回的數據(res.data)
state:{return{list:[]}
},
mutations:{updateList(state,newList){state.list=newList}
},
actions:{async getData(context){const res=await axios.get("http:localhost:3008/cart");console.log(res);//查看res的層級結構context.commit("updateList",res.data);//提交,觸發mutations中的方法}
}//在頁面中調用:App.vue
created(){//格式:$store.dispatch("模塊名/xxx")this.$store.dispatch("cart/getData")
}
3.3.動態渲染:先用mapState映射list到組件頁面
//App.vuecomputed: {...mapState("cart", ["list"]),}
此時list已經獲取后臺json文件中的cart數組中的數據作為其元素,并通過mapState映射到組件中,
因此組件可以直接使用list進行頁面渲染
//父組件App.vue
//使用v-for取出商品列表,但不在父組件直接渲染,而是設置自定義屬性item,通過父傳子,在子組件中渲染<div class="app-container"><cart-header></cart-header><cart-item v-for="item in list" :key="item.id" :item="item"></cart-item><cart-footer></cart-footer></div>
//子組件CartItem.vue
//html<div class="wrapper goods-container"><!-- 左側圖片 --><div class="left"><img :src="item.thumb" alt="" class="avatar"></div><!-- 右側商品描述 --><div class="right"><!-- 標題 --><div class="title">{{item.name}}</div><div class="info"><!-- 單價 --><div class="price">¥{{item.price}}</div><!-- 按鈕區域 --><div class="btns"><button class="btn btn-light" @click="btnClick(-1)">-</button><span class="count">{{item.count}}</span><button class="btn btn-light" @click="btnClick(1)">+</button></div></div></div></div>//js
//通過props屬性接收父組件傳過來的參數itemprops: {item:{type:Object,required:true}}//css(****不重要****)
.goods-container {display: flex;
}.left {flex: 1;padding: 10px;text-align: center;
}.right {flex: 2;padding: 10px;box-sizing: border-box;
}
.title {font-size: 16px;font-weight: bold;color: #333;margin-bottom: 10px;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;
}
.price {font-size: 18px;color: #e4393c; /* 常見紅色系表示優惠價 */margin-top: 5px;
}
.btns {margin-top: 15px;
}.btns button {display: inline-block;padding: 5px 10px;margin-right: 5px;font-size: 14px;cursor: pointer;border: none;border-radius: 3px;
}/* 不同類型的按鈕樣式 */
.btns .remove-btn {background-color: #ff4d4f;color: white;
}.btns .add-to-cart {background-color: #1abc9c;color: white;
}
效果:
4.點擊修改數量并同步前后端【重點】
4.1.要求和思路
點擊"+“和”-",實現數量的增減,要求不僅是vuex中的數據發生改變.后臺json文件中也會同步修改
思路:
-
按鈕綁定點擊事件,并傳參,點擊事件中會調用actions中的方法
-
actions中的方法主要做兩件事:
- 提交,觸發mutations方法以更新vuex狀態;
- 使用axios.patch向后臺發送請求,局部更新count屬性
-
mutations中的方法根據匹配到的id,更新對應的count
4.2.代碼
//CartItem.vue
//"+"和"-"按鈕綁定btnClick
methods:{btnClick(num){const newCount=num+this.list.count;if(newCount<1) return;//商品數量不能少于1(商品數量為0或者刪除商品的業務邏輯單獨實現)count newId=this.list.id//調用actions方法:updateCountAsyncthis.$store.dispatch("cart/updateCountAsync",{newId,newCount})}
}//cart.js
mutations:{updateList(state,obj){//通過傳回來的id找到對應的商品goodsconst goods=state.list.find(item==>item.id===obj.id);//更新這件商品的數量goods.count=obj.count;}
},
actions:{async updateCountAsync(context,obj){//更新后端數據const res=await axios.patch(`http://localhost:3008/cart/${obj.newId}`,{count:obj.newCount})console.log(res.data)//更新前端數據context.commit("updateList",{id:obj.newId,count:obj.newCount})}
}
效果:
- 點擊按鈕"+",商品數量隨之增加,控制臺
console.log(this.item.count)
同步更新 - 打開db.json文件,該商品的count屬性被更新
5.使用getters完成總價和總數量數據的同步
5.1.先提供CartFooter.vue的結構和樣式
如下:
<template><div class="footer-container"><!-- 中間的合計 --><div class="total-section"><span>共計xxx件商品,合計:</span><span class="price">¥xxx</span></div><!-- 右側結算按鈕 --><button class="btn btn-success btn-settle">結算</button></div>
</template><style scoped>
.footer-container {display: flex;justify-content: space-between;align-items: center;background-color: #f8f8f8;padding: 15px 20px;box-shadow: 0 -2px 5px rgba(0, 0, 0, 0.1);
}.total-section {font-size: 16px;color: #333;
}.total-section .price{font-size: 18px;color: #e60012; /* 使用醒目的顏色突出總價 */
}.btn-success {position: relative;display: inline-block;padding: 10px 20px;font-size: 16px;color: #ffffff;background-color: #e60012; /* 醒目紅色背景 */border: none;border-radius: 5px;cursor: pointer;transition: all 0.3s ease-in-out;
}.btn-success:hover {background-color: darken(#e60012, 10%); /* 懸停時加深背景色 */transform: scale(1.05); /* 增加懸停效果 */
}
</style>
5.2.提供getters
//格式:數組.reduce((求和參數,數組屬性)=>xxx,0);//從0開始累計getters:{totalNum(state){return state.list.reduce((sum,item)=>sum+item.count,0)},totalPrice(state){return state.list.reduce((sum,item)=>sum+item.count*item.price,0)}}
5.3. 使用getters
//CartFooter.vue
//html
...<span>共計{{totalNum}}件商品,合計:</span><span class="price">¥{{totalPrice}}</span>//jsimport {mapGetters} from "vuex"...computed: {//格式:...mapGetters("子模塊",['要映射的屬性'])...mapGetters('cart',['totalNum','totalPrice'])
},
最終效果:
其他
1.為什么在axios在項目中要局部安裝
1. 全局安裝與局部安裝的區別
當使用 npm install axios -g 進行全局安裝時,Axios 被放置在系統的全局環境中,而不是當前項目的 node_modules 文件夾中。這意味著全局安裝不會影響任何具體項目中的依賴列表,也不會更新該項目的 package.json 文件1。
因此,即使成功執行了 npm install axios -g,當前項目的 package.json 文件仍然不會有 axios 字段,這是預期行為而非錯誤。2. 導致模塊未找到的根本原因
Vue 項目運行時,默認只會查找位于當前項目目錄下的 node_modules 文件夾內的模塊。如果 Axios 是通過 -g 參數全局安裝的,則 Vue 構建工具(如 Webpack)無法識別該模塊,從而引發 Module not found: Error: Can't resolve 'axios' 錯誤33. 正確的解決方案
為了使 Axios 在項目中可用,應將其作為局部依賴安裝到當前項目中,而不是采用全局安裝的方式。以下是具體的解決步驟:
方法一:局部安裝 AXIOS 并保存到依賴項
執行以下命令將 Axios 安裝為項目的局部依賴,并自動更新 package.json 文件:
npm install axios --save
此操作會在 package.json 的 dependencies 字段中添加 Axios 條目,同時下載對應的模塊到 node_modules 文件夾中。對于像 Axios 這樣的庫,通常建議始終將其作為局部依賴安裝。這樣不僅可以確保不同項目間互不影響,還能更方便地管理版本沖突問題
2.Axios PATCH 方法的功能與使用
功能
axios.patch() 是一種用于向服務器發送部分修改的數據的方法。它通常用來更新資源的部分屬性,而不是替換整個資源。這種行為符合 RESTful API 設計原則中的“局部更新”概念
作用于后臺數據的能力
通過 axios.patch()
發送的請求會攜帶需要更新的具體字段及其新值,到指定 URL 上對應的資源。
服務器接收到這些數據后,會對目標資源執行相應的更新操作,并返回更新后的狀態或確認消息。
這種方式相比 PUT 更高效,因為它只傳輸變化的內容而非完整的對象
語法
axios.patch(url[, data[, config]])
- url: (字符串) 表示要訪問的目標地址。
- data: (可選, 對象或其他序列化類型) 要傳遞給服務器的信息體。
- config: (可選, 對象) 配置選項,比如超時時間、自定義頭部等。