移动端商品详情页设计

效果图

代码如下

页面设计

 <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-sp">
      <div class="goods-sp-item" v-for="(specification,specificationIndex) in goods.specifications"
           :key="specificationIndex">
        <div>
          <span>{{ specification.goodsSpecificationName }}: </span>
          <span
              v-for="(goodsSpecificationOption,goodsSpecificationOptionIndex) in specification.goodsSpecificationOptions"
              :key="goodsSpecificationOptionIndex">{{ goodsSpecificationOption.goodsSpecificationOptionName }} </span>
        </div>
      </div>
    </div>
    <div class="goods-introduction">
      <span>{{ goods.goodsIntroduction }}</span>
    </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="购物车" dot/>
      <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>颜色分类</span>
        </div>
        <!--规格 end-->
        <!--底部 start-->
        <el-button class="button" size="large" color="#ff9003" round @click="onAddCart">加入购物车</el-button>
        <!--底部 end-->
      </div>
    </van-popup>
    <!--加入购物车弹出框 end-->

  </div>

逻辑编写

<script setup>
import {onMounted, reactive, ref} from "vue";
import axios from "@/utils/request"
import {useRoute} from "vue-router"
import {useDataStore} from "../../stores/dataStore"
import {ElMessage} from "element-plus";
import AddressList from "../../components/AddressList/Index.vue"

const dataStore = useDataStore()

const route = useRoute()
//加入购物车弹出框控制器
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(() => {
  ElMessage.success("成功")
  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 = () => {
  showCart.value = true
}
/**
 * 加入购物车
 */
const onAddCart = () => {
  axios.post("front/cart/addGoodsCart", {
    userId: dataStore.userId,
    goodsId: goodsId,
    goodsHeadImg: goods.goodsHeadImg,
    goodsName: goods.goodsName,
    goodsPrice: goods.goodsPrice,
    num: 1,
  }).then(res => {
    if (res.data.code == 200) {
      showCart.value = false
    }
  })
}

</script>

css设计

<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-sp {
  background-color: #f7f7f7;
  border-radius: 2%;
  margin-top: 10px;
  margin-bottom: 10px;
}

.goods-sp-item {
  padding: 8px;
}

.goods-sp-item span {
  font-size: 12px;
  font-weight: bold;
}

.goods-introduction {
  background-color: #f7f7f7;
  font-size: 12px;
  margin-top: 10px;
  margin-bottom: 10px;
}

.goods-introduction span {
  padding: 10px;
}

.goods-name span {
  margin-left: 5px;
  font-size: 16px;
  font-weight: bold;
}

/*加入购物车弹出框样式*/
.add-cart-show {
  height: 500px;
}

.add-cart-show button {
  position: fixed;
  bottom: 10px;
  left: 10px;
  width: 350px;
  color: #faf7e7;
  font-weight: 700;
}

.add-header {
  display: flex;
  position: fixed;
  left: 10px;
  top: 70px;
  z-index: 100;
  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: 110px;
}

.add-goods-specification {
  margin-top: 20px;
}
</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-sp">
      <div class="goods-sp-item" v-for="(specification,specificationIndex) in goods.specifications"
           :key="specificationIndex">
        <div>
          <span>{{ specification.goodsSpecificationName }}: </span>
          <span
              v-for="(goodsSpecificationOption,goodsSpecificationOptionIndex) in specification.goodsSpecificationOptions"
              :key="goodsSpecificationOptionIndex">{{ goodsSpecificationOption.goodsSpecificationOptionName }} </span>
        </div>
      </div>
    </div>
    <div class="goods-introduction">
      <span>{{ goods.goodsIntroduction }}</span>
    </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="购物车" dot/>
      <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>颜色分类</span>
        </div>
        <!--规格 end-->
        <!--底部 start-->
        <el-button class="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} from "vue-router"
import {useDataStore} from "../../stores/dataStore"
import {ElMessage} from "element-plus";
import AddressList from "../../components/AddressList/Index.vue"

const dataStore = useDataStore()

const route = useRoute()
//加入购物车弹出框控制器
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(() => {
  ElMessage.success("成功")
  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 = () => {
  showCart.value = true
}
/**
 * 加入购物车
 */
const onAddCart = () => {
  axios.post("front/cart/addGoodsCart", {
    userId: dataStore.userId,
    goodsId: goodsId,
    goodsHeadImg: goods.goodsHeadImg,
    goodsName: goods.goodsName,
    goodsPrice: goods.goodsPrice,
    num: 1,
  }).then(res => {
    if (res.data.code == 200) {
      showCart.value = false
    }
  })
}

</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-sp {
  background-color: #f7f7f7;
  border-radius: 2%;
  margin-top: 10px;
  margin-bottom: 10px;
}

.goods-sp-item {
  padding: 8px;
}

.goods-sp-item span {
  font-size: 12px;
  font-weight: bold;
}

.goods-introduction {
  background-color: #f7f7f7;
  font-size: 12px;
  margin-top: 10px;
  margin-bottom: 10px;
}

.goods-introduction span {
  padding: 10px;
}

.goods-name span {
  margin-left: 5px;
  font-size: 16px;
  font-weight: bold;
}

/*加入购物车弹出框样式*/
.add-cart-show {
  height: 500px;
}

.add-cart-show button {
  position: fixed;
  bottom: 10px;
  left: 10px;
  width: 350px;
  color: #faf7e7;
  font-weight: 700;
}

.add-header {
  display: flex;
  position: fixed;
  left: 10px;
  top: 70px;
  z-index: 100;
  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: 110px;
}

.add-goods-specification {
  margin-top: 20px;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/45553.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【VUE】npm打包报错 Syntax Error: Error: Cannot find module ‘imagemin-gifsicle‘

一. Syntax Error: Error: Cannot find module ‘imagemin-gifsicle’ npm run build 报错&#xff0c;报错如下 原因 这个错误消息显示缺少了 imagemin-gifsicle 模块&#xff0c;而它是 image-webpack-loader 的依赖项&#xff0c;导致构建失败。解决 &#xff08;1&#xf…

安全—01day

文章目录 1. 编码1.1 ASCLL编码1.2 URL编码1.3 Unicode编码1.4 HTML编码1.5 Base64编码 2. form表单2.1 php接收form表单2.2 python接收form表单 1. 编码 1.1 ASCLL编码 ASCII 是基于拉丁字母的一套电脑编码系统&#xff0c;主要用于显示现代英语和其他西欧语言。它是最通用的…

电容触摸屏(TP)的工艺结构

液晶显示屏(LCM),触摸屏(TP) “GG、GP、GF”这是结构分类&#xff0c;第一个字母表面材质&#xff08;又称为上层&#xff09;&#xff0c;第二个字母是触摸屏的材质&#xff08;又称为下层&#xff09;&#xff0c;两者贴合在一起。 G玻璃&#xff0c;FFILM&#xff0c;“”贴…

Stable Diffusion - 扩展 SegmentAnything 和 GroundingDINO 实例分割算法 插件的配置与使用

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://blog.csdn.net/caroline_wendy/article/details/131918652 Paper and GitHub&#xff1a; Segment Anything: SAM - Segment Anything GitHub: https://github.com/facebookresearch/s…

蓝桥杯专题-真题版含答案-【牌型种数】【煤球数目】【寒假作业】【奖券数目】

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

MySQL 数据库约束

目录 一、数据库约束 1、约束类型 二、NULL 约束 三、unique 约束 四、default 约束 五、primary key 约束 自增主键 六、foreign key 外键约束 七、check 约束 一、数据库约束 我们使用数据库来存储数据&#xff0c;一般是希望这里存储的数据是靠谱的&#xff0c;…

There has been an error.Error running C:\WINDOWS\System32\icacls

目前网上有两种有效的解决方案&#xff1a; windows用户名含中文的创建一个新用户&#xff0c;链接 安装其他版本的PostgreSQL(可优先考虑&#xff0c;我使用该方法解决的问题)&#xff0c;链接

java项目之人才公寓管理系统(ssm+mysql+jsp)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的人才公寓管理系统。技术交流和部署相关看文章末尾&#xff01; 开发环境&#xff1a; 后端&#xff1a; 开发语言&#xff1a;Java 框架&…

【产品实习评审】对于高校跑腿的任务模型和价格模型设计比较到位

大家好&#xff0c;本篇文章分享【校招VIP】商业在线实习项目“跑个腿”第一期需求发布模块产品同学的脑图周最佳作品&#xff0c;该同学来自江苏师范大学社会学专业。 本项目亮点&#xff1a; 1 跑腿需求发布模块—构建项目数据模型&#xff0c;包括时效、常用地址和联系 2…

卤味行业数据分析报告

在一个炎热的夏日午后&#xff0c;热气蒸腾的城市街头弥漫着一股令人垂涎欲滴的香气。这股香气源自一家招牌醒目的卤味小吃摊位&#xff0c;摊主技巧娴熟地将各式美味的食材浸泡在独特的卤汁中。这里没有花哨的招牌&#xff0c;却吸引了无数食客的目光和嘴巴。 卤制食品在中国烹…

Rust vs Go:常用语法对比(四)

题图来自 Go vs. Rust performance comparison: The basics 61. Get current date 获取当前时间 package mainimport ( "fmt" "time")func main() { d : time.Now() fmt.Println("Now is", d) // The Playground has a special sandbox, so you …

上手 SpringBoot

简介 SpringBoot设计的目的是简化 Spring应用的初始搭建以及 开发过程。 SpringBoot概述 parent 继承父pom文件&#xff0c;方便管理依赖的版本。此处涉及maven的使用 作用&#xff1a; 继承parent的形式可以采用引入依赖的形式实现效果 starter(原理是依赖传递) 包含了若…

Mac电脑文件夹无权限问题

sudo cp 16.5.zip /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport 走到之前的folder &#xff0c;右键选择get info更改權限, 再應用到所有子文件夹 右下解鎖再加自己Read & Write, -右邊拉下應該可以應用到所有子文件 这样就可以…

【N32L40X】学习笔记10-外部触发方式计数

定时器采用外部触发方式计数 也就是外部时钟源模式2 此模式由 TIMx_SMCTRL .EXCEN 选择等于 1。计数器可以在外部触发输入 ETR 的每个上升沿或下降沿 计数。 极性选择分频选择过滤选择选择外部时钟ETR模式 bsp_time_counter_ETR.h #ifndef _BSP_TIME_COUNTER_ETR_H_ #defi…

nfs服务器的描述,搭建和使用

前言 这是我在这个网站整理的笔记&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;RodmaChen nfs服务器的描述&#xff0c;搭建和使用 NFS概述工作原理优缺点 nfs服务器搭建服务端客户端 NFS概述 NFS&#xff08;Network File System&#xff09;是一种基…

Bug管理规范

目录 1.目的 2.角色和职责 3.缺陷等级定义 4.缺陷提交原则 5.缺陷流转流程 5.1创建缺陷 5.2缺陷分拣/分配 5.3研发认领缺陷 5.4.研发解决缺陷 5.5关闭缺陷 5.6缺陷激活 1.目的 项目过程中对缺陷管理的规则&#xff0c;明确提单规范、用例优先级的选择规则、走单流程、…

软件工程学术顶会——ICSE 2023 议题(网络安全方向)清单与摘要

按语&#xff1a;IEEE/ACM ICSE全称International Conference on Software Engineering&#xff0c;是软件工程领域公认的旗舰学术会议&#xff0c;中国计算机学会推荐的A类国际学术会议&#xff0c;Core Conference Ranking A*类会议&#xff0c;H5指数74&#xff0c;Impact s…

【NLP】如何使用Hugging-Face-Pipelines?

一、说明 随着最近开发的库&#xff0c;执行深度学习分析变得更加容易。其中一个库是拥抱脸。Hugging Face 是一个平台&#xff0c;可为 NLP 任务&#xff08;如文本分类、情感分析等&#xff09;提供预先训练的语言模型。 本博客将引导您了解如何使用拥抱面部管道执行 NLP 任务…

华为eNSP:isis的配置

一、拓扑图 二、路由器的配置 配置接口IP AR1&#xff1a; <Huawei>system-view [Huawei]int g0/0/0 [Huawei-GigabitEthernet0/0/0]ip add 1.1.1.1 24 [Huawei-GigabitEthernet0/0/0]qu AR2: <Huawei>system-view [Huawei]int g0/0/0 [Huawei-GigabitEthe…