详情模块-效果图
详情模块-静态结构
src\pages\goods\index.vue
vue
<template>
<view class="goods">
<!-- 返回按钮 -->
<GoBackBtn />
<scroll-view scroll-y class="viewport">
<!-- 商品信息 -->
<view class="goods anchor" data-anchor-index="0">
<!-- 轮播图 -->
<view class="preview">
<swiper autoplay circular>
<swiper-item
v-for="(item, index) in []"
:key="index"
>
<image :src="item" />
</swiper-item>
</swiper>
<!-- 指示器 -->
<view class="indicator">
<text class="current">{{ 0 }}</text>
<text class="split">/</text>
<text class="total">{{ 0 }}</text>
</view>
</view>
</view>
<!-- 商品评价 - 静态结构 - 没有接口不需要处理 -->
<!-- 商品详情 -->
<!-- 常见问题 -->
<!-- 推荐 -->
</scroll-view>
<!-- 用户操作 -->
<!-- 弹出层 -->
<!-- SKU -->
</view>
</template>
<script>
// id=1188006
export default {};
</script>
<style lang="scss">
page {
height: 100%;
overflow: hidden;
display: flex;
flex-direction: column;
}
/* 自定义导航栏 */
.navbar {
width: 750rpx;
background-color: #fff;
position: fixed;
top: 0;
left: 0;
z-index: 9;
.search {
height: 40px;
padding: 1px 110px 0 50px;
.input {
height: 62rpx;
border-radius: 60rpx;
font-size: 26rpx;
color: #8b8b8b;
background-color: #f3f4f4;
position: relative;
&::before {
position: absolute;
left: 24rpx;
top: 50%;
color: #b7b7b7;
font-size: 28rpx;
transform: translateY(-50%);
}
}
}
.wrap {
position: relative;
}
.back {
position: absolute;
left: 10px;
top: 2px;
z-index: 9;
display: flex;
justify-content: center;
align-items: center;
width: 60rpx;
height: 60rpx;
border-radius: 50%;
font-size: 23px;
color: #191919;
}
.tabs {
display: flex;
justify-content: space-evenly;
border-bottom: 1rpx solid #eaeaea;
text {
display: block;
padding: 10rpx 10rpx 16rpx;
font-size: 28rpx;
position: relative;
}
.active {
color: #27ba9b;
font-weight: 500;
&::after {
content: "";
position: absolute;
left: 18rpx;
right: 20rpx;
bottom: 14rpx;
height: 4rpx;
background-color: #27ba9b;
}
}
}
}
.viewport {
background-color: #f4f4f4;
height: 100vh;
}
.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;
height: 100%;
display: flex;
flex-direction: column;
flex: 1;
.preview {
height: 750rpx;
position: relative;
.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;
}
}
.indicator {
.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;
}
.remarks {
line-height: 1;
padding: 0 20rpx 30rpx;
font-size: 24rpx;
color: #cf4444;
}
}
.related {
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;
}
}
}
/* 商品评论 */
.comments {
padding-left: 20rpx;
.comment {
padding: 24rpx 40rpx 24rpx 10rpx;
border-top: 1rpx solid #eaeaea;
}
.caption {
height: 60rpx;
display: flex;
justify-content: space-between;
align-items: center;
.avatar {
width: 60rpx;
height: 60rpx;
margin-right: 20rpx;
border-radius: 50%;
}
}
.user {
font-size: 26rpx;
color: #333;
display: flex;
align-items: center;
}
.rating {
width: 144rpx;
height: 24rpx;
background-image: url(https://static.botue.com/erabbit/static/images/rating_off.png);
background-size: contain;
.rank {
height: 100%;
background-image: url(https://static.botue.com/erabbit/static/images/rating_on.png);
background-size: 144rpx 24rpx;
}
}
.content {
.text {
line-height: 1.4;
margin-top: 24rpx;
font-size: 24rpx;
color: #333;
}
.extra {
display: flex;
justify-content: space-between;
margin: 20rpx 1rpx 0 0;
font-size: 22rpx;
color: #666;
}
}
.pictures {
display: flex;
flex-wrap: wrap;
margin: 20rpx 0 0 1rpx;
}
.picture {
width: 150rpx;
height: 150rpx;
margin-right: 27rpx;
&:last-child {
margin-right: 0;
}
}
}
/* 类似商品 */
.similar {
margin-top: 20rpx;
.bar {
display: flex;
align-items: center;
height: 90rpx;
font-size: 28rpx;
color: #333;
background-color: #fff;
text {
flex: 1;
text-align: center;
position: relative;
}
.active {
&::after {
content: "";
display: block;
width: 60rpx;
height: 4rpx;
background-color: #27ba9b;
transform: translateX(-50%);
position: absolute;
left: 50%;
bottom: -5rpx;
}
}
}
.content {
padding-top: 20rpx;
background-color: #f4f4f4;
white-space: nowrap;
navigator {
display: inline-block;
width: 200rpx;
height: 270rpx;
padding: 15rpx 15rpx 0;
margin-right: 15rpx;
background-color: #fff;
border-radius: 6rpx;
&:first-child {
margin-left: 15rpx;
}
}
image {
height: 172rpx;
}
.name {
max-height: 64rpx;
line-height: 1.2;
margin-top: 10rpx;
font-size: 24rpx;
color: #333;
-webkit-line-clamp: 1;
}
.price {
font-size: 18rpx;
color: #cf4444;
}
.number {
font-size: 24rpx;
margin-left: 2rpx;
}
}
}
/* 商品详情 */
.detail {
padding-left: 20rpx;
.content {
margin-left: -20rpx;
}
.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;
}
}
}
/* 常见问题 */
.help {
display: flex;
align-items: center;
padding: 20rpx 0 20rpx 20rpx;
margin-top: 20rpx;
font-size: 28rpx;
color: #333;
background-color: #fff;
position: relative;
.icon-help {
font-size: 34rpx;
margin-right: 6rpx;
color: #ffa868;
}
}
/* 商品推荐 */
.recommend {
padding-left: 20rpx;
.content {
padding: 0 20rpx 20rpx;
margin-left: -20rpx;
background-color: #f4f4f4;
overflow: hidden;
navigator {
width: 345rpx;
padding: 24rpx 20rpx 20rpx;
margin: 20rpx 20rpx 0 0;
border-radius: 10rpx;
background-color: #fff;
float: left;
}
.image {
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 {
height: 120rpx;
padding: 0 20rpx;
border-top: 1rpx solid #eaeaea;
display: flex;
justify-content: space-between;
align-items: center;
.buttons {
display: flex;
& > view {
width: 220rpx;
text-align: center;
line-height: 72rpx;
font-size: 26rpx;
color: #fff;
border-radius: 72rpx;
}
.addcart {
background-color: #ffa868;
}
.payment {
background-color: #27ba9b;
margin-left: 20rpx;
}
}
.icons {
padding-right: 10rpx;
display: flex;
align-items: center;
justify-content: space-evenly;
flex: 1;
button {
text-align: center;
line-height: 1.4;
padding: 0;
border-radius: 0;
font-size: 20rpx;
color: #333;
background-color: #fff;
}
text {
display: block;
font-size: 34rpx;
}
}
}
</style>
返回按钮
目标:
- 普通的页面自带返回按钮,但是自定义导航的页面需要自己封装返回按钮
- 点击返回按钮时,如果有上一页,就返回上一页,如果没有上一页,就返回首页
思路:关键API getCurrentPages
静态结构:
src\components\GoBackBtn\GoBackBtn.vue
vue
<template>
<view :style="{top: capButton.top +'px'}" class="back icon-left" />
</template>
<script>
import {mapState} from "vuex";
export default {
computed: {
...mapState(['capButton'])
},
};
</script>
<style>
.back {
position: absolute;
left: 50rpx;
z-index: 9;
display: flex;
justify-content: center;
align-items: center;
width: 60rpx;
height: 60rpx;
border-radius: 50%;
font-size: 23px;
color: #fff;
background-color: rgba(0, 0, 0, 0.5);
}
</style>
代码:
src\components\GoBackBtn\GoBackBtn.vue
js
methods: {
onBack() {
const pages = getCurrentPages();
if(pages.length > 1){
uni.navigateBack();
}else {
uni.switchTab({url: '/pages/index/index'})
}
},
},
请求数据
src/api/goods.js
js
import http from "@/utils/http";
/**
* 商品详情
*/
export const getGoodsDetailAPI = (id) => {
return http({
url: "/goods",
data: { id },
});
};
vue
<script>
import { getGoodsDetailAPI } from "@/api/goods";
export default {
data() {
return {
goods: {},
};
},
onLoad({ id }) {
this.loadData()
},
methods:{
async lodaData(id){
const { result } = await getGoodsDetailAPI(id);
this.goods = result;
}
}
};
</script>
商品信息-轮播图
diff
<view class="goods anchor" data-anchor-index="0">
<!-- 轮播图 -->
<view class="preview">
<swiper
autoplay
circular
+ @change="current = $event.detail.current"
>
<swiper-item
- v-for="(item, index) in []"
+ v-for="(item, index) in goods.mainPictures"
:key="index"
>
<image :src="item" />
</swiper-item>
</swiper>
<!-- 指示器 -->
<view class="indicator">
+ <text class="current">{{ current + 1 }}</text>
<text class="split">/</text>
+ <text class="total">{{ goods.mainPictures ? goods.mainPictures.length : '' }} </text>
</view>
</view>
</view>
商品信息-名称和价格
vue
<!-- 轮播图 -->
<!-- 名称和价格 -->
<view class="meta">
<view class="price">
<text class="symbol">¥</text>
<text class="number">{{ 0}}</text>
</view>
<view class="brand">
<image mode="aspectFill" />
</view>
<view class="name ellipsis">
{{ '名称' }}
</view>
<view class="remarks"> {{ '描述' }} </view>
</view>
diff
<!-- 轮播图 -->
<!-- 名称和价格 -->
<view class="meta">
<view class="price">
<text class="symbol">¥</text>
+ <text class="number">{{ goods.price }}</text>
</view>
<view class="brand">
<image mode="aspectFill"
+ :src="goods.brand.picture"
/>
</view>
<view class="name ellipsis">
+ {{ goods.name }}
</view>
<view class="remarks">
+ {{ goods.desc }}
</view>
</view>
规格参数-Todo
vue
<!-- 名称和价格 -->
<!-- 规格参数 -->
<view class="related">
<view class="item arrow">
<text class="label">选择</text>
<text class="text ellipsis">
{{ '白色 红外体温计 1件' || "请选择商品规格" }}
</text>
</view>
<view class="item arrow">
<text class="label">送至</text>
<text class="text ellipsis">北京市顺义区京顺路9号黑马程序员</text>
</view>
<view class="item arrow">
<text class="label">服务</text>
<text class="text ellipsis">无忧退 快速退款 免费包邮</text>
</view>
</view>
商品评价
纯静态结构
vue
<!-- 商品评价 - 静态结构 - 没有接口不需要处理 -->
<view class="comments panel anchor" data-anchor-index="1">
<view class="title arrow">
<text>评价</text>
<navigator url="/pages/comments/index" hover-class="none" class="more"
>好评度 70%</navigator
>
</view>
<view class="comment">
<view class="caption">
<view class="user">
<image
class="avatar"
src="https://static.botue.com/erabbit/static/uploads/avatar_2.jpg"
/>
<text>白月初</text>
</view>
<view class="rating">
<view class="rank" style="width: 80%"></view>
</view>
</view>
<view class="content">
<view class="text"> 质量不错,灵敏度高,结构巧妙,款式也好看 </view>
<view class="pictures">
<view class="picture">
<image
src="https://static.botue.com/erabbit/static/uploads/comment_1.jpg"
/>
</view>
<view class="picture">
<image
src="https://static.botue.com/erabbit/static/uploads/comment_2.jpg"
/>
</view>
<view class="picture">
<image
src="https://static.botue.com/erabbit/static/uploads/comment_2.jpg"
/>
</view>
</view>
<view class="extra">
<text class="date">购买时间: 2020-11-11</text>
<text class="type">黑色 公开版 128G</text>
</view>
</view>
</view>
<view class="comment">
<view class="caption">
<view class="user">
<image
class="avatar"
src="https://static.botue.com/erabbit/static/uploads/avatar_3.jpg"
/>
<text>白月初</text>
</view>
<view class="rating">
<view class="rank" style="width: 60%"></view>
</view>
</view>
<view class="content">
<view class="text"> 质量不错,灵敏度高,结构巧妙,款式也好看 </view>
<view class="pictures">
<view class="picture">
<image
src="https://static.botue.com/erabbit/static/uploads/comment_1.jpg"
/>
</view>
<view class="picture">
<image
src="https://static.botue.com/erabbit/static/uploads/comment_2.jpg"
/>
</view>
<view class="picture">
<image
src="https://static.botue.com/erabbit/static/uploads/comment_2.jpg"
/>
</view>
<view class="picture">
<image
src="https://static.botue.com/erabbit/static/uploads/comment_1.jpg"
/>
</view>
</view>
<view class="extra">
<text class="date">购买时间: 2020-11-11</text>
<text class="type">黑色 公开版 128G</text>
</view>
</view>
</view>
</view>
商品详情
vue
<!-- 商品信息 -->
<!-- 商品评价 - 静态结构 - 没有接口不需要处理 -->
<!-- 商品详情 -->
<view class="detail panel anchor" data-anchor-index="2">
<view class="title">
<text>详情</text>
</view>
<view class="content">
<view class="properties">
<!-- 商品详情属性 -->
<view
class="item"
v-for="item in []"
:key="item.name"
>
<text class="label">{{ item.name }}</text>
<text class="value">{{ item.value }}</text>
</view>
</view>
<!-- 商品详情图片 -->
<image
mode="widthFix"
v-for="(item, index) in []"
:key="index"
:src="item"
/>
</view>
</view>
diff
<!-- 商品信息 -->
<!-- 商品评价 - 静态结构 - 没有接口不需要处理 -->
<!-- 商品详情 -->
<view class="detail panel anchor" data-anchor-index="2">
<view class="title">
<text>详情</text>
</view>
<view class="content">
<view class="properties">
<!-- 商品详情属性 -->
<view
class="item"
+ v-for="item in goods.details.properties"
:key="item.name"
>
<text class="label">{{ item.name }}</text>
<text class="value">{{ item.value }}</text>
</view>
</view>
<!-- 商品详情图片 -->
<image
mode="widthFix"
+ v-for="(item, index) in goods.details.pictures"
:key="index"
:src="item"
/>
</view>
</view>
常见问题
vue
<!-- 商品信息 -->
<!-- 商品评价 - 静态结构 - 没有接口不需要处理 -->
<!-- 商品详情 -->
<!-- 常见问题 -->
<view class="help arrow">
<text class="icon-help"></text>
<view hover-class="none">常见问题</view>
</view>
推荐
请求数据、渲染界面
api/goods.js
js
/**
* 同类推荐(也支持猜你喜欢)
* id 传入代表查询相关商品,不传代表查询猜你喜欢
* limit 查询数量
*/
export const getGoodsRelevantAPI = (id, limit = 4) => {
return http({
url: "/goods/relevant",
data: {
id,
limit,
},
});
};
diff
<script>
import {
getGoodsDetailAPI,
+ getGoodsRelevantAPI
} from "@/api/goods";
export default {
data() {
return {
goods: {},
current: 0,
+ goodsRelevants: [],
};
},
methods: {
async loadData(id) {
const { result } = await getGoodsDetailAPI(id);
this.goods = result;
},
+ async loadRecommend(id) {
+ const { result } = await getGoodsRelevantAPI(id);
+ this.goodsRelevants = result;
+ },
},
onLoad({ id }) {
this.loadData(id);
+ this.loadRecommend(id);
},
};
</script>
vue
<!-- 商品信息 -->
<!-- 商品评价 - 静态结构 - 没有接口不需要处理 -->
<!-- 商品详情 -->
<!-- 常见问题 -->
<!-- 推荐 -->
<view class="recommend panel anchor" data-anchor-index="3">
<view class="title">
<text>推荐</text>
</view>
<view class="content">
<navigator
v-for="item in goodsRelevants"
:key="item.id"
:url="`/pages/goods/index?id=${item.id}`"
hover-class="none"
>
<image class="image" mode="aspectFit" :src="item.picture"></image>
<view class="name ellipsis">
{{ item.name }}
</view>
<view class="price">
<text class="symbol">¥</text>
<text class="number">{{ item.price }}</text>
</view>
</navigator>
</view>
</view>
4个弹出层菜单组件
Clause-服务条款
src\pages\goods\components\Clause\index.vue
vue
<template>
<view>
<view class="title">服务说明</view>
<view class="content">
<view class="item">
<view class="dt">无忧退货</view>
<view class="dd"
>自收到商品之日起30天内,可在线申请无忧退货服务(内
裤、食品等特殊商品除外)</view
>
</view>
<view class="item">
<view class="dt">快速退款</view>
<view class="dd"
>收到退货包裹并确认无误后,将在48小时内办理退款,
退款将原路返回,不同银行处理时间不同,预计1-5个工作日到账</view
>
</view>
<view class="item">
<view class="dt">满88元免邮费</view>
<view class="dd"
>单笔订单金额(不含运费)满88元可免邮费,不满88元,
单笔订单收取10元邮费</view
>
</view>
</view>
</view>
</template>
<style>
.content {
padding: 20rpx 10rpx 100rpx 20rpx !important;
}
.item {
margin-top: 20rpx;
}
.dt {
margin-bottom: 10rpx;
font-size: 28rpx;
color: #333;
font-weight: 500;
position: relative;
}
.dt::before {
content: "";
width: 10rpx;
height: 10rpx;
border-radius: 50%;
background-color: #eaeaea;
transform: translateY(-50%);
position: absolute;
top: 50%;
left: -20rpx;
}
.dd {
line-height: 1.6;
font-size: 26rpx;
color: #999;
}
</style>
Helps-帮助
src\pages\goods\components\Helps\index.vue
vue
<template>
<view>
<view class="title">常见问题</view>
<view class="content">
<view class="item">
<view class="dt">购买运费如何收取</view>
<view class="dd"
>单笔订单金额(不含运费)满88元免邮;不满88元,每单收取10元运费。(港澳台地区需满500元免邮费;不满500元,每单收取30元运费)</view
>
</view>
<view class="item">
<view class="dt">使用什么快递发货</view>
<view class="dd">默认使用顺丰快递发货(个别商品使用其它快递)</view>
<view class="dd">配送范围覆盖全国大部分地区(港澳台地区除外)</view>
</view>
<view class="item">
<view class="dt">如何申请退货</view>
<view class="dd"
>1.
自收到商品之日起30日内,客户可申请无忧退货,退款将原路返还,不同的银行处理时间不同,预计1-5个工作日到账;</view
>
<view class="dd"
>2.
因小兔鲜儿产生的退货,如质量问题,退货邮费由小兔鲜儿承担,退款完成后会以现金券的形式报销,因客户个人原因产生的退货,购买和寄回运费由客户个人承担</view
>
</view>
</view>
</view>
</template>
<style>
.content {
padding: 20rpx 10rpx 100rpx 20rpx !important;
}
.item {
margin-top: 20rpx;
}
.dt {
margin-bottom: 10rpx;
font-size: 28rpx;
color: #333;
font-weight: 500;
position: relative;
}
.dt::before {
content: "";
width: 10rpx;
height: 10rpx;
border-radius: 50%;
background-color: #eaeaea;
transform: translateY(-50%);
position: absolute;
top: 50%;
left: -20rpx;
}
.dd {
line-height: 1.6;
font-size: 26rpx;
color: #999;
}
</style>
Shipment-快递
src\pages\goods\components\Shipment\index.vue
vue
<template>
<view>
<view class="title">配送至</view>
<view class="shipment">
<view class="item">
<view class="user">李明 13824686868</view>
<view class="address">北京市顺义区后沙峪地区安平北街6号院</view>
<text class="icon icon-checked"></text>
</view>
<view class="item">
<view class="user">王东 13824686868</view>
<view class="address">北京市顺义区后沙峪地区安平北街6号院</view>
<text class="icon icon-ring"></text>
</view>
<view class="item">
<view class="user">张三 13824686868</view>
<view class="address">北京市朝阳区孙河安平北街6号院</view>
<text class="icon icon-ring"></text>
</view>
</view>
<view class="footer">
<view class="button primary"> 新建地址 </view>
<view v-if="false" class="button primary">确定</view>
</view>
</view>
</template>
<style>
.shipment {
min-height: 300rpx;
max-height: 540rpx;
overflow: auto;
padding: 20rpx 10rpx !important;
}
.shipment .item {
padding: 30rpx 50rpx 30rpx 60rpx;
background-size: 40rpx;
background-repeat: no-repeat;
background-position: 0 center;
background-image: url(https://static.botue.com/erabbit/static/images/locate.png);
position: relative;
}
.shipment .item .icon {
color: #999;
font-size: 40rpx;
transform: translateY(-50%);
position: absolute;
top: 50%;
right: 0;
}
.shipment .item .icon-checked {
color: #27ba9b;
}
.shipment .item .icon-ring {
color: #444;
}
.shipment .item .user {
font-size: 28rpx;
color: #444;
font-weight: 500;
}
.shipment .item .address {
font-size: 26rpx;
color: #666;
}
</style>
SKU 商品选择
src\pages\goods\components\Sku\index.vue
vue
<template>
<view>
<view class="header">
<image
class="thumb"
src="https://static.botue.com/erabbit/static/uploads/goods_preview_1.jpg"
></image>
<view class="wrap">
<view class="price">
<view class="discount">
<text class="symbol">¥</text>
<text class="number">129</text>
<text class="decimal">.00</text>
</view>
<view class="original">
<text class="symbol">¥</text>
<text class="number">199</text>
<text class="decimal">.00</text>
</view>
</view>
<view class="extra">
<text class="text">重量: 0.2kg</text>
<text class="text">编号: 676587698</text>
</view>
</view>
</view>
<view class="body">
<view class="specs">
<view class="label">颜色</view>
<view class="section">
<view class="item checked">白色</view>
<view class="item">黑色</view>
<view class="item">灰色</view>
<view class="item">卡其色</view>
</view>
<view class="label">类型</view>
<view class="section">
<view class="item">红外体温计</view>
<view class="item disabled">双模</view>
<view class="item">灵敏</view>
<view class="item">便携式</view>
</view>
</view>
<view class="number">
<view class="label">数量</view>
<view class="counter">
<text class="text disabled">-</text>
<input type="text" class="input" value="1" />
<text class="text">+</text>
</view>
</view>
</view>
<view class="footer">
<!-- <view class="button secondary" >加入购物车</view > -->
<view class="button primary">立即购买</view>
</view>
</view>
</template>
<style>
.header {
display: flex;
padding: 30rpx 0 !important;
}
.header .thumb {
width: 180rpx;
height: 180rpx;
margin-right: 20rpx;
border-radius: 8rpx;
}
.header .wrap {
display: flex;
flex-direction: column;
justify-content: flex-end;
}
.header .price {
display: flex;
align-items: baseline;
}
.header .price .discount {
font-size: 40rpx;
color: #cf4444;
}
.header .price .original {
font-size: 28rpx;
margin-left: 20rpx;
color: #999;
text-decoration: line-through;
}
.header .symbol,
.header .decimal {
font-size: 70%;
}
.header .extra {
margin-bottom: 10rpx;
font-size: 22rpx;
color: #666;
}
.header .extra .text {
margin-right: 10rpx;
}
.body {
height: 540rpx !important;
overflow: auto;
}
.body .label {
margin: 10rpx 0 20rpx;
color: #333;
font-weight: 500;
font-size: 26rpx;
}
.body .specs .section {
overflow: hidden;
}
.body .specs .item {
min-width: 100rpx;
text-align: center;
line-height: 1;
padding: 10rpx 30rpx;
margin: 0 20rpx 20rpx 0;
border-radius: 50rpx;
color: #444;
font-size: 26rpx;
border: 1rpx solid #f3f4f4;
background-color: #f3f4f4;
float: left;
}
.body .specs .checked {
color: rgba(39, 186, 155, 0.8);
border: 1rpx solid rgba(39, 186, 155, 0.3);
background-color: rgba(39, 186, 155, 0.1);
}
.body .specs .disabled {
opacity: 0.6;
border: 1rpx dashed #999;
}
.body .number {
display: flex;
justify-content: space-between;
align-items: center;
height: 80rpx;
margin-top: 30rpx;
}
.body .number .counter {
display: flex;
}
.body .counter .input {
display: block;
width: 100rpx;
height: 48rpx;
text-align: center;
border-radius: 4rpx;
font-size: 24rpx;
color: #444;
background-color: #f6f6f6;
}
.body .counter .text {
display: block;
width: 48rpx;
height: 48rpx;
text-align: center;
line-height: 48rpx;
font-size: 32rpx;
}
.body .counter .disabled {
color: #999;
}
</style>
弹出层
vue
<uni-popup ref="popup" type="bottom" background-color="#fff">
<view class="popup-root">
<text class="close icon-close"></text>
<!-- 4个组件 -->
</view>
</uni-popup>
目标:用到了uni-ui中提供的弹出层组件 uni-popup
,主要在以下区域使用
步骤:
- 声明数据:
showType:''
showType
与v-show
配合, 做条件渲染- 点击事件,修改showType的值, 并且打开弹出层
- 点击关闭,关闭弹出层
代码:
1、声明数据:showType:''
js
data() {
return {
// ... 省略其它代码...
showType: ''
};
},
2、showType
与v-show
配合, 做条件渲染
js
import Sku from "./components/Sku";
import Shipment from "./components/Shipment";
import Clause from "./components/Clause";
import Helps from "./components/Helps";
// id=1188006
export default {
components: {
Sku,
Shipment,
Clause,
Helps,
},
}
diff
<uni-popup ref="popup" type="bottom" background-color="#fff">
<view class="popup-root">
<text class="close icon-close"></text>
💥💥 记得注册组件
+ <Sku v-show="showType === 'sku'" /></Sku>
+ <Shipment v-show="showType === 'shipment'" />
+ <Clause v-show="showType === 'clause'" />
+ <Helps v-show="showType === 'helps'" />
</view>
</uni-popup>
3、点击事件,修改showType的值, 并且打开弹出层
js
onShowPopup(type) {
this.showType = type;
this.$refs.popup.open();
},
用户操作
vue
<template>
<view class="goods">
<!-- 返回按钮 -->
<scroll-view scroll-y class="viewport">
<!-- 商品信息 -->
<!-- 商品评价 - 静态结构 - 没有接口不需要处理 -->
<!-- 商品详情 -->
<!-- 常见问题 -->
<!-- 推荐 -->
</scroll-view>
<!-- 用户操作 -->
<view class="toolbar">
<view class="icons">
<button class="collect"><text class="icon-heart"></text>收藏</button>
<button class="contact" open-type="contact">
<text class="icon-handset"></text>客服
</button>
<button class="cart" >
<text class="icon-cart"></text>购物车
</button>
</view>
<view class="buttons">
<view data-button-type="cart" class="addcart">
加入购物车
</view>
<view
data-button-type="payment"
class="payment"
>
立即购买
</view>
</view>
</view>
<!-- 弹出层 -->
<!-- SKU -->
</view>
</template>