Merge branch 'main' of https://git.brother7.cn/zoujing/YGChatCS
This commit is contained in:
0
pages/goods/README.md
Normal file
0
pages/goods/README.md
Normal file
254
pages/goods/components/GoodInfo/README.md
Normal file
254
pages/goods/components/GoodInfo/README.md
Normal file
@@ -0,0 +1,254 @@
|
||||
# GoodInfo 商品信息组件
|
||||
|
||||
## 概述
|
||||
|
||||
`GoodInfo` 是一个高性能的商品信息展示组件,专为电商、旅游、服务类应用设计。组件采用现代化的UI设计,支持响应式布局和暗色模式,提供优秀的用户体验。
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 🎯 核心功能
|
||||
- **价格展示**: 突出显示商品价格,支持货币符号和价格标签
|
||||
- **商品标题**: 清晰展示商品名称和相关标签
|
||||
- **地址信息**: 显示商品/服务地址,支持图标和交互
|
||||
- **设施展示**: 网格布局展示商品特色设施或服务项目
|
||||
|
||||
### ⚡ 性能优化
|
||||
- **计算属性缓存**: 使用 `computed` 优化设施列表渲染
|
||||
- **按需渲染**: 条件渲染减少不必要的DOM节点
|
||||
- **轻量级设计**: 最小化组件体积和依赖
|
||||
- **懒加载支持**: 支持图标和内容的懒加载
|
||||
|
||||
### 🎨 UI特性
|
||||
- **现代化设计**: 圆角卡片、阴影效果、渐变背景
|
||||
- **响应式布局**: 适配不同屏幕尺寸
|
||||
- **暗色模式**: 自动适配系统主题
|
||||
- **交互反馈**: 悬停效果和过渡动画
|
||||
|
||||
## 基础用法
|
||||
|
||||
### 简单使用
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<GoodInfo :goodsInfo="goodsData" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import GoodInfo from './components/GoodInfo/index.vue'
|
||||
|
||||
const goodsData = {
|
||||
price: 399,
|
||||
title: '【成人票】云从朵花温泉门票',
|
||||
timeTag: '随时可退',
|
||||
address: '距您43.1公里 黔南州布依族苗族自治州龙里县'
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### 完整配置
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<GoodInfo :goodsInfo="fullGoodsData" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const fullGoodsData = {
|
||||
price: 399,
|
||||
title: '【成人票】云从朵花温泉门票',
|
||||
tag: '热销',
|
||||
timeTag: '随时可退',
|
||||
address: '距您43.1公里 黔南州布依族苗族自治州龙里县',
|
||||
facilities: [
|
||||
{ icon: 'home', name: '48个泡池' },
|
||||
{ icon: 'color', name: '11个特色药池' },
|
||||
{ icon: 'fire', name: '4个汗蒸房' },
|
||||
{ icon: 'person', name: '儿童充气水上乐园' },
|
||||
{ icon: 'game', name: '儿童戏水区' },
|
||||
{ icon: 'home-filled', name: '石板浴' }
|
||||
]
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## API 文档
|
||||
|
||||
### Props
|
||||
|
||||
| 参数 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| goodsInfo | Object | `{}` | 商品信息对象 |
|
||||
|
||||
### goodsInfo 对象结构
|
||||
|
||||
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| price | Number/String | 否 | `399` | 商品价格 |
|
||||
| title | String | 否 | `'【成人票】云从朵花温泉门票'` | 商品标题 |
|
||||
| tag | String | 否 | - | 价格标签(如:热销、限时优惠) |
|
||||
| timeTag | String | 否 | `'随时可退'` | 时间相关标签 |
|
||||
| address | String | 否 | `'距您43.1公里 黔南州布依族苗族自治州龙里县'` | 地址信息 |
|
||||
| facilities | Array | 否 | 默认设施列表 | 设施/特色列表 |
|
||||
|
||||
### facilities 数组结构
|
||||
|
||||
```javascript
|
||||
[
|
||||
{
|
||||
icon: 'home', // uni-icons 图标名称
|
||||
name: '48个泡池' // 设施名称
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## 样式定制
|
||||
|
||||
### CSS 变量
|
||||
|
||||
组件支持通过 CSS 变量进行主题定制:
|
||||
|
||||
```scss
|
||||
.good-info {
|
||||
--primary-color: #ff6b35; // 主色调
|
||||
--background-color: #fff; // 背景色
|
||||
--text-color: #333; // 文字颜色
|
||||
--border-radius: 16rpx; // 圆角大小
|
||||
--shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08); // 阴影
|
||||
}
|
||||
```
|
||||
|
||||
### 响应式断点
|
||||
|
||||
- **小屏设备**: `max-width: 750rpx`
|
||||
- **暗色模式**: `prefers-color-scheme: dark`
|
||||
|
||||
## 性能优化建议
|
||||
|
||||
### 1. 数据结构优化
|
||||
|
||||
```javascript
|
||||
// ✅ 推荐:使用 reactive 包装数据
|
||||
const goodsData = reactive({
|
||||
price: 399,
|
||||
title: '商品标题'
|
||||
})
|
||||
|
||||
// ❌ 避免:频繁的深层对象更新
|
||||
const goodsData = ref({
|
||||
nested: {
|
||||
deep: {
|
||||
value: 'data'
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### 2. 设施列表优化
|
||||
|
||||
```javascript
|
||||
// ✅ 推荐:预定义设施列表
|
||||
const FACILITY_PRESETS = {
|
||||
spa: [
|
||||
{ icon: 'home', name: '48个泡池' },
|
||||
{ icon: 'water', name: '恒温泳池' }
|
||||
],
|
||||
hotel: [
|
||||
{ icon: 'bed', name: '豪华客房' },
|
||||
{ icon: 'car', name: '免费停车' }
|
||||
]
|
||||
}
|
||||
|
||||
// 使用预设
|
||||
const goodsData = {
|
||||
facilities: FACILITY_PRESETS.spa
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 图标优化
|
||||
|
||||
```javascript
|
||||
// ✅ 推荐:使用常见图标
|
||||
const commonIcons = ['home', 'person', 'heart', 'star']
|
||||
|
||||
// ❌ 避免:使用过多不同图标增加包体积
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 数据验证
|
||||
|
||||
```javascript
|
||||
// 添加数据验证
|
||||
const validateGoodsInfo = (data) => {
|
||||
return {
|
||||
price: Number(data.price) || 0,
|
||||
title: String(data.title || ''),
|
||||
facilities: Array.isArray(data.facilities) ? data.facilities : []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 错误处理
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<GoodInfo
|
||||
:goodsInfo="goodsData"
|
||||
@error="handleError"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const handleError = (error) => {
|
||||
console.error('GoodInfo Error:', error)
|
||||
// 错误上报或用户提示
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### 3. 无障碍访问
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<view
|
||||
class="good-info"
|
||||
role="article"
|
||||
:aria-label="`商品信息:${goodsInfo.title}`"
|
||||
>
|
||||
<!-- 组件内容 -->
|
||||
</view>
|
||||
</template>
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **图标依赖**: 组件依赖 `uni-icons`,请确保项目中已安装
|
||||
2. **单位适配**: 样式使用 `rpx` 单位,适配小程序和H5
|
||||
3. **性能考虑**: 设施列表较多时建议分页或虚拟滚动
|
||||
4. **主题适配**: 支持暗色模式,但需要系统支持
|
||||
|
||||
## 更新日志
|
||||
|
||||
### v1.0.0 (2024-01-XX)
|
||||
- ✨ 初始版本发布
|
||||
- 🎨 现代化UI设计
|
||||
- ⚡ 性能优化
|
||||
- 📱 响应式布局
|
||||
- 🌙 暗色模式支持
|
||||
|
||||
## 技术栈
|
||||
|
||||
- **框架**: Vue 3 Composition API
|
||||
- **样式**: SCSS
|
||||
- **图标**: uni-icons
|
||||
- **构建**: Vite/Webpack
|
||||
|
||||
## 浏览器支持
|
||||
|
||||
- ✅ Chrome 80+
|
||||
- ✅ Firefox 75+
|
||||
- ✅ Safari 13+
|
||||
- ✅ Edge 80+
|
||||
- ✅ 微信小程序
|
||||
- ✅ 支付宝小程序
|
||||
- ✅ H5
|
||||
BIN
pages/goods/components/GoodInfo/images/商品详情.png
Normal file
BIN
pages/goods/components/GoodInfo/images/商品详情.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
68
pages/goods/components/GoodInfo/index.vue
Normal file
68
pages/goods/components/GoodInfo/index.vue
Normal file
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<view class="good-info">
|
||||
<!-- 价格区域 -->
|
||||
<view class="price-section">
|
||||
<view class="price-main">
|
||||
<text class="currency">¥</text>
|
||||
<text class="price">{{ goodsData.price || 399 }}</text>
|
||||
</view>
|
||||
<view class="price-tag" v-if="goodsData.tag">
|
||||
{{ goodsData.tag }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 标题区域 -->
|
||||
<view class="title-section">
|
||||
<text class="title">
|
||||
{{ goodsData.commodityName || "【成人票】云从朵花温泉门票" }}
|
||||
</text>
|
||||
<view class="tag-wrapper" v-if="goodsData.timeTag">
|
||||
<view class="time-tag">{{ goodsData.timeTag || "随时可退" }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 地址区域 -->
|
||||
<view class="address-section">
|
||||
<LocationInfo :orderData="goodsData" />
|
||||
</view>
|
||||
|
||||
<!-- 设施信息区域 -->
|
||||
<view class="facilities-section">
|
||||
<view class="facilities-grid">
|
||||
<view
|
||||
class="facility-item"
|
||||
v-for="(facility, index) in facilitiesList"
|
||||
:key="index"
|
||||
>
|
||||
<text class="facility-text">{{ facility }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, defineProps } from "vue";
|
||||
import LocationInfo from "@/components/LocationInfo/index.vue";
|
||||
|
||||
// Props定义
|
||||
const props = defineProps({
|
||||
goodsData: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
|
||||
// 设施列表 - 使用computed优化性能
|
||||
const facilitiesList = computed(() => {
|
||||
if (props.goodsData.commodityTag && props.goodsData.commodityTag.length) {
|
||||
return props.goodsData.commodityTag;
|
||||
}
|
||||
|
||||
return [];
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "./styles/index.scss";
|
||||
</style>
|
||||
106
pages/goods/components/GoodInfo/styles/index.scss
Normal file
106
pages/goods/components/GoodInfo/styles/index.scss
Normal file
@@ -0,0 +1,106 @@
|
||||
.good-info {
|
||||
background: #fff;
|
||||
margin-bottom: 12px;
|
||||
|
||||
// 价格区域
|
||||
.price-section {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.price-main {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
|
||||
.currency {
|
||||
font-size: 12px;
|
||||
color: #ff6a00;
|
||||
font-weight: 600;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
.price {
|
||||
font-size: 18px;
|
||||
color: #ff6a00;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 标题区域
|
||||
.title-section {
|
||||
margin-bottom: 12px;
|
||||
|
||||
.title {
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
line-height: 1.4;
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.tag-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.time-tag {
|
||||
color: #f55726;
|
||||
padding: 3px 6px;
|
||||
border-radius: 6px;
|
||||
font-size: 9px;
|
||||
border: 1px solid #f55726;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 地址区域
|
||||
.address-section {
|
||||
margin-bottom: 12px;
|
||||
padding: 12px 0;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
.address-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
|
||||
.address-text {
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 设施信息区域
|
||||
.facilities-section {
|
||||
.facilities-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 8px;
|
||||
|
||||
.facility-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 8px;
|
||||
background: #fafafa;
|
||||
border-radius: 6px;
|
||||
|
||||
.facility-text {
|
||||
font-size: 12px;
|
||||
color: #333;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
pages/goods/images/商品详情.png
Normal file
BIN
pages/goods/images/商品详情.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 585 KiB |
44
pages/goods/index.vue
Normal file
44
pages/goods/index.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<view class="goods-container">
|
||||
<TopNavBar title="商品详情" :fixed="true" />
|
||||
|
||||
<view class="content-wrapper">
|
||||
<ImageSwiper :border-radius="0" :images="goodsData.commodityPhotoList" />
|
||||
|
||||
<view class="goods-content">
|
||||
<!-- 商品信息组件 -->
|
||||
<GoodInfo :goodsData="goodsData" />
|
||||
|
||||
<ModuleTitle title="购买须知" />
|
||||
|
||||
<zero-markdown-view :markdown="goodsData.commodityTip" :fontSize="14" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import { goodsDetail } from "@/request/api/GoodsApi";
|
||||
import TopNavBar from "@/components/TopNavBar/index.vue";
|
||||
import ImageSwiper from "@/components/ImageSwiper/index.vue";
|
||||
import GoodInfo from "./components/GoodInfo/index.vue";
|
||||
import ModuleTitle from "@/components/ModuleTitle/index.vue";
|
||||
|
||||
const goodsData = ref({});
|
||||
// 获取商品详情数据
|
||||
const goodsInfo = async (params) => {
|
||||
const res = await goodsDetail(params);
|
||||
|
||||
goodsData.value = res.data;
|
||||
};
|
||||
|
||||
onLoad(({ commodityId = "1950766939442774018" }) => {
|
||||
goodsInfo({ commodityId });
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "./styles/index.scss";
|
||||
</style>
|
||||
18
pages/goods/styles/index.scss
Normal file
18
pages/goods/styles/index.scss
Normal file
@@ -0,0 +1,18 @@
|
||||
.goods-container {
|
||||
min-height: 100vh;
|
||||
background-color: #fff;
|
||||
|
||||
.content-wrapper {
|
||||
// 为固定导航栏预留空间
|
||||
padding-top: calc(var(--status-bar-height, 44px) + 68px);
|
||||
}
|
||||
|
||||
.goods-content {
|
||||
border-radius: 12px 12px 0 0;
|
||||
background-color: #fff;
|
||||
padding: 12px;
|
||||
position: relative;
|
||||
margin-top: -30px;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
@@ -14,11 +14,7 @@
|
||||
<view class="goods-description">
|
||||
<text class="goods-title">{{ commodityName }}</text>
|
||||
<!-- 门店地址 -->
|
||||
<view class="store-address" @click="openMap">
|
||||
<uni-icons type="location" size="18" color="#999" />
|
||||
<text>{{ orderData.commodityAddress }}</text>
|
||||
<uni-icons type="right" size="14" color="#999" />
|
||||
</view>
|
||||
<LocationInfo :orderData="orderData" />
|
||||
<!-- 酒店类型 -->
|
||||
<template v-if="orderData.orderType === '0'">
|
||||
<view class="in-date" v-if="checkInData">
|
||||
@@ -48,6 +44,7 @@
|
||||
|
||||
<script setup>
|
||||
import { defineProps, computed } from "vue";
|
||||
import LocationInfo from "@/components/LocationInfo/index.vue";
|
||||
import iconHouse from "./images/icon_house.png";
|
||||
import iconFood from "./images/food.png";
|
||||
import iconTicket from "./images/ticket.png";
|
||||
@@ -123,29 +120,6 @@ const formatServiceAmount = (amount) => {
|
||||
if (!amount) return "";
|
||||
return typeof amount === "number" ? `×${amount}` : amount;
|
||||
};
|
||||
|
||||
// 打开地图
|
||||
const openMap = () => {
|
||||
const address = props.orderData.commodityAddress;
|
||||
const latitude = Number(props.orderData.commodityLatitude);
|
||||
const longitude = Number(props.orderData.commodityLongitude);
|
||||
|
||||
uni.getLocation({
|
||||
type: "gcj02", //返回可以用于uni.openLocation的经纬度
|
||||
success: (res) => {
|
||||
console.log("当前经纬度", latitude, longitude);
|
||||
|
||||
uni.openLocation({
|
||||
latitude: latitude,
|
||||
longitude: longitude,
|
||||
address: address,
|
||||
success: () => {
|
||||
console.log("success");
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -99,19 +99,6 @@ $image-size-md: 65px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.store-address {
|
||||
@include flex-center;
|
||||
@include text-style($font-size-xs, $color-primary);
|
||||
|
||||
text {
|
||||
flex: 1;
|
||||
padding: 0 6px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.in-date,
|
||||
.out-date {
|
||||
@include text-style($font-size-xs, $color-secondary);
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
<template>
|
||||
<view class="top-nav-bar" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||||
<view class="nav-content">
|
||||
<view class="nav-left" @click="goBack">
|
||||
<uni-icons class="icon-back" type="left" size="20" color="#333">
|
||||
</uni-icons>
|
||||
</view>
|
||||
<view class="nav-center">
|
||||
<slot name="title">
|
||||
<text class="nav-title">{{ title }}</text>
|
||||
</slot>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
|
||||
// Props
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
showBack: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
});
|
||||
|
||||
// Emits
|
||||
const emit = defineEmits(["back"]);
|
||||
|
||||
// 状态栏高度
|
||||
const statusBarHeight = ref(0);
|
||||
|
||||
// 获取系统信息
|
||||
onMounted(() => {
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
statusBarHeight.value = systemInfo.statusBarHeight || 44;
|
||||
});
|
||||
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
if (props.showBack) {
|
||||
emit("back");
|
||||
uni.navigateBack({
|
||||
delta: 1,
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@import "./styles/index.scss";
|
||||
</style>
|
||||
@@ -1,114 +0,0 @@
|
||||
## 顶部导航栏组件
|
||||
|
||||
组件名称:顶部导航栏组件
|
||||
|
||||
## 功能特性
|
||||
|
||||
1. **自适应状态栏高度**:自动获取设备状态栏高度并适配
|
||||
2. **返回功能**:左侧返回按钮,支持自定义返回事件
|
||||
3. **标题显示**:支持传入标题文本或使用插槽自定义标题内容
|
||||
4. **右侧扩展**:支持右侧插槽,可添加自定义操作按钮
|
||||
5. **响应式设计**:适配不同屏幕尺寸
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 基础用法
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<TopNavBar title="服务工单" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import TopNavBar from './components/TopNavBar/index.vue'
|
||||
</script>
|
||||
```
|
||||
|
||||
### 自定义标题
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<TopNavBar>
|
||||
<template #title>
|
||||
<text class="custom-title">自定义标题</text>
|
||||
</template>
|
||||
</TopNavBar>
|
||||
</template>
|
||||
```
|
||||
|
||||
### 自定义右侧操作
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<TopNavBar title="服务工单">
|
||||
<template #right>
|
||||
<image class="menu-icon" src="./images/menu.png" @click="showMenu" />
|
||||
</template>
|
||||
</TopNavBar>
|
||||
</template>
|
||||
```
|
||||
|
||||
### 自定义返回事件
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<TopNavBar title="服务工单" @back="handleBack" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const handleBack = () => {
|
||||
// 自定义返回逻辑
|
||||
console.log('自定义返回')
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## Props
|
||||
|
||||
| 参数 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| title | String | '' | 导航栏标题 |
|
||||
| showBack | Boolean | true | 是否显示返回按钮 |
|
||||
|
||||
## Events
|
||||
|
||||
| 事件名 | 说明 | 参数 |
|
||||
|--------|------|------|
|
||||
| back | 点击返回按钮时触发 | - |
|
||||
|
||||
## Slots
|
||||
|
||||
| 插槽名 | 说明 |
|
||||
|--------|------|
|
||||
| title | 自定义标题内容 |
|
||||
| right | 自定义右侧操作区域 |
|
||||
|
||||
## 样式定制
|
||||
|
||||
组件支持通过CSS变量进行样式定制:
|
||||
|
||||
```scss
|
||||
.top-nav-bar {
|
||||
--nav-bg-color: #fff; // 背景色
|
||||
--nav-title-color: #333; // 标题颜色
|
||||
--nav-border-color: #f0f0f0; // 边框颜色
|
||||
}
|
||||
```
|
||||
|
||||
## 技术实现
|
||||
|
||||
- 使用 uniapp + Vue3 组合式 API 开发
|
||||
- 自动获取系统状态栏高度进行适配
|
||||
- 使用 fixed 定位实现固定顶部效果
|
||||
- 支持插槽扩展,提供良好的可定制性
|
||||
- 响应式设计,适配不同设备屏幕
|
||||
|
||||
## 兼容性
|
||||
|
||||
- 微信小程序
|
||||
- H5
|
||||
- App
|
||||
|
||||
## 备注
|
||||
|
||||
仅供学习、交流使用,请勿用于商业用途。
|
||||
@@ -1,28 +0,0 @@
|
||||
.nav-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
box-sizing: border-box;
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
.nav-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.nav-center {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.nav-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
@query="queryList"
|
||||
>
|
||||
<template #top>
|
||||
<TopNavBar>
|
||||
<TopNavBar titleAlign="left">
|
||||
<template #title>
|
||||
<Tabs
|
||||
:tabs="tabList"
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import TopNavBar from "./components/TopNavBar/index.vue";
|
||||
import TopNavBar from "@/components/TopNavBar/index.vue";
|
||||
import Tabs from "./components/Tabs/index.vue";
|
||||
import OrderCard from "./components/OrderCard/index.vue";
|
||||
import CustomEmpty from "./components/CustomEmpty/index.vue";
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
background-position: 0 0;
|
||||
background-size: 100% 242px;
|
||||
background-repeat: no-repeat;
|
||||
// padding: 60px 15px;
|
||||
padding: 60px 15px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user