商品详情-准备工作和页面渲染
新建页面-》静态结构-》页面参数处理-》封装API接口-》初始化调用
1.新建页面
2.静态结构
// src/pages/goods/goods.vue <script setup lang="ts"> // 获取屏幕边界到安全区域距离 const { safeAreaInsets } = uni.getSystemInfoSync() </script> <template> <scroll-view scroll-y class="viewport"> <!-- 基本信息 --> <view class="goods"> <!-- 商品主图 --> <view class="preview"> <swiper circular> <swiper-item> <image mode="aspectFill" src="https://yanxuan-item.nosdn.127.net/99c83709ca5f9fd5c5bb35d207ad7822.png" /> </swiper-item> <swiper-item> <image mode="aspectFill" src="https://yanxuan-item.nosdn.127.net/f9107d47c08f0b99c097e30055c39e1a.png" /> </swiper-item> <swiper-item> <image mode="aspectFill" src="https://yanxuan-item.nosdn.127.net/754c56785cc8c39f7414752f62d79872.png" /> </swiper-item> <swiper-item> <image mode="aspectFill" src="https://yanxuan-item.nosdn.127.net/ef16f8127610ef56a2a10466d6dae157.jpg" /> </swiper-item> <swiper-item> <image mode="aspectFill" src="https://yanxuan-item.nosdn.127.net/1f0c3f5d32b0e804deb9b3d56ea6c3b2.png" /> </swiper-item> </swiper> <view class="indicator"> <text class="current">1</text> <text class="split">/</text> <text class="total">5</text> </view> </view> <!-- 商品简介 --> <view class="meta"> <view class="price"> <text class="symbol">¥</text> <text class="number">29.90</text> </view> <view class="name ellipsis">云珍·轻软旅行长绒棉方巾 </view> <view class="desc"> 轻巧无捻小方巾,旅行便携 </view> </view> <!-- 操作面板 --> <view class="action"> <view class="item arrow"> <text class="label">选择</text> <text class="text ellipsis"> 请选择商品规格 </text> </view> <view class="item arrow"> <text class="label">送至</text> <text class="text ellipsis"> 请选择收获地址 </text> </view> <view class="item arrow"> <text class="label">服务</text> <text class="text ellipsis"> 无忧退 快速退款 免费包邮 </text> </view> </view> </view> <!-- 商品详情 --> <view class="detail panel"> <view class="title"> <text>详情</text> </view> <view class="content"> <view class="properties"> <!-- 属性详情 --> <view class="item"> <text class="label">属性名</text> <text class="value">属性值</text> </view> <view class="item"> <text class="label">属性名</text> <text class="value">属性值</text> </view> </view> <!-- 图片详情 --> <image mode="widthFix" src="https://yanxuan-item.nosdn.127.net/a8d266886d31f6eb0d7333c815769305.jpg" ></image> <image mode="widthFix" src="https://yanxuan-item.nosdn.127.net/a9bee1cb53d72e6cdcda210071cbd46a.jpg" ></image> </view> </view> <!-- 同类推荐 --> <view class="similar panel"> <view class="title"> <text>同类推荐</text> </view> <view class="content"> <navigator v-for="item in 4" :key="item" class="goods" hover-class="none" :url="`/pages/goods/goods?id=`" > <image class="image" mode="aspectFill" src="https://yanxuan-item.nosdn.127.net/e0cea368f41da1587b3b7fc523f169d7.png" ></image> <view class="name ellipsis">简约山形纹全棉提花毛巾</view> <view class="price"> <text class="symbol">¥</text> <text class="number">18.50</text> </view> </navigator> </view> </view> </scroll-view> <!-- 用户操作 --> <view class="toolbar" :style="{ paddingBottom: safeAreaInsets?.bottom + 'px' }"> <view class="icons"> <button class="icons-button"><text class="icon-heart"></text>收藏</button> <button class="icons-button" open-type="contact"> <text class="icon-handset"></text>客服 </button> <navigator class="icons-button" url="/pages/cart/cart" open-type="switchTab"> <text class="icon-cart"></text>购物车 </navigator> </view> <view class="buttons"> <view class="addcart"> 加入购物车 </view> <view class="buynow"> 立即购买 </view> </view> </view> </template> <style lang="scss"> page { height: 100%; overflow: hidden; display: flex; flex-direction: column; } .viewport { background-color: #f4f4f4; } .panel { margin-top: 20rpx; background-color: #fff; .title { display: flex; justify-content: space-between; align-items: center; height: 90rpx; line-height: 1; padding: 30rpx 60rpx 30rpx 6rpx; position: relative; text { padding-left: 10rpx; font-size: 28rpx; color: #333; font-weight: 600; border-left: 4rpx solid #27ba9b; } navigator { font-size: 24rpx; color: #666; } } } .arrow { &::after { position: absolute; top: 50%; right: 30rpx; content: '\e6c2'; color: #ccc; font-family: 'erabbit' !important; font-size: 32rpx; transform: translateY(-50%); } } /* 商品信息 */ .goods { background-color: #fff; .preview { height: 750rpx; position: relative; .image { width: 750rpx; height: 750rpx; } .indicator { height: 40rpx; padding: 0 24rpx; line-height: 40rpx; border-radius: 30rpx; color: #fff; font-family: Arial, Helvetica, sans-serif; background-color: rgba(0, 0, 0, 0.3); position: absolute; bottom: 30rpx; right: 30rpx; .current { font-size: 26rpx; } .split { font-size: 24rpx; margin: 0 1rpx 0 2rpx; } .total { font-size: 24rpx; } } } .meta { position: relative; border-bottom: 1rpx solid #eaeaea; .price { height: 130rpx; padding: 25rpx 30rpx 0; color: #fff; font-size: 34rpx; box-sizing: border-box; background-color: #35c8a9; } .number { font-size: 56rpx; } .brand { width: 160rpx; height: 80rpx; overflow: hidden; position: absolute; top: 26rpx; right: 30rpx; } .name { max-height: 88rpx; line-height: 1.4; margin: 20rpx; font-size: 32rpx; color: #333; } .desc { line-height: 1; padding: 0 20rpx 30rpx; font-size: 24rpx; color: #cf4444; } } .action { padding-left: 20rpx; .item { height: 90rpx; padding-right: 60rpx; border-bottom: 1rpx solid #eaeaea; font-size: 26rpx; color: #333; position: relative; display: flex; align-items: center; &:last-child { border-bottom: 0 none; } } .label { width: 60rpx; color: #898b94; margin: 0 16rpx 0 10rpx; } .text { flex: 1; -webkit-line-clamp: 1; } } } /* 商品详情 */ .detail { padding-left: 20rpx; .content { margin-left: -20rpx; .image { width: 100%; } } .properties { padding: 0 20rpx; margin-bottom: 30rpx; .item { display: flex; line-height: 2; padding: 10rpx; font-size: 26rpx; color: #333; border-bottom: 1rpx dashed #ccc; } .label { width: 200rpx; } .value { flex: 1; } } } /* 同类推荐 */ .similar { .content { padding: 0 20rpx 200rpx; background-color: #f4f4f4; display: flex; flex-wrap: wrap; .goods { width: 340rpx; padding: 24rpx 20rpx 20rpx; margin: 20rpx 7rpx; border-radius: 10rpx; background-color: #fff; } .image { width: 300rpx; height: 260rpx; } .name { height: 80rpx; margin: 10rpx 0; font-size: 26rpx; color: #262626; } .price { line-height: 1; font-size: 20rpx; color: #cf4444; } .number { font-size: 26rpx; margin-left: 2rpx; } } navigator { &:nth-child(even) { margin-right: 0; } } } /* 底部工具栏 */ .toolbar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 1; background-color: #fff; height: 100rpx; padding: 0 20rpx var(--window-bottom); border-top: 1rpx solid #eaeaea; display: flex; justify-content: space-between; align-items: center; box-sizing: content-box; .buttons { display: flex; & > view { width: 220rpx; text-align: center; line-height: 72rpx; font-size: 26rpx; color: #fff; border-radius: 72rpx; } .addcart { background-color: #ffa868; } .buynow, .payment { background-color: #27ba9b; margin-left: 20rpx; } } .icons { padding-right: 10rpx; display: flex; align-items: center; flex: 1; .icons-button { flex: 1; text-align: center; line-height: 1.4; padding: 0; margin: 0; border-radius: 0; font-size: 20rpx; color: #333; background-color: #fff; &::after { border: none; } } text { display: block; font-size: 34rpx; } } } </style>
我们写入就可以看到了是为什么,因为之前我们在这里已经提前写好了
怎么接受Id?
下面我们就可以封装接口了
调用接口
类型定义:
import type { GoodsItem } from './global' /** 商品信息 */ export type GoodsResult = { /** id */ id: string /** 商品名称 */ name: string /** 商品描述 */ desc: string /** 当前价格 */ price: number /** 原价 */ oldPrice: number /** 商品详情: 包含详情属性 + 详情图片 */ details: Details /** 主图图片集合[ 主图图片链接 ] */ mainPictures: string[] /** 同类商品[ 商品信息 ] */ similarProducts: GoodsItem[] /** sku集合[ sku信息 ] */ skus: SkuItem[] /** 可选规格集合备注[ 可选规格信息 ] */ specs: SpecItem[] /** 用户地址列表[ 地址信息 ] */ userAddresses: AddressItem[] } /** 商品详情: 包含详情属性 + 详情图片 */ export type Details = { /** 商品属性集合[ 属性信息 ] */ properties: DetailsPropertyItem[] /** 商品详情图片集合[ 图片链接 ] */ pictures: string[] } /** 属性信息 */ export type DetailsPropertyItem = { /** 属性名称 */ name: string /** 属性值 */ value: string } /** sku信息 */ export type SkuItem = { /** id */ id: string /** 库存 */ inventory: number /** 原价 */ oldPrice: number /** sku图片 */ picture: string /** 当前价格 */ price: number /** sku编码 */ skuCode: string /** 规格集合[ 规格信息 ] */ specs: SkuSpecItem[] } /** 规格信息 */ export type SkuSpecItem = { /** 规格名称 */ name: string /** 可选值名称 */ valueName: string } /** 可选规格信息 */ export type SpecItem = { /** 规格名称 */ name: string /** 可选值集合[ 可选值信息 ] */ values: SpecValueItem[] } /** 可选值信息 */ export type SpecValueItem = { /** 是否可售 */ available: boolean /** 可选值备注 */ desc: string /** 可选值名称 */ name: string /** 可选值图片链接 */ picture: string } /** 地址信息 */ export type AddressItem = { /** 收货人姓名 */ receiver: string /** 联系方式 */ contact: string /** 省份编码 */ provinceCode: string /** 城市编码 */ cityCode: string /** 区/县编码 */ countyCode: string /** 详细地址 */ address: string /** 默认地址,1为是,0为否 */ isDefault: number /** 收货地址 id */ id: string /** 省市区 */ fullLocation: string }
先进行简单渲染
我们看一下效果