Notas Prácticas del Proyecto UNIAPP 68 Verificación del carrito de compras para confirmar el pedido
Ideas
Necesita usar vuex
para pasar valores entre páginas
Captura de pantalla del caso
Página de liquidación de pedidos
Página de carrito de compras Página
de confirmación de pedido
Página de pago
código
Página del carrito de compras del código frontal shopcart.vue
<template>
<view class="shop-cart">
<template v-if=" list.length > 0 ">
<!-- 自定义导航栏 -->
<uniNavBar
title="购物车"
:rightText=" isNavBar ? '完成' : '编辑'"
fixed="true"
statusBar="true"
@clickRight=" isNavBar = !isNavBar"
></uniNavBar>
<!-- 商品内容 -->
<view class="shop-item" v-for="(item,index) in list" :key="index">
<label for="" class="radio" @tap="selectedItem(index)">
<radio value="" color="#FF3333" :checked="item.checked" /> <text></text>
</label>
<image class="shop-img" :src="item.imgUrl" mode=""></image>
<view class="shop-text">
<view class="shop-name">
{
{
item.name}}
</view>
<view class="shop-color f-color">
{
{
item.color}}
</view>
<view class="shop-price">
<view class="">
¥{
{
item.pprice}}
</view>
<template v-if="!isNavBar">
<view>x {
{
item.num}}</view>
</template>
<template v-else>
<uniNumberBox
:value="item.num"
:min=1
@change="changeNumber($event,index,item)"
></uniNumberBox>
</template>
</view>
</view>
</view>
<!-- 底部 -->
<view class="shop-foot">
<label for="" class="radio foot-radio" @tap='checkedAllFn'>
<radio value="" color="#FF3333" :checked="checkedAll"></radio><text>全选</text>
</label>
<template v-if="!isNavBar">
<view class="foot-total">
<view class="foot-count">
合计:
<text class="f-active-color">
¥{
{
totalCount.pprice}}
</text>
</view>
<view class="foot-num" @tap="goConfirmOrder">
结算({
{
totalCount.num}})
</view>
</view>
</template>
<template v-else>
<view class="foot-total">
<view class="foot-num" style="background-color: black;">
移入收藏夹
</view>
<view class="foot-num" @tap="delGoodsFn">
删除
</view>
</view>
</template>
</view>
</template>
<template v-else>
<uniNavBar
title="购物车"
fixed="true"
statusBar="true"
></uniNavBar>
<view class="shop-else-list">
<text>囧~ 购物车还是空的~</text>
</view>
</template>
<Tabbar currentPage='shopcart'></Tabbar>
</view>
</template>
<script>
import $http from '@/common/api/request.js'
import uniNavBar from '@/components/uni/uni-nav-bar/uni-nav-bar.vue'
import uniNumberBox from '@/components/uni/uni-number-box/uni-number-box.vue'
import Tabbar from '@/components/common/Tabbar.vue';//引入
// 状态机引入
import {
mapState,mapActions,mapGetters,mapMutations} from 'vuex'
export default {
data() {
return {
isNavBar:false,
}
},
computed:{
// 状态机数据处理
...mapState({
list:state=>state.cart.list,
selectedList:state=>state.cart.selectedList,
}),
...mapGetters(['checkedAll','totalCount'])
},
components:{
uniNavBar,uniNumberBox,Tabbar
},
onShow() {
this.getData();
},
methods: {
...mapActions(['checkedAllFn','delGoodsFn']),
...mapMutations(['selectedItem','initGetData']),
getData(){
$http.request({
url:'/selectCart',
method:"POST",
header:{
token:true
}
}).then((res)=>{
this.initGetData(res)
}).catch(()=>{
uni.showToast({
title:'请求失败',
icon:'none'
})
})
},
changeNumber(value,index,item){
if ( value == item.num ) return;
$http.request({
url:'/updateCart',
method:"POST",
header:{
token:true
},
data:{
goodsId:item.goods_id,
num:value
}
}).then((res)=>{
this.list[index].num = value;
}).catch(()=>{
uni.showToast({
title:'请求失败',
icon:'none'
})
})
},
// 进入确认订单
goConfirmOrder(){
if(this.selectedList.length === 0){
return uni.showToast({
title:"至少选择一件商品",
icon:"none"
})
}
uni.navigateTo({
url:`/pages/confirm-order/confirm-order?detail=${
JSON.stringify(this.selectedList)}`
})
}
}
}
</script>
<style lang="scss">
.shop-list{
padding-bottom: 100rpx;
}
.shop-else-list{
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: #f7f7f7;
display: flex;
align-items: center;
justify-content: center;
}
.shop-item{
display: flex;
padding: 20rpx;
align-items: center;
background-color: #f7f7f7;
margin-bottom: 10rpx;
}
.shop-img{
width: 200rpx;
height: 200rpx;
}
.shop-text{
flex: 1;
padding-left: 20rpx;
}
.shop-color{
font-size: 24rpx;
}
.shop-price{
display: flex;
justify-content: space-between;
}
.shop-foot{
border-top: 2rpx solid #f7f7f7;
background-color: #FFFFFF;
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 100rpx;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 120rpx;
}
.foot-radio{
padding-left: 20rpx;
}
.foot-total{
display: flex;
}
.foot-count{
line-height: 100rpx;
padding: 0 20rpx;
font-size: 32rpx;
}
.foot-num{
background-color: #49bdfb;
color: #FFFFFF;
padding: 0 60rpx;
line-height: 100rpx;
}
</style>
Confirmar código de página de pedido comfirm-order.vue
<template>
<view class="confirm-order bg-active-color">
<Lines></Lines>
<!-- 地址 -->
<view class="order-map" @tap="goPathList">
<block v-if="path">
<view class="map-title">
<view class="map-name">收件人:{
{
path.name}}</view>
<view class="">{
{
path.tel}}</view>
</view>
<view class="map-add">
收货地址:{
{
path.city}} {
{
path.detail}}
</view>
</block>
<block v-else>
<view class="map-title">
<view class="map-name">请选择地址</view>
</view>
</block>
</view>
<!-- 商品 -->
<view class="goods-list" v-for="(item,index) in goodsList" :key="index">
<view class="goods-content bg-active-color">
<image class="goods-img" :src="item.imgUrl" mode=""></image>
<view class="goods-text">
<view class="goods-name">
{
{
item.name}}
</view>
<view class="goods-size f-color">
颜色分类:黑色
</view>
<view class="f-active-color">
7天无理由
</view>
</view>
<view class="">
<view class="">
¥{
{
item.pprice}}
</view>
<view class="goods-size">
x {
{
item.num}}
</view>
</view>
</view>
</view>
<!-- 底部:提交订单 -->
<view class="order-foot">
<view class="total-price">
合计: <text class="f-active-color">${
{
totalCount.pprice}}</text>
</view>
<view class="confirm" @tap="goPayment">
提交订单
</view>
</view>
</view>
</template>
<script>
import Lines from '@/components/common/Lines.vue'
import {
mapGetters,mapState} from 'vuex'
export default {
data() {
return {
path:false
};
},
computed:{
...mapState({
list:state=>state.cart.list
}),
...mapGetters(['defaultPath','totalCount']),
// 根据商品列表找到对应的e.detail 数据的 id 最终返回商品数据
goodsList(){
return this.item.map(id=>{
return this.list.find(v=>v.id == id)
})
}
},
onLoad(e) {
console.log(e.detail,this.list);
// 选中的商品id集合 [1,3]
this.item = JSON.parse(e.detail);
// 如果默认地址的一个赋值
if(this.defaultPath.length){
this.path = this.defaultPath[0];
}
// 如果出发自定义事件,on去接收值
uni.$on('selectPathItem',(res)=>{
// console.log(res);
this.path = res;
})
},
onUnload() {
uni.$off('selectPathItem',()=>{
console.log('移除了selectPathItem');
})
},
components:{
Lines
},
methods:{
// 跳转到地址管理页面
goPathList(){
uni.navigateTo({
url:'/pages/my-path-list/my-path-list?type=selectedPath'
})
},
// 确认支付
goPayment(){
uni.navigateTo({
url:'/pages/payment/payment'
})
}
}
}
</script>
<style lang="less">
.confirm-order{
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
}
.order-map{
margin-bottom: 10rpx;
padding: 20rpx;
background-color: #fff;
line-height: 50rpx;
}
.map-title{
display: flex;
justify-content: space-between;
}
.map-name{
font-weight: bold;
}
.goods-list{
background-color: #fff;
padding: 10rpx 0;
}
.goods-content{
padding: 10rpx 20rpx;
display: flex;
justify-content: space-between;
align-items: center;
}
.goods-text{
width: 360rpx;
padding: 0 10rpx;
font-size: 26rpx;
}
.goods-img{
width: 160rpx;
height: 160rpx;
}
.goods-size{
font-size: 24rpx;
}
.order-foot{
width: 100%;
height: 80rpx;
position: fixed;
bottom: 0;
left: 0;
background-color: #fff;
display: flex;
justify-content: flex-end;
align-items: center;
}
.confirm{
color: #fff;
background-color: #49bdfb;
padding: 10rpx 30rpx;
}
.total-price{
padding: 0 20rpx;
}
</style>
cart.js bajo vuex
export default{
state:{
list:[
/* {
id:1,
name:"332经济法能聚聚会技能大赛 经济法能聚聚会技能大赛",
color:"颜色:嘿嘿嘿激活",
imgUrl:"../../static/logo.png",
pprice:"27",
num:1,
checked:false
},{
id:2,
name:"032经济法能聚聚会技能大赛 经济法能聚聚会技能大赛",
color:"颜色:嘿嘿嘿激活",
imgUrl:"../../static/logo.png",
pprice:"48",
num:6,
checked:false
} */
],
selectedList:[]
},
getters:{
// 判断是否 全选
checkedAll(state){
return state.list.length === state.selectedList.length;
},
// 合计 结算数量
totalCount(state){
let total = {
pprice:0,
num:0
}
state.list.forEach(v=>{
// 是否选中
if(state.selectedList.indexOf(v.id) > -1){
// 合计
total.pprice += v.pprice*v.num;
// 结算数量
total.num = state.selectedList.length;
}
})
return total;
}
},
mutations:{
// 请求到数据赋值操作
initGetData(state,list){
state.list = list;
},
// 全选
checkAll(state){
state.selectedList = state.list.map(v=>{
v.checked = true;
return v.id;
})
},
// 全不选
unCheckAll(state){
state.list.forEach(v=>{
v.checked = false;
})
state.selectedList = [];
},
// 单选
selectedItem(state,index){
let id = state.list[index].id;
let i = state.selectedList.indexOf(id);
// 如果selectList已经存在就代表他之前的选中状态,checked=false,并且在selectedList删除
if (i>-1) {
state.list[index].checked = false;
return state.selectedList.splice(i,1);
}
// 如果之前没有选中,checked=true,把当前的id添加到selectedList
state.list[index].checked = true;
state.selectedList.push(id);
},
//
delGoods(state){
state.list = state.list.filter(v=>{
return state.selectedList.indexOf(v.id) === -1;
})
},
// 加入购物车
addShopCart(state, goods){
state.list.push(goods);
}
},
actions:{
checkedAllFn({
commit,getters}){
getters.checkedAll ? commit("unCheckAll") : commit("checkAll")
},
delGoodsFn({
commit}){
commit('delGoods');
commit("unCheckAll");
uni.showToast({
title:'删除成功',
icon:"none"
})
}
}
}
Estructura de directorios
Estructura del directorio front-end
-
Archivo de configuración manifest.json: appid, logo…
-
Archivo de configuración pages.json: navegación, barra de pestañas, enrutamiento
-
Archivo de entrada de inicialización de main.js vue
-
Configuración global de App.vue: estilos, monitoreo global
-
recursos estáticos estáticos: imágenes, iconos de fuentes
-
página página
- índice
- index.vue
- lista
- lista.vue
- mi
- mi.vue
- mi-configuración
- mi-config.vue
- mi-configuración
- mi-config.vue
- mi-agregar-ruta
- mi-agregar-ruta.vue
- mi-lista-de-rutas
- mi-lista-de-rutas.vue
- buscar
- buscar.vue
- lista de búsqueda
- lista de búsqueda.vue
- carrito de compras
- carrito de compras.vue
- detalles
- detalles.vue
- mi pedido
- mi-pedido.vue
- confirmar pedido
- confirmar-pedido.vue
- pago
- pago.vue
- pago exitoso
- pago-éxito.vue
- acceso
- iniciar sesión.vue
- iniciar sesión-tel
login-tel.vue
- código de inicio de sesión
login-code.vue
- índice
-
componentes componentes
- índice
- banner.vista
- Caliente.vue
- Iconos.vue
- indexSwiper.vue
- Recomendar.vue
- Tienda.vue
Tabbar.vue
- común
- tarjeta.vue
- Común.vue
- CommondityList.vue
- línea.vue
- ShopList.vue
- orden
- lista de pedidos.vue
- uni
- caja uni-numérica
- uni-number-box.vue
- uni-iconos
- uni-iconos.vue
- barra de navegación uni
- uni-nav-bar.vue
- mpvue-citypicker
- mpvueCityPicker.vue
- caja uni-numérica
- índice
-
archivos públicos comunes: archivo css global || archivo js global
- API
- solicitud.js
- común.css
- uni.css
- API
-
almacenar el archivo de la máquina de estado vuex
- módulos
- carrito.js
- ruta.js
- usuario.js
- index.js
- módulos