效果图
源码如下
页面设计
<template>
<div class="container">
<!--商品详情 start-->
<van-image class="goods-item-image" :src="goods.goodsHeadImg"></van-image>
<div class="goods-price">
¥<span>{{ goods.goodsPrice }}</span>.00起
</div>
<div class="goods-name">
<el-button round size="small">{{ goods.goodsBrand.goodsBrandName }}</el-button>
<span>{{ goods.goodsName }}</span>
<span>{{ goods.goodsCaption }}</span>
</div>
<div class="goods-introduction">
<el-input style="width: 100%;" type="textarea" autosize v-model="goods.goodsIntroduction"></el-input>
<!-- <el-text>{{ goods.goodsIntroduction }}</el-text>-->
</div>
<div class="goods-images" v-for="(img,imgIndex) in goods.images" :key="imgIndex">
<van-image class="goods-item-image" :src="img.goodsImageUrl"></van-image>
</div>
<!--商品详情 end-->
<!--底部导航 start-->
<van-action-bar style="margin-bottom: 50px ">
<van-action-bar-icon icon="chat-o" text="客服" badge="12"/>
<van-action-bar-icon icon="cart-o" text="购物车" badge="6" @click="onCartShow"/>
<van-action-bar-icon icon="shop-o" text="店铺" badge="5"/>
<van-action-bar-button type="warning" text="加入购物车" @click="onAddCartShow"/>
<van-action-bar-button type="danger" text="立即购买"/>
</van-action-bar>
<!--底部导航 end-->
<!--加入购物车弹出框 end-->
<van-popup v-model:show="showCart" position="bottom" closeable>
<div class="add-cart-show">
<!--顶部 start-->
<div class="add-header">
<van-image class="add-goods-img" radius="10" :src="goods.goodsHeadImg"></van-image>
<div class="add-goods-price">
¥<span>{{ goods.goodsPrice }}</span>
</div>
</div>
<!--顶部 end-->
<!--地址 start-->
<AddressList class="add-address"/>
<!--地址 end-->
<!--规格 start-->
<div class="add-goods-specification">
<span class="goodsSpecificationName">{{ goods.specifications[0].goodsSpecificationName }}</span>
<el-radio-group v-for="(o,index2) in goods.specifications[0].goodsSpecificationOptions" :key="index2"
direction="horizontal"
v-model="radio1" fill="#018cel" text-color="#ffffff">
<el-radio-button class="goodsSpecificationOption"
:label="o.goodsSpecificationOptionName"></el-radio-button>
</el-radio-group>
<span v-if="goods.specifications[1]"
class="goodsSpecificationName">{{ goods.specifications[1].goodsSpecificationName }}</span>
<el-radio-group v-if="goods.specifications[1]"
v-for="(o,index2) in goods.specifications[1].goodsSpecificationOptions" :key="index2"
direction="horizontal"
v-model="radio2" fill="#018cel" text-color="#ffffff">
<el-radio-button class="goodsSpecificationOption"
:label="o.goodsSpecificationOptionName"></el-radio-button>
</el-radio-group>
<span v-if="goods.specifications[2]"
class="goodsSpecificationName">{{ goods.specifications[2].goodsSpecificationName }}</span>
<el-radio-group v-if="goods.specifications[2]"
v-for="(o,index2) in goods.specifications[2].goodsSpecificationOptions" :key="index2"
direction="horizontal"
v-model="radio3" fill="#018cel" text-color="#ffffff">
<el-radio-button class="goodsSpecificationOption"
:label="o.goodsSpecificationOptionName"></el-radio-button>
</el-radio-group>
<span v-if="goods.specifications[3]"
class="goodsSpecificationName">{{ goods.specifications[3].goodsSpecificationName }}</span>
<el-radio-group v-if="goods.specifications[3]"
v-for="(o,index2) in goods.specifications[3].goodsSpecificationOptions" :key="index2"
direction="horizontal"
v-model="radio4" fill="#018cel" text-color="#ffffff">
<el-radio-button class="goodsSpecificationOption"
:label="o.goodsSpecificationOptionName"></el-radio-button>
</el-radio-group>
<span v-if="goods.specifications[4]"
class="goodsSpecificationName">{{ goods.specifications[4].goodsSpecificationName }}</span>
<el-radio-group v-if="goods.specifications[4]"
v-for="(o,index2) in goods.specifications[4].goodsSpecificationOptions" :key="index2"
direction="horizontal"
v-model="radio5" fill="#018cel" text-color="#ffffff">
<el-radio-button class="goodsSpecificationOption"
:label="o.goodsSpecificationOptionName"></el-radio-button>
</el-radio-group>
<span v-if="goods.specifications[5]"
class="goodsSpecificationName">{{ goods.specifications[5].goodsSpecificationName }}</span>
<el-radio-group v-if="goods.specifications[5]"
v-for="(o,index2) in goods.specifications[5].goodsSpecificationOptions" :key="index2"
direction="horizontal"
v-model="radio6" fill="#018cel" text-color="#ffffff">
<el-radio-button class="goodsSpecificationOption"
:label="o.goodsSpecificationOptionName"></el-radio-button>
</el-radio-group>
</div>
<!--规格 end-->
<!--底部 start-->
<el-button class="add-goods-button" size="large" color="#ff9003" round @click="onAddCart">加入购物车</el-button>
<!--底部 end-->
</div>
</van-popup>
<!--加入购物车弹出框 end-->
</div>
</template>
逻辑编写
<script setup>
import {onMounted, reactive, ref} from "vue";
import axios from "@/utils/request"
import {useRoute, useRouter} from "vue-router"
import {useDataStore} from "../../stores/dataStore"
import AddressList from "../../components/AddressList/Index.vue"
import {showSuccessToast} from 'vant';
const router = useRouter()
const dataStore = useDataStore()
const route = useRoute()
//单选框选中的规格数据
const radio1 = ref("")
const radio2 = ref("")
const radio3 = ref("")
const radio4 = ref("")
const radio5 = ref("")
const radio6 = ref("")
//加入购物车弹出框控制器
const showCart = ref(false)
//商品id
const goodsId = route.params.name
//商品数据
const goods = reactive({
goodsId: "",
goodsHeadImg: "",
goodsName: "",
goodsCaption: "",
goodsPrice: "",
goodsIntroduction: "",
goodsUse: "",
goodsBrand: "",
goodsType1: "",
goodsType2: "",
goodsType3: "",
images: "",
specifications: ""
})
onMounted(() => {
axios.get("front/goods/findDesc", {
params: {
goodsId: goodsId
}
}).then(res => {
if (res.data.code == 200) {
goods.goodsId = res.data.data.goodsId
goods.goodsHeadImg = res.data.data.goodsHeadImg
goods.goodsName = res.data.data.goodsName
goods.goodsCaption = res.data.data.goodsCaption
goods.goodsPrice = res.data.data.goodsPrice
goods.goodsIntroduction = res.data.data.goodsIntroduction
goods.goodsUse = res.data.data.goodsUse
goods.goodsBrand = res.data.data.goodsBrand
goods.goodsType1 = res.data.data.goodsType1
goods.goodsType2 = res.data.data.goodsType2
goods.goodsType3 = res.data.data.goodsType3
goods.images = res.data.data.images
goods.specifications = res.data.data.specifications
}
})
})
/**
* 加入购物车弹出框
*/
const onAddCartShow = () => {
if (!dataStore.isLogin) {
router.push("/home/login")
} else {
showCart.value = true
}
}
/**
* 加入购物车
*/
const onAddCart = () => {
axios.post("front/cart/addGoodsCart", {
userId: dataStore.userId,
goodsId: goodsId,
goodsHeadImg: goods.goodsHeadImg,
goodsName: goods.goodsName,
goodsPrice: goods.goodsPrice,
specificationContent: radio1.value + " " + radio2.value + " " + radio3.value + " " + radio4.value + " " + radio5.value + " " + radio6.value,
num: 1,
}).then(res => {
if (res.data.code == 200) {
showSuccessToast('加入成功');
showCart.value = false
}
})
}
/**
* 查看购物车
*/
const onCartShow = () => {
router.push("/home/cart")
}
</script>
样式设计
<style scoped>
.container {
background-color: #ffffff;
}
/**
商品数据样式
*/
.goods-price {
margin-top: 10px;
color: #ff4142;
}
.goods-price span {
font-style: normal;
font-family: JDZH-Regular, sans-serif;
display: inline-block;
font-size: 22px;
font-weight: 500;
line-height: normal;
color: #f44d0b;
}
.goods-name {
font-size: 21px;
color: #181818;
font-family: JDZH-Regular, sans-serif;
}
.goods-name button {
margin: 4px;
display: inline;
color: #fdfdff;
font-weight: 400;
background-color: #fe012d;
}
.goods-introduction {
background-color: #f9f9f9;
font-size: 12px;
margin-top: 10px;
margin-bottom: 10px;
}
.goods-name span {
margin-left: 5px;
font-size: 16px;
font-weight: bold;
}
/*
加入购物车弹出框样式
*/
.add-cart-show {
height: 600px;
}
.add-header {
display: flex;
left: 10px;
background-color: #ffffff;
}
.add-goods-img {
margin: 10px;
width: 80px;
}
.add-goods-price {
margin-left: 20px;
margin-top: 35px;
color: #ff4142;
font-size: 15px;
}
.add-goods-price span {
font-style: normal;
font-family: JDZH-Regular, sans-serif;
display: inline-block;
font-size: 32px;
font-weight: 500;
line-height: normal;
color: #f44d0b;
}
/**
地址
*/
.add-address {
margin-top: 10px;
}
/**
规格
*/
.add-goods-specification {
margin: 20px;
}
.goodsSpecificationName {
display: block;
line-height: 37px;
color: #121212;
font-size: 14px;
font-weight: 700;
}
.goodsSpecificationOption {
margin: 2px;
}
/**
底部
*/
.add-goods-button {
position: fixed;
bottom: 10px;
left: 10px;
width: 350px;
color: #faf7e7;
font-weight: 700;
}
</style>
全部代码
<template>
<div class="container">
<!--商品详情 start-->
<van-image class="goods-item-image" :src="goods.goodsHeadImg"></van-image>
<div class="goods-price">
¥<span>{{ goods.goodsPrice }}</span>.00起
</div>
<div class="goods-name">
<el-button round size="small">{{ goods.goodsBrand.goodsBrandName }}</el-button>
<span>{{ goods.goodsName }}</span>
<span>{{ goods.goodsCaption }}</span>
</div>
<div class="goods-introduction">
<el-input style="width: 100%;" type="textarea" autosize v-model="goods.goodsIntroduction"></el-input>
<!-- <el-text>{{ goods.goodsIntroduction }}</el-text>-->
</div>
<div class="goods-images" v-for="(img,imgIndex) in goods.images" :key="imgIndex">
<van-image class="goods-item-image" :src="img.goodsImageUrl"></van-image>
</div>
<!--商品详情 end-->
<!--底部导航 start-->
<van-action-bar style="margin-bottom: 50px ">
<van-action-bar-icon icon="chat-o" text="客服" badge="12"/>
<van-action-bar-icon icon="cart-o" text="购物车" badge="6" @click="onCartShow"/>
<van-action-bar-icon icon="shop-o" text="店铺" badge="5"/>
<van-action-bar-button type="warning" text="加入购物车" @click="onAddCartShow"/>
<van-action-bar-button type="danger" text="立即购买"/>
</van-action-bar>
<!--底部导航 end-->
<!--加入购物车弹出框 end-->
<van-popup v-model:show="showCart" position="bottom" closeable>
<div class="add-cart-show">
<!--顶部 start-->
<div class="add-header">
<van-image class="add-goods-img" radius="10" :src="goods.goodsHeadImg"></van-image>
<div class="add-goods-price">
¥<span>{{ goods.goodsPrice }}</span>
</div>
</div>
<!--顶部 end-->
<!--地址 start-->
<AddressList class="add-address"/>
<!--地址 end-->
<!--规格 start-->
<div class="add-goods-specification">
<span class="goodsSpecificationName">{{ goods.specifications[0].goodsSpecificationName }}</span>
<el-radio-group v-for="(o,index2) in goods.specifications[0].goodsSpecificationOptions" :key="index2"
direction="horizontal"
v-model="radio1" fill="#018cel" text-color="#ffffff">
<el-radio-button class="goodsSpecificationOption"
:label="o.goodsSpecificationOptionName"></el-radio-button>
</el-radio-group>
<span v-if="goods.specifications[1]"
class="goodsSpecificationName">{{ goods.specifications[1].goodsSpecificationName }}</span>
<el-radio-group v-if="goods.specifications[1]"
v-for="(o,index2) in goods.specifications[1].goodsSpecificationOptions" :key="index2"
direction="horizontal"
v-model="radio2" fill="#018cel" text-color="#ffffff">
<el-radio-button class="goodsSpecificationOption"
:label="o.goodsSpecificationOptionName"></el-radio-button>
</el-radio-group>
<span v-if="goods.specifications[2]"
class="goodsSpecificationName">{{ goods.specifications[2].goodsSpecificationName }}</span>
<el-radio-group v-if="goods.specifications[2]"
v-for="(o,index2) in goods.specifications[2].goodsSpecificationOptions" :key="index2"
direction="horizontal"
v-model="radio3" fill="#018cel" text-color="#ffffff">
<el-radio-button class="goodsSpecificationOption"
:label="o.goodsSpecificationOptionName"></el-radio-button>
</el-radio-group>
<span v-if="goods.specifications[3]"
class="goodsSpecificationName">{{ goods.specifications[3].goodsSpecificationName }}</span>
<el-radio-group v-if="goods.specifications[3]"
v-for="(o,index2) in goods.specifications[3].goodsSpecificationOptions" :key="index2"
direction="horizontal"
v-model="radio4" fill="#018cel" text-color="#ffffff">
<el-radio-button class="goodsSpecificationOption"
:label="o.goodsSpecificationOptionName"></el-radio-button>
</el-radio-group>
<span v-if="goods.specifications[4]"
class="goodsSpecificationName">{{ goods.specifications[4].goodsSpecificationName }}</span>
<el-radio-group v-if="goods.specifications[4]"
v-for="(o,index2) in goods.specifications[4].goodsSpecificationOptions" :key="index2"
direction="horizontal"
v-model="radio5" fill="#018cel" text-color="#ffffff">
<el-radio-button class="goodsSpecificationOption"
:label="o.goodsSpecificationOptionName"></el-radio-button>
</el-radio-group>
<span v-if="goods.specifications[5]"
class="goodsSpecificationName">{{ goods.specifications[5].goodsSpecificationName }}</span>
<el-radio-group v-if="goods.specifications[5]"
v-for="(o,index2) in goods.specifications[5].goodsSpecificationOptions" :key="index2"
direction="horizontal"
v-model="radio6" fill="#018cel" text-color="#ffffff">
<el-radio-button class="goodsSpecificationOption"
:label="o.goodsSpecificationOptionName"></el-radio-button>
</el-radio-group>
</div>
<!--规格 end-->
<!--底部 start-->
<el-button class="add-goods-button" size="large" color="#ff9003" round @click="onAddCart">加入购物车</el-button>
<!--底部 end-->
</div>
</van-popup>
<!--加入购物车弹出框 end-->
</div>
</template>
<script setup>
import {onMounted, reactive, ref} from "vue";
import axios from "@/utils/request"
import {useRoute, useRouter} from "vue-router"
import {useDataStore} from "../../stores/dataStore"
import AddressList from "../../components/AddressList/Index.vue"
import {showSuccessToast} from 'vant';
const router = useRouter()
const dataStore = useDataStore()
const route = useRoute()
//单选框选中的规格数据
const radio1 = ref("")
const radio2 = ref("")
const radio3 = ref("")
const radio4 = ref("")
const radio5 = ref("")
const radio6 = ref("")
//加入购物车弹出框控制器
const showCart = ref(false)
//商品id
const goodsId = route.params.name
//商品数据
const goods = reactive({
goodsId: "",
goodsHeadImg: "",
goodsName: "",
goodsCaption: "",
goodsPrice: "",
goodsIntroduction: "",
goodsUse: "",
goodsBrand: "",
goodsType1: "",
goodsType2: "",
goodsType3: "",
images: "",
specifications: ""
})
onMounted(() => {
axios.get("front/goods/findDesc", {
params: {
goodsId: goodsId
}
}).then(res => {
if (res.data.code == 200) {
goods.goodsId = res.data.data.goodsId
goods.goodsHeadImg = res.data.data.goodsHeadImg
goods.goodsName = res.data.data.goodsName
goods.goodsCaption = res.data.data.goodsCaption
goods.goodsPrice = res.data.data.goodsPrice
goods.goodsIntroduction = res.data.data.goodsIntroduction
goods.goodsUse = res.data.data.goodsUse
goods.goodsBrand = res.data.data.goodsBrand
goods.goodsType1 = res.data.data.goodsType1
goods.goodsType2 = res.data.data.goodsType2
goods.goodsType3 = res.data.data.goodsType3
goods.images = res.data.data.images
goods.specifications = res.data.data.specifications
}
})
})
/**
* 加入购物车弹出框
*/
const onAddCartShow = () => {
if (!dataStore.isLogin) {
router.push("/home/login")
} else {
showCart.value = true
}
}
/**
* 加入购物车
*/
const onAddCart = () => {
axios.post("front/cart/addGoodsCart", {
userId: dataStore.userId,
goodsId: goodsId,
goodsHeadImg: goods.goodsHeadImg,
goodsName: goods.goodsName,
goodsPrice: goods.goodsPrice,
specificationContent: radio1.value + " " + radio2.value + " " + radio3.value + " " + radio4.value + " " + radio5.value + " " + radio6.value,
num: 1,
}).then(res => {
if (res.data.code == 200) {
showSuccessToast('加入成功');
showCart.value = false
}
})
}
/**
* 查看购物车
*/
const onCartShow = () => {
router.push("/home/cart")
}
</script>
<style scoped>
.container {
background-color: #ffffff;
}
/**
商品数据样式
*/
.goods-price {
margin-top: 10px;
color: #ff4142;
}
.goods-price span {
font-style: normal;
font-family: JDZH-Regular, sans-serif;
display: inline-block;
font-size: 22px;
font-weight: 500;
line-height: normal;
color: #f44d0b;
}
.goods-name {
font-size: 21px;
color: #181818;
font-family: JDZH-Regular, sans-serif;
}
.goods-name button {
margin: 4px;
display: inline;
color: #fdfdff;
font-weight: 400;
background-color: #fe012d;
}
.goods-introduction {
background-color: #f9f9f9;
font-size: 12px;
margin-top: 10px;
margin-bottom: 10px;
}
.goods-name span {
margin-left: 5px;
font-size: 16px;
font-weight: bold;
}
/*
加入购物车弹出框样式
*/
.add-cart-show {
height: 600px;
}
.add-header {
display: flex;
left: 10px;
background-color: #ffffff;
}
.add-goods-img {
margin: 10px;
width: 80px;
}
.add-goods-price {
margin-left: 20px;
margin-top: 35px;
color: #ff4142;
font-size: 15px;
}
.add-goods-price span {
font-style: normal;
font-family: JDZH-Regular, sans-serif;
display: inline-block;
font-size: 32px;
font-weight: 500;
line-height: normal;
color: #f44d0b;
}
/**
地址
*/
.add-address {
margin-top: 10px;
}
/**
规格
*/
.add-goods-specification {
margin: 20px;
}
.goodsSpecificationName {
display: block;
line-height: 37px;
color: #121212;
font-size: 14px;
font-weight: 700;
}
.goodsSpecificationOption {
margin: 2px;
}
/**
底部
*/
.add-goods-button {
position: fixed;
bottom: 10px;
left: 10px;
width: 350px;
color: #faf7e7;
font-weight: 700;
}
</style>