日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > vue >内容正文

vue

uni-app 小程序项目三 1. 商品列表、过滤器、封装商品item组件、上拉加载、节流阀、下拉刷新、2. 商品详情、轮播图、商品价格闪烁问题 3.加入购物车、vuex、持久化存储、mixiins

發(fā)布時間:2024/1/8 vue 54 豆豆

1.0 創(chuàng)建 goodslist 分支

1.1 定義請求參數(shù)對象

  • 為了方便發(fā)起請求獲取商品列表的數(shù)據(jù),我們要根據(jù)接口的要求,事先定義一個請求參數(shù)對象:
  • data() {return {// 請求參數(shù)對象queryObj: {// 查詢關鍵詞query: '',// 商品分類Idcid: '',// 頁碼值pagenum: 1,// 每頁顯示多少條數(shù)據(jù)pagesize: 10}} }
  • 將頁面跳轉時攜帶的參數(shù),轉存到 queryObj 對象中:
  • onLoad(options) {// 將頁面參數(shù)轉存到 this.queryObj 對象中this.queryObj.query = options.query || ''this.queryObj.cid = options.cid || '' }
  • 為了方便開發(fā)商品分類頁面,建議大家通過微信開發(fā)者工具,新建商品列表頁面的編譯模式:
  • 1.2 獲取商品列表數(shù)據(jù)

  • 在 data 中新增如下的數(shù)據(jù)節(jié)點:
  • onLoad 生命周期函數(shù)中,調用 getGoodsList 方法獲取商品列表數(shù)據(jù):
  • 在 methods 節(jié)點中,聲明 getGoodsList 方法如下:
  • data() {return {// 商品列表的數(shù)據(jù)goodsList: [],// 總數(shù)量,用來實現(xiàn)分頁total: 0} }onLoad(options) {// 調用獲取商品列表數(shù)據(jù)的方法this.getGoodsList() }methods: {// 獲取商品列表數(shù)據(jù)的方法async getGoodsList() {// 發(fā)起請求const { data: res } = await uni.$http.get('/api/public/v1/goods/search', this.queryObj)if (res.meta.status !== 200) return uni.$showMsg()// 為數(shù)據(jù)賦值this.goodsList = res.message.goodsthis.total = res.message.total} }

    1.3 渲染商品列表結構

  • 在頁面中,通過 v-for 指令,循環(huán)渲染出商品的 UI 結構:(用到了 block 空白符)
  • 為了防止某些商品的圖片不存在,需要在 data 中定義一個默認的圖片、并在頁面渲染時按需使用:
  • 美化商品列表的 UI 結構:
  • <template><view><view class="goods-list"><block v-for="(goods, i) in goodsList" :key="i"><view class="goods-item"><!-- 商品左側圖片區(qū)域 --><view class="goods-item-left"> // 在這里使用兩個圖片做保險<image :src="goods.goods_small_logo || defaultPic" class="goods-pic"></image></view><!-- 商品右側信息區(qū)域 --><view class="goods-item-right"><!-- 商品標題 --><view class="goods-name">{{goods.goods_name}}</view><view class="goods-info-box"><!-- 商品價格 --><view class="goods-price">{{goods.goods_price}}</view></view></view></view></block></view></view> </template>data() {return {// 默認的空圖片defaultPic: 'https://img3.doubanio.com/f/movie/8dd0c794499fe925ae2ae89ee30cd225750457b4/pics/movie/celebrity-default-medium.png'} }.goods-item {display: flex;padding: 10px 5px;border-bottom: 1px solid #f0f0f0;.goods-item-left {margin-right: 5px;.goods-pic {width: 100px;height: 100px;display: block;}}.goods-item-right {display: flex;flex-direction: column;justify-content: space-between;.goods-name {font-size: 13px;}.goods-price {font-size: 16px;color: #c00000;}} }

    1.4 把商品 item 項封裝為自定義組件

  • components 目錄上鼠標右鍵,選擇 新建組件 my-goods: (沒有 components 文件夾就新建一個)
  • goods_list 頁面中,關于商品 item 項相關的 UI 結構、樣式、data 數(shù)據(jù),封裝到 my-goods 組件中:
  • <template><view class="goods-item"><!-- 商品左側圖片區(qū)域 --><view class="goods-item-left"><image :src="goods.goods_small_logo || defaultPic" class="goods-pic"></image></view><!-- 商品右側信息區(qū)域 --><view class="goods-item-right"><!-- 商品標題 --><view class="goods-name">{{goods.goods_name}}</view><view class="goods-info-box"><!-- 商品價格 --><view class="goods-price">{{goods.goods_price}}</view></view></view></view> </template><script>export default {// 定義 props 屬性,用來接收外界傳遞到當前組件的數(shù)據(jù)props: {// 商品的信息對象goods: {type: Object,defaul: {},},},data() {return {// 默認的空圖片defaultPic: 'https://img3.doubanio.com/f/movie/8dd0c794499fe925ae2ae89ee30cd225750457b4/pics/movie/celebrity-default-medium.png',}},} </script><style lang="scss">.goods-item {display: flex;padding: 10px 5px;border-bottom: 1px solid #f0f0f0;.goods-item-left {margin-right: 5px;.goods-pic {width: 100px;height: 100px;display: block;}}.goods-item-right {display: flex;flex-direction: column;justify-content: space-between;.goods-name {font-size: 13px;}.goods-price {font-size: 16px;color: #c00000;}}} </style>
  • 在 goods_list 組件中,循環(huán)渲染 my-goods 組件即可:
  • <view class="goods-list"><block v-for="(item, i) in goodsList" :key="i"><!-- 為 my-goods 組件動態(tài)綁定 goods 屬性的值 --><my-goods :goods="item"></my-goods></block> </view>

    1.5 使用過濾器處理價格

  • 在 my-goods 組件中,和 data 節(jié)點平級,聲明 filters 過濾器節(jié)點如下:
  • filters: {// 把數(shù)字處理為帶兩位小數(shù)點的數(shù)字tofixed(num) {return Number(num).toFixed(2)} }
  • 在渲染商品價格的時候,通過管道符 | 調用過濾器:
  • <!-- 商品價格 --> <view class="goods-price">{{goods.goods_price | tofixed}}</view>

    1.6 上拉加載更多

  • 打開項目根目錄中的 pages.json 配置文件,為 subPackages 分包中的 goods_list 頁面配置上拉觸底的距離:
  • "subPackages": [{"root": "subpkg","pages": [{"path": "goods_detail/goods_detail","style": {}},{"path": "goods_list/goods_list","style": {"onReachBottomDistance": 150 // 就這一行代碼}},{"path": "search/search","style": {}}]}]
  • goods_list 頁面中,和 methods 節(jié)點平級,聲明 onReachBottom 事件處理函數(shù),用來監(jiān)聽頁面的上拉觸底行為:
  • // 觸底的事件 onReachBottom() {// 讓頁碼值自增 +1this.queryObj.pagenum += 1// 重新獲取列表數(shù)據(jù)this.getGoodsList() }
  • 改造 methods 中的 getGoodsList 函數(shù),當列表數(shù)據(jù)請求成功之后,進行新舊數(shù)據(jù)的拼接處理:
  • // 獲取商品列表數(shù)據(jù)的方法 async getGoodsList() {// 發(fā)起請求const { data: res } = await uni.$http.get('/api/public/v1/goods/search', this.queryObj)if (res.meta.status !== 200) return uni.$showMsg()// 為數(shù)據(jù)賦值:通過展開運算符的形式,進行新舊數(shù)據(jù)的拼接this.goodsList = [...this.goodsList, ...res.message.goods]this.total = res.message.total }

    1.7 通過節(jié)流閥防止發(fā)起額外的請求

  • 在 data 中定義 isloading 節(jié)流閥如下:
  • data() {return {// 是否正在請求數(shù)據(jù)isloading: false} }
  • 修改 getGoodsList 方法,在請求數(shù)據(jù)前后,分別打開和關閉節(jié)流閥:
  • // 獲取商品列表數(shù)據(jù)的方法 async getGoodsList() {// ** 打開節(jié)流閥this.isloading = true// 發(fā)起請求const { data: res } = await uni.$http.get('/api/public/v1/goods/search', this.queryObj)// ** 關閉節(jié)流閥 這個 就放在 請求數(shù)據(jù)的 正 下面 ,this.isloading = false // 省略其它代碼... }
  • 在 onReachBottom 觸底事件處理函數(shù)中,根據(jù)節(jié)流閥的狀態(tài),來決定是否發(fā)起請求:
  • // 觸底的事件 onReachBottom() {// 判斷是否正在請求其它數(shù)據(jù),如果是,則不發(fā)起額外的請求if (this.isloading) returnthis.queryObj.pagenum += 1this.getGoodsList() }

    1.8 判斷數(shù)據(jù)是否加載完畢

  • 如果下面的公式成立,則證明沒有下一頁數(shù)據(jù)了:
  • 當前的頁碼值 * 每頁顯示多少條數(shù)據(jù) >= 總數(shù)條數(shù) pagenum * pagesize >= total
  • 修改 onReachBottom 事件處理函數(shù)如下:
  • // 觸底的事件 onReachBottom() {// 判斷是否還有下一頁數(shù)據(jù) 就這一行代碼if (this.queryObj.pagenum * this.queryObj.pagesize >= this.total) return uni.$showMsg('數(shù)據(jù)加載完畢!')// 判斷是否正在請求其它數(shù)據(jù),如果是,則不發(fā)起額外的請求if (this.isloading) returnthis.queryObj.pagenum += 1this.getGoodsList() }

    1.9 下拉刷新

  • pages.json 配置文件中,為當前的 goods_list 頁面單獨開啟下拉刷新效果:
  • "subPackages": [{"root": "subpkg","pages": [{"path": "goods_detail/goods_detail","style": {}}, {"path": "goods_list/goods_list","style": {"onReachBottomDistance": 150,"enablePullDownRefresh": true, // 就這 兩行"backgroundColor": "#F8F8F8" // 代碼}}, {"path": "search/search","style": {}}] }]
  • 監(jiān)聽頁面的 onPullDownRefresh 事件處理函數(shù):
  • // 下拉刷新的事件 onPullDownRefresh() {// 1. 重置關鍵數(shù)據(jù)this.queryObj.pagenum = 1this.total = 0this.isloading = falsethis.goodsList = []// 2. 重新發(fā)起請求 后面的回調函數(shù), 是關閉下路刷新的彈窗(這個只能手動關閉)this.getGoodsList(() => uni.stopPullDownRefresh()) }
  • 修改 getGoodsList 函數(shù),接收 cb 回調函數(shù)并按需進行調用:
  • // 獲取商品列表數(shù)據(jù)的方法 async getGoodsList(cb) {this.isloading = trueconst { data: res } = await uni.$http.get('/api/public/v1/goods/search', this.queryObj)this.isloading = false// 只要數(shù)據(jù)請求完畢,就立即按需調用 cb 回調函數(shù) (這個代碼是表示, 必須要有 cb 才會去執(zhí)行 cb() 這個回調函數(shù))cb && cb()if (res.meta.status !== 200) return uni.$showMsg()this.goodsList = [...this.goodsList, ...res.message.goods]this.total = res.message.total }

    1.20 點擊商品 item 項跳轉到詳情頁面

  • 將循環(huán)時的 block 組件修改為 view 組件,并綁定 click 點擊事件處理函數(shù):
  • <view class="goods-list"><view v-for="(item, i) in goodsList" :key="i" @click="gotoDetail(item)"><!-- 為 my-goods 組件動態(tài)綁定 goods 屬性的值 --><my-goods :goods="item"></my-goods></view> </view>
  • 在 methods 節(jié)點中,定義 gotoDetail 事件處理函數(shù):
  • // 點擊跳轉到商品詳情頁面 gotoDetail(item) {uni.navigateTo({url: '/subpkg/goods_detail/goods_detail?goods_id=' + item.goods_id}) }

    2.0 商品詳情

    2.1 添加商品詳情頁的編譯模式

  • 在微信開發(fā)者工具中,點擊工具欄上的編譯模式下拉菜單,選擇 添加編譯模式 選項:
  • 勾選 啟動頁面 的路徑,并填寫了 啟動參數(shù) 之后,點擊 確定 按鈕,添加詳情頁面的編譯模式:
  • 2.2 獲取商品詳情數(shù)據(jù)

  • 在 data 中定義商品詳情的數(shù)據(jù)節(jié)點:
  • data() {return {// 商品詳情對象goods_info: {}} }
  • 在 onLoad 中獲取商品的 Id,并調用請求商品詳情的方法:
  • onLoad(options) {// 獲取商品 Idconst goods_id = options.goods_id// 調用請求商品詳情數(shù)據(jù)的方法this.getGoodsDetail(goods_id) }
  • 在 methods 中聲明 getGoodsDetail 方法:
  • methods: {// 定義請求商品詳情數(shù)據(jù)的方法async getGoodsDetail(goods_id) {const { data: res } = await uni.$http.get('/api/public/v1/goods/detail', { goods_id })if (res.meta.status !== 200) return uni.$showMsg()// 為 data 中的數(shù)據(jù)賦值this.goods_info = res.message} }

    2.3 渲染商品詳情頁的 UI 結構

    2.31 渲染輪播圖區(qū)域

  • 使用 v-for 指令,循環(huán)渲染如下的輪播圖 UI 結構:
  • <!-- 輪播圖區(qū)域 --> <swiper :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000" :circular="true"><swiper-item v-for="(item, i) in goods_info.pics" :key="i"><image :src="item.pics_big"></image></swiper-item> </swiper>
  • 美化輪播圖的樣式:
  • swiper {height: 750rpx;image {width: 100%;height: 100%;} }

    2.32 實現(xiàn)輪播圖預覽效果

  • 為輪播圖中的 image 圖片綁定 click 事件處理函數(shù):
  • <swiper-item v-for="(item, i) in goods_info.pics" :key="i"><!-- 把當前點擊的圖片的索引,傳遞到 preview() 處理函數(shù)中 --><image :src="item.pics_big" @click="preview(i)"></image> </swiper-item>
  • 在 methods 中定義 preview 事件處理函數(shù):
  • // 實現(xiàn)輪播圖的預覽效果 preview(i) {// 調用 uni.previewImage() 方法預覽圖片uni.previewImage({// 預覽時,默認顯示圖片的索引current: i,// 所有圖片 url 地址的數(shù)組urls: this.goods_info.pics.map(x => x.pics_big)}) }

    2.33 渲染商品信息區(qū)域

  • 定義商品信息區(qū)域的 UI 結構如下:
  • <!-- 商品信息區(qū)域 --> <view class="goods-info-box"><!-- 商品價格 --><view class="price">{{goods_info.goods_price}}</view><!-- 信息主體區(qū)域 --><view class="goods-info-body"><!-- 商品名稱 --><view class="goods-name">{{goods_info.goods_name}}</view><!-- 收藏 --><view class="favi"><uni-icons type="star" size="18" color="gray"></uni-icons><text>收藏</text></view></view><!-- 運費 --><view class="yf">快遞:免運費</view> </view>
  • 美化商品信息區(qū)域的樣式:
  • // 商品信息區(qū)域的樣式 .goods-info-box {padding: 10px;padding-right: 0;.price {color: #c00000;font-size: 18px;margin: 10px 0;}.goods-info-body {display: flex;justify-content: space-between;.goods-name {font-size: 13px;padding-right: 10px;}// 收藏區(qū)域.favi {width: 120px;font-size: 12px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-left: 1px solid #efefef;color: gray;}}// 運費.yf {margin: 10px 0;font-size: 12px;color: gray;} }

    2.34 渲染商品詳情信息

  • 在頁面結構中,使用 rich-text 組件,將帶有 HTML 標簽的內容,渲染為小程序的頁面結構:
  • <!-- 商品詳情信息 --> <rich-text :nodes="goods_info.goods_introduce"></rich-text>
  • 修改 getGoodsDetail 方法,從而解決圖片底部 空白間隙 的問題:
  • // 定義請求商品詳情數(shù)據(jù)的方法 async getGoodsDetail(goods_id) {const { data: res } = await uni.$http.get('/api/public/v1/goods/detail', { goods_id })if (res.meta.status !== 200) return uni.$showMsg()// 使用字符串的 replace() 方法,為 img 標簽添加行內的 style 樣式,從而解決圖片底部空白間隙的問題res.message.goods_introduce = res.message.goods_introduce.replace(/<img /g, '<img style="display:block;" ')this.goods_info = res.message }
  • 解決 .webp 格式圖片在 ios 設備上無法正常顯示的問題:
  • // 定義請求商品詳情數(shù)據(jù)的方法 async getGoodsDetail(goods_id) {const { data: res } = await uni.$http.get('/api/public/v1/goods/detail', { goods_id })if (res.meta.status !== 200) return uni.$showMsg()// 使用字符串的 replace() 方法,將 webp 的后綴名替換為 jpg 的后綴名res.message.goods_introduce = res.message.goods_introduce.replace(/<img /g, '<img style="display:block;" ').replace(/webp/g, 'jpg')this.goods_info = res.message }

    3.35 解決商品價格閃爍的問題

  • 導致問題的原因:在商品詳情數(shù)據(jù)請求回來之前,data 中 goods_info 的值為 { },因此初次渲染頁面時,會導致 商品價格、商品名稱 等閃爍的問題。

  • 解決方案:判斷 goods_info.goods_name 屬性的值是否存在,從而使用 v-if 指令控制頁面的顯示與隱藏:

  • <template><view v-if="goods_info.goods_name"><!-- 省略其它代碼 --></view> </template>

    3.4 渲染詳情頁底部的商品導航區(qū)域

    3.41 渲染商品導航區(qū)域的 UI 結構

    基于 uni-ui 提供的 GoodsNav 組件來實現(xiàn)商品導航區(qū)域的效果

  • 在 data 中,通過 options 和 buttonGroup 兩個數(shù)組,來聲明商品導航組件的按鈕配置對象:
  • data() {return {// 商品詳情對象goods_info: {},// 左側按鈕組的配置對象options: [{icon: 'shop',text: '店鋪'}, {icon: 'cart',text: '購物車',info: 2}],// 右側按鈕組的配置對象buttonGroup: [{text: '加入購物車',backgroundColor: '#ff0000',color: '#fff'},{text: '立即購買',backgroundColor: '#ffa200',color: '#fff'}]} }
  • 在頁面中使用 uni-goods-nav 商品導航組件:
  • <!-- 商品導航組件 --> <view class="goods_nav"><!-- fill 控制右側按鈕的樣式 --><!-- options 左側按鈕的配置項 --><!-- buttonGroup 右側按鈕的配置項 --><!-- click 左側按鈕的點擊事件處理函數(shù) --><!-- buttonClick 右側按鈕的點擊事件處理函數(shù) --><uni-goods-nav :fill="true" :options="options" :buttonGroup="buttonGroup" @click="onClick" @buttonClick="buttonClick" /> </view>
  • 美化商品導航組件,使之固定在頁面最底部:
  • .goods-detail-container {// 給頁面外層的容器,添加 50px 的內padding,// 防止頁面內容被底部的商品導航組件遮蓋padding-bottom: 50px; }.goods_nav {// 為商品導航組件添加固定定位position: fixed;bottom: 0;left: 0;width: 100%; }

    3.4.2 點擊跳轉到購物車頁面

  • 點擊商品導航組件左側的按鈕,會觸發(fā) uni-goods-nav 的 @click 事件處理函數(shù),事件對象 e 中會包含當前點擊的按鈕相關的信息:
  • // 左側按鈕的點擊事件處理函數(shù) onClick(e) {console.log(e) }
  • 根據(jù) e.content.text 的值,來決定進一步的操作:
  • // 左側按鈕的點擊事件處理函數(shù) onClick(e) {if (e.content.text === '購物車') {// 切換到購物車頁面uni.switchTab({url: '/pages/cart/cart'})} }

    4.0 加入購物車

    4.1 配置 vuex

  • 在項目根目錄中創(chuàng)建 store 文件夾,專門用來存放 vuex 相關的模塊
  • 在 store 目錄上鼠標右鍵,選擇 新建 -> js文件,新建 store.js 文件:
  • 在 store.js 中按照如下 4 個步驟初始化 Store 的實例對象:
  • // 1. 導入 Vue 和 Vuex import Vue from 'vue' import Vuex from 'vuex'// 2. 將 Vuex 安裝為 Vue 的插件 Vue.use(Vuex)// 3. 創(chuàng)建 Store 的實例對象 const store = new Vuex.Store({// TODO:掛載 store 模塊modules: {}, })// 4. 向外共享 Store 的實例對象 export default store
  • 在 main.js 中導入 store 實例對象并掛載到 Vue 的實例上:
  • // 1. 導入 store 的實例對象 import store from './store/store.js'// 省略其它代碼...const app = new Vue({...App,// 2. 將 store 掛載到 Vue 實例上store, }) app.$mount()

    4.2 創(chuàng)建購物車的 store 模塊

  • 在 store 目錄上鼠標右鍵,選擇 新建 -> js文件,創(chuàng)建購物車的 store 模塊,命名為 cart.js:
  • 在 cart.js 中,初始化如下的 vuex 模塊:
  • export default {// 為當前模塊開啟命名空間namespaced: true,// 模塊的 state 數(shù)據(jù)state: () => ({// 購物車的數(shù)組,用來存儲購物車中每個商品的信息對象// 每個商品的信息對象,都包含如下 6 個屬性:// { goods_id, goods_name, goods_price, goods_count, goods_small_logo, goods_state }cart: [],}),// 模塊的 mutations 方法mutations: {},// 模塊的 getters 屬性getters: {}, }
  • store/store.js 模塊中,導入并掛載購物車的 vuex 模塊,示例代碼如下:
  • import Vue from 'vue' import Vuex from 'vuex' // 1. 導入購物車的 vuex 模塊 import moduleCart from './cart.js'Vue.use(Vuex)const store = new Vuex.Store({// TODO:掛載 store 模塊modules: {// 2. 掛載購物車的 vuex 模塊,模塊內成員的訪問路徑被調整為 m_cart,例如:// 購物車模塊中 cart 數(shù)組的訪問路徑是 m_cart/cartm_cart: moduleCart,}, })export default store

    4.3 在商品詳情頁中使用 Store 中的數(shù)據(jù)

  • 在 goods_detail.vue 頁面中,修改 標簽中的代碼如下:
  • // 從 vuex 中按需導出 mapState 輔助方法 import { mapState } from 'vuex'export default {computed: {// 調用 mapState 方法,把 m_cart 模塊中的 cart 數(shù)組映射到當前頁面中,作為計算屬性來使用// ...mapState('模塊的名稱', ['要映射的數(shù)據(jù)名稱1', '要映射的數(shù)據(jù)名稱2'])...mapState('m_cart', ['cart']),},// 省略其它代碼... }

    注意:今后無論映射 mutations 方法,還是 getters 屬性,還是 state 中的數(shù)據(jù),都需要指定模塊的名稱,才能進行映射。

  • 在頁面渲染時,可以直接使用映射過來的數(shù)據(jù),例如:
  • <!-- 運費 --> <view class="yf">快遞:免運費 -- {{cart.length}}</view>

    8.4 實現(xiàn)加入購物車的功能

  • 在 store 目錄下的 cart.js 模塊中,封裝一個將商品信息加入購物車的 mutations 方法,命名為 addToCart。示例代碼如下:
  • export default {// 為當前模塊開啟命名空間namespaced: true,// 模塊的 state 數(shù)據(jù)state: () => ({// 購物車的數(shù)組,用來存儲購物車中每個商品的信息對象// 每個商品的信息對象,都包含如下 6 個屬性:// { goods_id, goods_name, goods_price, goods_count, goods_small_logo, goods_state }cart: [],}),// 模塊的 mutations 方法mutations: {addToCart(state, goods) {// 根據(jù)提交的商品的Id,查詢購物車中是否存在這件商品// 如果不存在,則 findResult 為 undefined;否則,為查找到的商品信息對象const findResult = state.cart.find((x) => x.goods_id === goods.goods_id)if (!findResult) {// 如果購物車中沒有這件商品,則直接 pushstate.cart.push(goods)} else {// 如果購物車中有這件商品,則只更新數(shù)量即可findResult.goods_count++}},},// 模塊的 getters 屬性getters: {}, }
  • 在商品詳情頁面中,通過 mapMutations 這個輔助方法,把 vuex 中 m_cart 模塊下的 addToCart 方法映射到當前頁面:
  • // 按需導入 mapMutations 這個輔助方法 import { mapMutations } from 'vuex'export default {methods: {// 把 m_cart 模塊中的 addToCart 方法映射到當前頁面使用...mapMutations('m_cart', ['addToCart']),}, }
  • 為商品導航組件 uni-goods-nav 綁定 @buttonClick=“buttonClick” 事件處理函數(shù):
  • // 右側按鈕的點擊事件處理函數(shù) buttonClick(e) {// 1. 判斷是否點擊了 加入購物車 按鈕if (e.content.text === '加入購物車') {// 2. 組織一個商品的信息對象const goods = {goods_id: this.goods_info.goods_id, // 商品的Idgoods_name: this.goods_info.goods_name, // 商品的名稱goods_price: this.goods_info.goods_price, // 商品的價格goods_count: 1, // 商品的數(shù)量goods_small_logo: this.goods_info.goods_small_logo, // 商品的圖片goods_state: true // 商品的勾選狀態(tài)}// 3. 通過 this 調用映射過來的 addToCart 方法,把商品信息對象存儲到購物車中this.addToCart(goods)} }

    8.5 動態(tài)統(tǒng)計購物車中商品的總數(shù)量

  • 在 cart.js 模塊中,在 getters 節(jié)點下定義一個 total 方法,用來統(tǒng)計購物車中商品的總數(shù)量:
  • // 模塊的 getters 屬性 getters: {// 統(tǒng)計購物車中商品的總數(shù)量total(state) {let c = 0// 循環(huán)統(tǒng)計商品的數(shù)量,累加到變量 c 中state.cart.forEach(goods => c += goods.goods_count)return c} }
  • 在商品詳情頁面的 script 標簽中,按需導入 mapGetters 方法并進行使用:
  • // 按需導入 mapGetters 這個輔助方法 import { mapGetters } from 'vuex'export default {computed: {// 把 m_cart 模塊中名稱為 total 的 getter 映射到當前頁面中使用...mapGetters('m_cart', ['total']),}, }
  • 通過 watch 偵聽器,監(jiān)聽計算屬性 total 值的變化,從而動態(tài)為購物車按鈕的徽標賦值:
  • export default {watch: {// 1. 監(jiān)聽 total 值的變化,通過第一個形參得到變化后的新值total(newVal) {// 2. 通過數(shù)組的 find() 方法,找到購物車按鈕的配置對象const findResult = this.options.find((x) => x.text === '購物車')if (findResult) {// 3. 動態(tài)為購物車按鈕的 info 屬性賦值findResult.info = newVal}},}, }

    8.6 持久化存儲購物車中的商品

  • 在 cart.js 模塊中,聲明一個叫做 saveToStoragemutations 方法,此方法負責將購物車中的數(shù)據(jù)持久化存儲到本地:
  • // 將購物車中的數(shù)據(jù)持久化存儲到本地 saveToStorage(state) {uni.setStorageSync('cart', JSON.stringify(state.cart)) }
  • 修改 mutations 節(jié)點中的 addToCart 方法,在處理完商品信息后,調用步驟 1 中定義的 saveToStorage 方法:
  • addToCart(state, goods) {// 根據(jù)提交的商品的Id,查詢購物車中是否存在這件商品// 如果不存在,則 findResult 為 undefined;否則,為查找到的商品信息對象const findResult = state.cart.find(x => x.goods_id === goods.goods_id)if (!findResult) {// 如果購物車中沒有這件商品,則直接 pushstate.cart.push(goods)} else {// 如果購物車中有這件商品,則只更新數(shù)量即可findResult.goods_count++}// 通過 commit 方法,調用 m_cart 命名空間下的 saveToStorage 方法this.commit('m_cart/saveToStorage') }
  • 修改 cart.js 模塊中的 state 函數(shù),讀取本地存儲的購物車數(shù)據(jù),對 cart 數(shù)組進行初始化:
  • // 模塊的 state 數(shù)據(jù) state: () => ({// 購物車的數(shù)組,用來存儲購物車中每個商品的信息對象// 每個商品的信息對象,都包含如下 6 個屬性:// { goods_id, goods_name, goods_price, goods_count, goods_small_logo, goods_state }cart: JSON.parse(uni.getStorageSync('cart') || '[]') }),

    8.7 優(yōu)化商品詳情頁的 total 偵聽器

  • 使用普通函數(shù)的形式定義的 watch 偵聽器,在頁面首次加載后不會被調用。因此導致了商品詳情頁在首次加載完畢之后,不會將商品的總數(shù)量顯示到商品導航區(qū)域:
  • watch: {// 頁面首次加載完畢后,不會調用這個偵聽器total(newVal) {const findResult = this.options.find(x => x.text === '購物車')if (findResult) {findResult.info = newVal}} }
  • 為了防止這個上述問題,可以使用對象的形式來定義 watch 偵聽器(詳細文檔請參考 Vue 官方的 watch 偵聽器教程),示例代碼如下:
  • watch: {// 定義 total 偵聽器,指向一個配置對象total: {// handler 屬性用來定義偵聽器的 function 處理函數(shù)handler(newVal) {const findResult = this.options.find(x => x.text === '購物車')if (findResult) {findResult.info = newVal}},// immediate 屬性用來聲明此偵聽器,是否在頁面初次加載完畢后立即調用immediate: true} }

    8.8 動態(tài)為 tabBar 頁面設置數(shù)字徽標

    需求描述:從商品詳情頁面導航到購物車頁面之后,需要為 tabBar 中的購物車動態(tài)設置數(shù)字徽標。

  • 把 Store 中的 total 映射到 cart.vue 中使用:
  • // 按需導入 mapGetters 這個輔助方法 import { mapGetters } from 'vuex'export default {data() {return {}},computed: {// 將 m_cart 模塊中的 total 映射為當前頁面的計算屬性...mapGetters('m_cart', ['total']),}, }
  • 在頁面剛顯示出來的時候,立即調用 setBadge 方法,為 tabBar 設置數(shù)字徽標:
  • onShow() {// 在頁面剛展示的時候,設置數(shù)字徽標this.setBadge() }
  • 在 methods 節(jié)點中,聲明 setBadge 方法如下,通過 uni.setTabBarBadge() 為 tabBar 設置數(shù)字徽標:
  • methods: {setBadge() {// 調用 uni.setTabBarBadge() 方法,為購物車設置右上角的徽標uni.setTabBarBadge({index: 2, // 索引text: this.total + '' // 注意:text 的值必須是字符串,不能是數(shù)字})} }

    8.9 將設置 tabBar 徽標的代碼抽離為 mixins

    注意:除了要在 cart.vue 頁面中設置購物車的數(shù)字徽標,還需要在其它 3 個 tabBar 頁面中,為購物車設置數(shù)字徽標。

    此時可以使用 Vue 提供的 mixins 特性,提高代碼的可維護性。

  • 在項目根目錄中新建 mixins 文件夾,并在 mixins 文件夾之下新建 tabbar-badge.js 文件,用來把設置 tabBar 徽標的代碼封裝為一個 mixin 文件:
  • import { mapGetters } from 'vuex'// 導出一個 mixin 對象 export default {computed: {...mapGetters('m_cart', ['total']),},onShow() {// 在頁面剛展示的時候,設置數(shù)字徽標this.setBadge()},methods: {setBadge() {// 調用 uni.setTabBarBadge() 方法,為購物車設置右上角的徽標uni.setTabBarBadge({index: 2,text: this.total + '', // 注意:text 的值必須是字符串,不能是數(shù)字})},}, }
  • 修改 home.vue,cate.vue,cart.vue,my.vue 這 4 個 tabBar 頁面的源代碼,分別導入 @/mixins/tabbar-badge.js 模塊并進行使用:
  • // 導入自己封裝的 mixin 模塊 import badgeMix from '@/mixins/tabbar-badge.js'export default {// 將 badgeMix 混入到當前的頁面中進行使用mixins: [badgeMix],// 省略其它代碼... }

    總結

    以上是生活随笔為你收集整理的uni-app 小程序项目三 1. 商品列表、过滤器、封装商品item组件、上拉加载、节流阀、下拉刷新、2. 商品详情、轮播图、商品价格闪烁问题 3.加入购物车、vuex、持久化存储、mixiins的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。