???作者簡(jiǎn)介:大家好,我是亦世凡華、渴望知識(shí)儲(chǔ)備自己的一名在校大學(xué)生
??個(gè)人主頁(yè):亦世凡華、
??系列專欄:uni-app
??座右銘:人生亦可燃燒,亦可腐敗,我愿燃燒,耗盡所有光芒。
??引言
?????????經(jīng)過web前端的學(xué)習(xí),相信大家對(duì)于前端開發(fā)有了一定深入的了解,今天我開設(shè)了uni-app專欄,主要想從移動(dòng)端開發(fā)方向進(jìn)一步發(fā)展,而對(duì)于我來說寫移動(dòng)端博文的第二站就是uni-app開發(fā),希望看到我文章的朋友能對(duì)你有所幫助。
目錄
商品列表界面
實(shí)現(xiàn)上拉加載和下拉刷新
商品詳情界面
實(shí)現(xiàn)輪播圖區(qū)域
實(shí)現(xiàn)商品信息區(qū)域
渲染商品導(dǎo)航區(qū)域
實(shí)現(xiàn)加入購(gòu)物車
購(gòu)物車界面
實(shí)現(xiàn)收貨地址區(qū)域
實(shí)現(xiàn)結(jié)算區(qū)域
商品列表界面
接下來實(shí)現(xiàn)商品列表界面,展現(xiàn)的是商品的圖片信息和價(jià)格,在分包的商品列表中進(jìn)行展示,通過在主頁(yè)和分類點(diǎn)擊的商品圖片傳遞的參數(shù),決定商品要展現(xiàn)的內(nèi)容,具體實(shí)現(xiàn)過程如下:
通過調(diào)用接口,將獲取到的數(shù)據(jù)轉(zhuǎn)存到data中進(jìn)行保存:
將獲取到的數(shù)據(jù)進(jìn)行v-for遍歷,渲染到頁(yè)面上如下:
給出如下樣式:
如果想設(shè)置價(jià)格存在小數(shù)點(diǎn),可以通過以下方式:
當(dāng)然如果后期如果寫很多類似這種界面的話,可以將item單獨(dú)抽離出組件, 將單獨(dú)抽離的組件存放到components組件當(dāng)中去,后期如何想調(diào)用這種組件進(jìn)行頁(yè)面渲染的話傳遞數(shù)據(jù)即可,如下:
<template>
<view class="goods-item">
<!-- 左側(cè)的盒子 -->
<view class="goods-item-left">
<image :src="item.goods_small_logo || defaultPic" class="goods-pic"></image>
</view>
<!-- 右側(cè)的盒子 -->
<view class="goods-item-right">
<!-- 商品名稱 -->
<view class="goods-name">{{item.goods_name}}</view>
<!-- 商品價(jià)格 -->
<view class="goods-info-box">
<view class="goods-price">¥{{item.goods_price}}</view>
</view>
</view>
</view>
</template>
<script>
export default {
name:"my-goods",
props:{
item:{
type:Object,
default:{}
}
},
data() {
return {
// 默認(rèn)的空?qǐng)D片
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-info-box{
.goods-price{
color: #c00000;
font-size: 16px;
}
}
}
}
</style>
自定義好my-goods組件之后,我們可以在goods-list組件中調(diào)用我們自定義的組件,通過props傳遞參數(shù)即可,如下:
實(shí)現(xiàn)上拉加載和下拉刷新
接下來實(shí)現(xiàn)商品列表的上拉加載更多的功能,當(dāng)頁(yè)面向下滑動(dòng)時(shí)觸發(fā)上拉觸底函數(shù),關(guān)系page頁(yè)數(shù),具體實(shí)現(xiàn)如下:
在項(xiàng)目的pages.json文件中,設(shè)置如下的上拉觸底的距離。
接下來調(diào)用頁(yè)面上拉觸底函數(shù)進(jìn)行頁(yè)碼值+1操作,并在調(diào)用接口賦值data數(shù)據(jù)時(shí),將原本數(shù)據(jù)和現(xiàn)在獲取到的數(shù)據(jù)進(jìn)行一個(gè)數(shù)組的拼接,如下:
因?yàn)樵谶M(jìn)行上來觸底的時(shí)候如果頻繁的進(jìn)行上拉下拉會(huì)導(dǎo)致頻繁的請(qǐng)求頁(yè)碼值加+1,所以要設(shè)置一個(gè)節(jié)流閥,在下一條數(shù)據(jù)加載完成后,才去調(diào)用上拉觸底函數(shù),現(xiàn)在好像這個(gè)bug修復(fù)了,我目前是不需要設(shè)置節(jié)流閥也能實(shí)現(xiàn)效果,但是如果遇到老項(xiàng)目還是需要設(shè)置節(jié)流閥的,這里簡(jiǎn)單提一下設(shè)置節(jié)流閥的過程思路,如下:
判斷數(shù)據(jù)是否加載完成,如果數(shù)據(jù)渲染完成,再次觸發(fā)上拉觸底函數(shù)時(shí),就讓page不再自增加1,如果下面的公式成立,則證明沒有下一頁(yè)數(shù)據(jù)了,如下:
當(dāng)前的頁(yè)碼值 * 每頁(yè)顯示多少條數(shù)據(jù) >= 總數(shù)條數(shù)
pagenum * pagesize >= total
修改上拉觸底函數(shù)如下:
接下來實(shí)現(xiàn)上拉刷新的效果,首先進(jìn)行如下配置:
設(shè)置下拉刷新函數(shù),需要重置數(shù)據(jù)如下:
接下來通過傳遞的參數(shù)設(shè)置調(diào)用阻止下拉刷新的函數(shù),如下:
接下來給goods_list設(shè)置點(diǎn)擊事件,進(jìn)行路由跳轉(zhuǎn)到詳情頁(yè)界面,如下:
商品詳情界面
接下來實(shí)現(xiàn)商品詳情,通過點(diǎn)擊頁(yè)面列表的商品數(shù)據(jù)從而跳轉(zhuǎn)到商品詳情界面,并傳遞相關(guān)query參數(shù)來標(biāo)識(shí)當(dāng)前商品詳情頁(yè)面代表的是哪個(gè)商品數(shù)據(jù),所以接下來通過調(diào)用get接口來獲取到當(dāng)前商品的相關(guān)數(shù)據(jù),如下:
實(shí)現(xiàn)輪播圖區(qū)域
接下來實(shí)現(xiàn)輪播圖區(qū)域的內(nèi)容,將我們get接口獲取到的相關(guān)圖片數(shù)據(jù)進(jìn)行輪播圖的實(shí)現(xiàn),如下:
實(shí)現(xiàn)商品信息區(qū)域
接下來實(shí)現(xiàn)商品的信息區(qū)域,定義如下的商品文字信息結(jié)構(gòu):
// 商品文字信息區(qū)域
.goods-info-box{
padding: 10px;
padding-right: 0;
// 商品價(jià)格
.price{
color: #c00000;
font-size: 18px;
margin: 10px 0;
}
// 商品信息主體區(qū)域
.goods-info-body{
display: flex;
justify-content: space-between;
// 商品名字
.goods_name{
font-size: 13px;
margin-right: 10px;
}
// 收藏
.favi{
width: 120px;
font-size: 12px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-left: 1px solid #efefef;
color: gray;
}
}
// 運(yùn)費(fèi)區(qū)域
.yf{
font-size: 12px;
color: gray;
margin: 10px 0;
}
}
接下來實(shí)現(xiàn)商品的圖文區(qū)域,使用uni-app的API來識(shí)別后端傳遞過來的html標(biāo)簽,如下:
渲染商品導(dǎo)航區(qū)域
接下來實(shí)現(xiàn)渲染商品的導(dǎo)航區(qū)域,這里使用的uni-app的一個(gè)插件需要自行下載,如下:
使用官方提供給我們的一個(gè)基礎(chǔ)案例,復(fù)制到項(xiàng)目代碼中,得到如下界面
接下來給其設(shè)置固定定位,使其固定在最下方:
因?yàn)槭枪潭ǘㄎ?,?huì)覆蓋掉頁(yè)面的一部分內(nèi)容,所以我們要設(shè)置內(nèi)容的下內(nèi)邊距為導(dǎo)航區(qū)域的高度
給導(dǎo)航區(qū)域設(shè)置點(diǎn)擊事件,當(dāng)點(diǎn)擊購(gòu)物車時(shí),跳轉(zhuǎn)到購(gòu)物車界面,如下:
實(shí)現(xiàn)加入購(gòu)物車
接下來實(shí)現(xiàn)商品詳情界面將商品添加到購(gòu)物車的功能,因?yàn)橛许?yè)面有好多都需要該數(shù)據(jù),所以可以設(shè)置將數(shù)據(jù)存放到store倉(cāng)庫(kù)里面,那么這里的話就需要使用vuex來進(jìn)行集中式狀態(tài)管理了,具體的實(shí)現(xiàn)過程如下:
首先先創(chuàng)建一個(gè)新的倉(cāng)庫(kù),作為存放整合各個(gè)數(shù)據(jù)和方法的容器:
import Vue from 'vue'
import Vuex from 'vuex'
import muduleCart from '@/store/cart.js'
Vue.use(Vuex)
const store = new Vuex.Store({
// 掛載 store 模塊
modules:{
'm_cart':muduleCart
}
})
export default store
將創(chuàng)建好的容器在main.js入口文件上進(jìn)行掛載到Vue實(shí)例上,如下:
在store文件夾下新建一個(gè)cart.js模塊,封裝方法來實(shí)現(xiàn)加入購(gòu)物車的功能,代碼如下:
export default {
namespaced:true,
state:()=>({
// 購(gòu)物車的數(shù)組,用來存放購(gòu)物車中每個(gè)商品的信息對(duì)象
cart:[]
}),
mutations:{
addToCart(state,goods){
// 根據(jù)提交的商品的Id,查詢購(gòu)物車中是否存在這件商品
// 如果不存在,則 findResult 為 undefined;否則,為查找到的商品信息對(duì)象
const findResult = state.cart.find(x=>x.goods_id === goods.goods_id)
if(!findResult){
// 如果購(gòu)物車中沒有這件商品,則直接 push
state.cart.push(goods)
}else{
// 如果購(gòu)物車中有這件商品,則只更新數(shù)量即可
findResult.goods_count++
}
}
},
getters:{
// 統(tǒng)計(jì)購(gòu)物車中商品的總數(shù)量
total(state){
let c = 0
state.cart.forEach(x => c += x.goods_count)
return c
}
}
}
給加入購(gòu)物車按鈕設(shè)置點(diǎn)擊事件,如下:
通過以下方法調(diào)用store中的數(shù)據(jù)
雖然我們點(diǎn)擊加入購(gòu)物車按鈕,購(gòu)物車會(huì)出現(xiàn)商品數(shù)量,但是我們一旦刷新編譯器的話數(shù)據(jù)就會(huì)消失,這里需要我們?cè)O(shè)置一下本地存儲(chǔ),如下:
開啟watch深度監(jiān)聽,一旦數(shù)據(jù)發(fā)生變化則立即調(diào)用
接下來處理購(gòu)物車數(shù)字徽標(biāo)的問題,當(dāng)點(diǎn)擊購(gòu)物車時(shí)跳轉(zhuǎn)到購(gòu)物車頁(yè)面,在購(gòu)物車頁(yè)面的tabBar處會(huì)出現(xiàn)你選中商品數(shù)量的一個(gè)徽標(biāo),因?yàn)檫@個(gè)徽標(biāo)不管你從哪個(gè)頁(yè)面點(diǎn)擊進(jìn)入,購(gòu)物車選中的數(shù)量是不會(huì)改變的,這里的話可以將設(shè)置徽標(biāo)的功能設(shè)置為mixins混入文件,如下:
購(gòu)物車界面
接下來實(shí)現(xiàn)購(gòu)物車界面,將vuex保存的狀態(tài)數(shù)據(jù)來渲染到購(gòu)物車界面,如下:
<template>
<view>
<!-- 商品列表的標(biāo)題區(qū)域 -->
<view class="cart-title">
<!-- 左側(cè)的圖標(biāo) -->
<uni-icons type="shop" size="18"></uni-icons>
<!-- 右側(cè)的文本 -->
<text class="cart-title-text">購(gòu)物車</text>
</view>
<!-- 循環(huán)渲染購(gòu)物車中的商品信息 -->
<block v-for="(item,index) in cart" :key="index">
<my-goods :item="item"></my-goods>
</block>
</view>
</template>
<script>
import badgeMix from '@/mixins/tabbar-badge.js'
import { mapState } from 'vuex'
export default {
computed:{
...mapState('m_cart',['cart'])
},
mixins:[badgeMix],
data() {
return {
};
},
}
</script>
<style lang="scss">
.cart-title{
height: 40px;
display: flex;
align-items: center;
padding-left: 5px;
border-bottom: 1px solid #EFEFEF;
.cart-title-text{
font-size: 14px;
margin-left: 10px;
}
}
</style>
完成購(gòu)物車商品列表的展示之后,我們需要在購(gòu)物車界面單獨(dú)渲染出一個(gè)單選框按鈕,這里的話可以通過props傳參來控制只有購(gòu)物車界面才出現(xiàn)單選框按鈕,實(shí)現(xiàn)過程如下:
界面實(shí)現(xiàn)如下:
接下來實(shí)現(xiàn)將單選框勾選的商品id和勾選狀態(tài)進(jìn)行vuex狀態(tài)管理并存儲(chǔ)在本地當(dāng)中,實(shí)現(xiàn)過程如下
父組件調(diào)用子組件的方法,并拿到當(dāng)前商品的id和狀態(tài):
在store中定義能更新狀態(tài)的方法,來根據(jù) goods_id 查詢購(gòu)物車中對(duì)應(yīng)商品的信息對(duì)象:
接下來實(shí)現(xiàn)數(shù)字輸入框的樣式,可以參看uni-app官網(wǎng)提供給我們的組件,這里就不再贅述,簡(jiǎn)單的說一下如何調(diào)用吧,和單選框功能實(shí)現(xiàn)基本一致,通過v-if來動(dòng)態(tài)的創(chuàng)建數(shù)字輸入框的顯示和隱藏,這里也一樣,如下:
通過在store中設(shè)置更新數(shù)量的函數(shù)并存儲(chǔ)在本地中
接下來實(shí)現(xiàn)滑動(dòng)刪除的功能,這里也是借用uni-app官網(wǎng)提供的一個(gè)組件,
在store中定義一個(gè)刪除的方法,如下:
通過mapMutations方法,將store中定義的方法映射出來,然后進(jìn)行傳遞參數(shù)即可。
實(shí)現(xiàn)收貨地址區(qū)域
接下來實(shí)現(xiàn)收獲地址區(qū)域的創(chuàng)建,收獲地址區(qū)域我們定義在components組件當(dāng)中去,然后設(shè)置相關(guān)樣式在購(gòu)物車頁(yè)面中調(diào)用該組件即可,如下:
接下來開始設(shè)置收獲地址組件的相關(guān)樣式,點(diǎn)擊增加地址組件的功能,是調(diào)用uni-app官方給我們提供的API,這里直接通過await使用即可,給出如下完整代碼:
<template>
<view>
<!-- 選擇收貨地址的盒子 -->
<view class="address-choose-box" v-if="JSON.stringify(address) === '{}'">
<button type="primary" size="mini" class="bunChooseAddress" @click="chooseAddress">請(qǐng)選擇收貨地址+</button>
</view>
<!-- 渲染收貨信息的盒子 -->
<view class="address-info-box" v-else>
<view class="row1">
<view class="row1-left">
<view class="username">收貨人:{{address.userName}}</view>
</view>
<view class="row1-right">
<view class="phone">電話:{{address.telNumber}}</view>
<uni-icons type="arrowright" size="16"></uni-icons>
</view>
</view>
<view class="row2">
<view class="row2-left">收貨地址:</view>
<view class="row2-right">{{addStr}}</view>
</view>
</view>
<!-- 底部的邊框線 -->
<image src="../../static/images/cart_border@2x.png" class="address-border"></image>
</view>
</template>
<script>
export default {
name:"my-address",
data() {
return {
// 收獲地址
address:{}
};
},
methods:{
async chooseAddress(){
const res = await uni.chooseAddress()
if(res.errMsg === "chooseAddress:ok"){
// 為data里面的收獲地址對(duì)象賦值
this.address = res
}
}
},
computed:{
addStr(){
if (!this.address.provinceName) return ''
// 拼接 省,市,區(qū),詳細(xì)地址 的字符串并返回給用戶
return this.address.provinceName + this.address.cityName + this.address.countyName + this.address.detailInfo
}
}
}
</script>
<style lang="scss">
.address-choose-box{
display: flex;
height: 90px;
justify-content: center;
align-items: center;
}
.address-border{
display: block;
width: 100%;
height: 5px;
}
// 渲染收貨信息的盒子
.address-info-box {
font-size: 12px;
height: 90px;
display: flex;
flex-direction: column;
justify-content: center;
padding: 0 5px;
// 第一行
.row1 {
display: flex;
justify-content: space-between;
.row1-right {
display: flex;
align-items: center;
.phone {
margin-right: 5px;
}
}
}
// 第二行
.row2 {
display: flex;
align-items: center;
margin-top: 10px;
.row2-left {
white-space: nowrap;
}
}
}
</style>
因?yàn)閿?shù)據(jù)是暫時(shí)性的,并沒有存儲(chǔ)到瀏覽器緩存中,一刷新界面數(shù)據(jù)就消失了,這里需要我們使用vuex進(jìn)行數(shù)據(jù)的狀態(tài)管理,如下:
在store文件夾中重新建一個(gè)user.js文件,用于存放收獲地址的數(shù)據(jù)和方法:
export default {
// 開啟命名空間
namespaced: true,
// state數(shù)據(jù)
state:()=>({
// 收獲地址
address:JSON.parse(uni.getStorageSync('address') || '{}'),
}),
// 方法
mutations:{
// 更新收獲地址
updateAddress(state,address){
state.address = address
this.commit('m_user/saveAddressToStorage')
},
// 持久化存儲(chǔ)address
saveAddressToStorage(state){
uni.setStorageSync('address',JSON.stringify(state.address))
}
},
// 數(shù)據(jù)包裝器
getters:{
addStr(state){
if (!state.address.provinceName) return ''
// 拼接 省,市,區(qū),詳細(xì)地址 的字符串并返回給用戶
return state.address.provinceName + state.address.cityName + state.address.countyName + state.address.detailInfo
}
},
}
在store.js文件中進(jìn)行掛載:
掛載完成之后,在收獲地址組件中進(jìn)行數(shù)據(jù)和方法的調(diào)用:
實(shí)現(xiàn)結(jié)算區(qū)域
接下來實(shí)現(xiàn)結(jié)算區(qū)域,需要在購(gòu)物車界面底部建立一個(gè)導(dǎo)航按鈕用于顯示購(gòu)買的價(jià)格,全選和結(jié)算按鈕的功能實(shí)現(xiàn),具體操作如下:
<template>
<view class="my-settle-container">
<!-- 全選 -->
<label class="radio" @click="changeAllState">
<radio color="#C00000" :checked="isFullChecked" /><text>全選</text>
</label>
<!-- 合計(jì) -->
<view class="amount-box">
合計(jì):<text class="amount">¥{{checkedGoodsAmount}}</text>
</view>
<!-- 結(jié)算按鈕 -->
<view class="btn-settle">結(jié)算({{checkedCount}})</view>
</view>
</template>
<script>
import { mapGetters,mapMutations } from 'vuex'
export default {
name:"my-settle",
data() {
return {
};
},
computed:{
...mapGetters('m_cart',['checkedCount','total','checkedGoodsAmount']),
isFullChecked(){
return this.total === this.checkedCount
}
},
methods:{
...mapMutations('m_cart',['updateAllGoodsState']),
changeAllState(){
this.updateAllGoodsState(!this.isFullChecked)
}
}
}
</script>
<style lang="scss">
.my-settle-container{
position: fixed;
z-index: 999;
bottom: 0;
left: 0;
width: 100%;
height: 60px;
background-color: white;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 14px;
padding-left: 5px;
.radio{
display: flex;
align-items: center;
}
.amount-box{
.amount{
color: #C00000;
font-weight: bold;
}
}
.btn-settle{
background-color: #C00000;
height: 60px;
color: white;
line-height: 60px;
padding: 0 10px;
min-width: 100px;
text-align: center;
}
}
</style>
在vuex中調(diào)用數(shù)據(jù)和方法,具體操作如下:
實(shí)現(xiàn)的功能為:
當(dāng)然如果購(gòu)物車界面一件商品都沒有的話,展示個(gè)圖片顯示無數(shù)據(jù)即可,這里使用v-if和v-else即可
文章來源:http://www.zghlxwxcb.cn/news/detail-441760.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-441760.html
到了這里,關(guān)于uni-app--》如何實(shí)現(xiàn)網(wǎng)上購(gòu)物小程序(中下)?的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!