feat: 调整项目结构
This commit is contained in:
342
src/components/ImageSwiper/README.md
Normal file
342
src/components/ImageSwiper/README.md
Normal file
@@ -0,0 +1,342 @@
|
||||
# ImageSwiper 轮播图组件
|
||||
|
||||
一个功能丰富的轮播图组件,支持自定义圆角、缩略图导航和图片描述。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- 🎨 **可配置圆角**:支持数字(px)或字符串形式的圆角设置
|
||||
- 📏 **可配置高度**:支持数字(px)或字符串形式的高度设置
|
||||
- 🖼️ **缩略图导航**:底部缩略图快速切换,支持左右滑动
|
||||
- 👁️ **缩略图控制**:可配置显示或隐藏缩略图
|
||||
- 📱 **响应式设计**:适配不同屏幕尺寸
|
||||
- 🎯 **自定义数据**:支持传入自定义图片数据
|
||||
- 📊 **进度指示器**:显示当前图片位置
|
||||
- 🎭 **选中状态**:缩略图选中时高亮显示,带缩放动画
|
||||
- 🔄 **自动滚动**:缩略图自动滚动到可视区域
|
||||
- ⚡ **性能优化**:使用计算属性优化渲染
|
||||
|
||||
## 基础用法
|
||||
|
||||
### 默认使用
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<ImageSwiper />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import ImageSwiper from '@/components/ImageSwiper/index.vue'
|
||||
</script>
|
||||
```
|
||||
|
||||
### 自定义圆角
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<!-- 数字形式 (px) -->
|
||||
<ImageSwiper :border-radius="12" />
|
||||
|
||||
<!-- 字符串形式 -->
|
||||
<ImageSwiper border-radius="1rem" />
|
||||
|
||||
<!-- 无圆角 -->
|
||||
<ImageSwiper :border-radius="0" />
|
||||
</template>
|
||||
```
|
||||
|
||||
### 自定义高度
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<!-- 数字形式 (px) -->
|
||||
<ImageSwiper :height="300" />
|
||||
|
||||
<!-- 字符串形式 -->
|
||||
<ImageSwiper height="50vh" />
|
||||
|
||||
<!-- 小高度轮播图 -->
|
||||
<ImageSwiper :height="120" />
|
||||
</template>
|
||||
```
|
||||
|
||||
### 隐藏缩略图
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<!-- 隐藏缩略图,只显示主轮播图 -->
|
||||
<ImageSwiper :show-thumbnails="false" />
|
||||
|
||||
<!-- 结合其他属性使用 -->
|
||||
<ImageSwiper
|
||||
:height="250"
|
||||
:border-radius="15"
|
||||
:show-thumbnails="false"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
### 自定义图片数据
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<ImageSwiper
|
||||
:border-radius="15"
|
||||
:images="customImages"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import ImageSwiper from '@/components/ImageSwiper/index.vue'
|
||||
|
||||
const customImages = ref([
|
||||
{
|
||||
photoUrl: "https://example.com/image1.jpg",
|
||||
photoName: "图片描述1"
|
||||
},
|
||||
{
|
||||
photoUrl: "https://example.com/image2.jpg",
|
||||
photoName: "图片描述2"
|
||||
}
|
||||
])
|
||||
</script>
|
||||
```
|
||||
|
||||
### 缩略图滑动功能
|
||||
|
||||
组件支持缩略图左右滑动,当图片数量较多时,缩略图会自动滚动到可视区域:
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<!-- 多图片展示,缩略图支持滑动 -->
|
||||
<ImageSwiper :images="manyImages" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const manyImages = ref([
|
||||
{ photoUrl: "https://example.com/1.jpg", photoName: "图片1" },
|
||||
{ photoUrl: "https://example.com/2.jpg", photoName: "图片2" },
|
||||
{ photoUrl: "https://example.com/3.jpg", photoName: "图片3" },
|
||||
// ... 更多图片
|
||||
{ photoUrl: "https://example.com/10.jpg", photoName: "图片10" }
|
||||
])
|
||||
</script>
|
||||
```
|
||||
|
||||
## API 文档
|
||||
|
||||
### Props
|
||||
|
||||
| 参数 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| borderRadius | Number \| String | 8 | 轮播图圆角大小,数字时单位为px |
|
||||
| height | Number \| String | 200 | 轮播图高度,数字时单位为px |
|
||||
| showThumbnails | Boolean | true | 是否显示缩略图 |
|
||||
| images | Array | [] | 图片数据数组,为空时使用默认数据 |
|
||||
|
||||
### images 数组结构
|
||||
|
||||
```typescript
|
||||
interface ImageItem {
|
||||
photoUrl: string; // 图片URL
|
||||
photoName: string; // 图片名称/描述
|
||||
}
|
||||
```
|
||||
|
||||
## 样式定制
|
||||
|
||||
### 圆角配置示例
|
||||
|
||||
```vue
|
||||
<!-- 小圆角 -->
|
||||
<ImageSwiper :border-radius="4" />
|
||||
|
||||
<!-- 中等圆角 -->
|
||||
<ImageSwiper :border-radius="12" />
|
||||
|
||||
<!-- 大圆角 -->
|
||||
<ImageSwiper :border-radius="24" />
|
||||
|
||||
<!-- 使用rem单位 -->
|
||||
<ImageSwiper border-radius="0.5rem" />
|
||||
|
||||
<!-- 使用百分比 -->
|
||||
<ImageSwiper border-radius="10%" />
|
||||
```
|
||||
|
||||
### 动态圆角控制
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<view>
|
||||
<slider
|
||||
:value="radius"
|
||||
:min="0"
|
||||
:max="50"
|
||||
@change="handleChange"
|
||||
/>
|
||||
<ImageSwiper :border-radius="radius" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const radius = ref(8)
|
||||
|
||||
const handleChange = (e) => {
|
||||
radius.value = e.detail.value
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## 高级用法
|
||||
|
||||
### 响应式配置
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<ImageSwiper
|
||||
:border-radius="responsiveRadius"
|
||||
:height="responsiveHeight"
|
||||
:show-thumbnails="showThumbnails"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
// 根据屏幕宽度动态调整圆角和高度
|
||||
const responsiveRadius = computed(() => {
|
||||
const screenWidth = uni.getSystemInfoSync().screenWidth
|
||||
return screenWidth > 750 ? 16 : 8
|
||||
})
|
||||
|
||||
const responsiveHeight = computed(() => {
|
||||
const screenWidth = uni.getSystemInfoSync().screenWidth
|
||||
return screenWidth > 750 ? 300 : 200
|
||||
})
|
||||
|
||||
// 动态控制缩略图显示
|
||||
const showThumbnails = ref(true)
|
||||
</script>
|
||||
```
|
||||
|
||||
### 动态控制示例
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<view>
|
||||
<!-- 控制面板 -->
|
||||
<view class="control-panel">
|
||||
<text>高度: {{ dynamicHeight }}px</text>
|
||||
<slider
|
||||
:value="dynamicHeight"
|
||||
:min="100"
|
||||
:max="400"
|
||||
@change="handleHeightChange"
|
||||
/>
|
||||
|
||||
<view class="checkbox-wrapper">
|
||||
<checkbox :checked="showThumbnails" @change="handleThumbnailToggle" />
|
||||
<text>显示缩略图</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 轮播图组件 -->
|
||||
<ImageSwiper
|
||||
:height="dynamicHeight"
|
||||
:show-thumbnails="showThumbnails"
|
||||
:border-radius="10"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const dynamicHeight = ref(200)
|
||||
const showThumbnails = ref(true)
|
||||
|
||||
const handleHeightChange = (e) => {
|
||||
dynamicHeight.value = e.detail.value
|
||||
}
|
||||
|
||||
const handleThumbnailToggle = (e) => {
|
||||
showThumbnails.value = e.detail.value
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### 主题适配
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<ImageSwiper :border-radius="themeRadius" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
|
||||
// 根据主题调整圆角
|
||||
const isDarkMode = ref(false)
|
||||
const themeRadius = computed(() => {
|
||||
return isDarkMode.value ? 12 : 8
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **圆角单位**:数字类型自动添加px单位,字符串类型直接使用
|
||||
2. **高度单位**:数字类型自动添加px单位,字符串类型直接使用(支持vh、rem等)
|
||||
3. **缩略图显示**:当设置 `showThumbnails` 为 `false` 时,缩略图完全隐藏
|
||||
4. **图片比例**:建议使用相同比例的图片以获得最佳显示效果
|
||||
5. **性能优化**:大量图片时建议使用懒加载
|
||||
6. **兼容性**:支持微信小程序、H5、App等平台
|
||||
|
||||
## 更新日志
|
||||
|
||||
### v1.3.0
|
||||
- ✨ 新增 `height` 属性,支持自定义轮播图高度
|
||||
- ✨ 新增 `showThumbnails` 属性,支持隐藏缩略图
|
||||
- 🎨 优化样式系统,移除硬编码高度
|
||||
- 🔧 改进计算属性,支持动态高度和缩略图控制
|
||||
- 📝 更新文档和演示示例,新增多个高级用法示例
|
||||
- 🎯 增强组件灵活性,适应更多使用场景
|
||||
|
||||
### v1.2.0
|
||||
- ✨ 新增缩略图左右滑动功能
|
||||
- ✨ 新增缩略图选中状态高亮显示
|
||||
- ✨ 新增缩略图自动滚动到可视区域
|
||||
- 🎨 优化缩略图动画效果和交互体验
|
||||
- 🔧 改进主轮播图与缩略图的联动机制
|
||||
- 📝 更新文档和演示示例
|
||||
|
||||
### v1.1.0
|
||||
- ✨ 新增 `borderRadius` 属性,支持自定义圆角
|
||||
- ✨ 新增 `images` 属性,支持自定义图片数据
|
||||
- 🔧 优化组件结构,使用计算属性提升性能
|
||||
- 📝 完善文档和示例
|
||||
|
||||
### v1.0.0
|
||||
- 🎉 初始版本发布
|
||||
- ✨ 基础轮播图功能
|
||||
- ✨ 缩略图导航
|
||||
- ✨ 进度指示器
|
||||
|
||||
## 技术栈
|
||||
|
||||
- Vue 3 Composition API
|
||||
- SCSS
|
||||
- uni-app
|
||||
|
||||
## 浏览器支持
|
||||
|
||||
- 微信小程序
|
||||
- H5 (Chrome, Firefox, Safari, Edge)
|
||||
- App (iOS, Android)
|
||||
|
||||
## 许可证
|
||||
|
||||
MIT License
|
||||
227
src/components/ImageSwiper/demo.vue
Normal file
227
src/components/ImageSwiper/demo.vue
Normal file
@@ -0,0 +1,227 @@
|
||||
<template>
|
||||
<view class="demo-container">
|
||||
<view class="demo-title">ImageSwiper 轮播图组件演示</view>
|
||||
|
||||
<!-- 示例1: 默认圆角 -->
|
||||
<view class="demo-section">
|
||||
<view class="section-title">示例1: 默认圆角 (8px)</view>
|
||||
<ImageSwiper />
|
||||
</view>
|
||||
|
||||
<!-- 示例2: 无圆角 -->
|
||||
<view class="demo-section">
|
||||
<view class="section-title">示例2: 无圆角 (0px)</view>
|
||||
<ImageSwiper :border-radius="0" />
|
||||
</view>
|
||||
|
||||
<!-- 示例3: 大圆角 -->
|
||||
<view class="demo-section">
|
||||
<view class="section-title">示例3: 大圆角 (20px)</view>
|
||||
<ImageSwiper :border-radius="20" />
|
||||
</view>
|
||||
|
||||
<!-- 示例4: 字符串圆角 -->
|
||||
<view class="demo-section">
|
||||
<view class="section-title">示例4: 字符串圆角 (1rem)</view>
|
||||
<ImageSwiper border-radius="1rem" />
|
||||
</view>
|
||||
|
||||
<!-- 示例5: 自定义图片数据 -->
|
||||
<view class="demo-section">
|
||||
<view class="section-title">示例5: 自定义图片数据 + 圆角15px</view>
|
||||
<ImageSwiper :border-radius="15" :images="customImages" />
|
||||
</view>
|
||||
|
||||
<!-- 示例7: 多图片测试滑动 -->
|
||||
<view class="demo-section">
|
||||
<view class="section-title">示例7: 多图片测试缩略图滑动</view>
|
||||
<ImageSwiper :border-radius="10" :images="manyImages" />
|
||||
</view>
|
||||
|
||||
<!-- 示例6: 动态圆角控制 -->
|
||||
<view class="demo-section">
|
||||
<view class="section-title">示例6: 动态圆角控制</view>
|
||||
<view class="control-panel">
|
||||
<text>圆角大小: {{ dynamicRadius }}px</text>
|
||||
<slider
|
||||
:value="dynamicRadius"
|
||||
:min="0"
|
||||
:max="50"
|
||||
@change="handleRadiusChange"
|
||||
activeColor="#007AFF"
|
||||
/>
|
||||
</view>
|
||||
<ImageSwiper :border-radius="dynamicRadius" />
|
||||
</view>
|
||||
|
||||
<!-- 示例8: 自定义高度 -->
|
||||
<view class="demo-section">
|
||||
<view class="section-title">示例8: 自定义高度 (300px)</view>
|
||||
<ImageSwiper :height="300" :border-radius="12" />
|
||||
</view>
|
||||
|
||||
<!-- 示例9: 小高度轮播图 -->
|
||||
<view class="demo-section">
|
||||
<view class="section-title">示例9: 小高度轮播图 (120px)</view>
|
||||
<ImageSwiper :height="120" :border-radius="8" />
|
||||
</view>
|
||||
|
||||
<!-- 示例10: 隐藏缩略图 -->
|
||||
<view class="demo-section">
|
||||
<view class="section-title">示例10: 隐藏缩略图</view>
|
||||
<ImageSwiper :show-thumbnails="false" :border-radius="15" />
|
||||
</view>
|
||||
|
||||
<!-- 示例11: 动态高度和缩略图控制 -->
|
||||
<view class="demo-section">
|
||||
<view class="section-title">示例11: 动态高度和缩略图控制</view>
|
||||
<view class="control-panel">
|
||||
<text>高度: {{ dynamicHeight }}px</text>
|
||||
<slider
|
||||
:value="dynamicHeight"
|
||||
:min="100"
|
||||
:max="400"
|
||||
@change="handleHeightChange"
|
||||
activeColor="#007AFF"
|
||||
/>
|
||||
<view class="checkbox-wrapper">
|
||||
<checkbox :checked="showThumbnails" @change="handleThumbnailToggle" />
|
||||
<text class="checkbox-label">显示缩略图</text>
|
||||
</view>
|
||||
</view>
|
||||
<ImageSwiper
|
||||
:height="dynamicHeight"
|
||||
:show-thumbnails="showThumbnails"
|
||||
:border-radius="10"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 示例12: 字符串高度 -->
|
||||
<view class="demo-section">
|
||||
<view class="section-title">示例12: 字符串高度 (50vh)</view>
|
||||
<ImageSwiper height="50vh" :border-radius="20" :show-thumbnails="false" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import ImageSwiper from './index.vue'
|
||||
|
||||
// 动态圆角控制
|
||||
const dynamicRadius = ref(8)
|
||||
|
||||
// 动态高度控制
|
||||
const dynamicHeight = ref(200)
|
||||
|
||||
// 缩略图显示控制
|
||||
const showThumbnails = ref(true)
|
||||
|
||||
// 自定义图片数据
|
||||
const customImages = ref([
|
||||
{
|
||||
photoUrl: "https://fastly.picsum.photos/id/100/654/400.jpg?hmac=lYhMw5jKKjJJKjJKjJKjJKjJKjJKjJKjJKjJKjJKjJK",
|
||||
photoName: "自定义图片1",
|
||||
},
|
||||
{
|
||||
photoUrl: "https://fastly.picsum.photos/id/200/654/400.jpg?hmac=lYhMw5jKKjJJKjJKjJKjJKjJKjJKjJKjJKjJKjJKjJK",
|
||||
photoName: "自定义图片2",
|
||||
},
|
||||
{
|
||||
photoUrl: "https://fastly.picsum.photos/id/300/654/400.jpg?hmac=lYhMw5jKKjJJKjJKjJKjJKjJKjJKjJKjJKjJKjJKjJK",
|
||||
photoName: "自定义图片3",
|
||||
}
|
||||
])
|
||||
|
||||
// 多图片数据,用于测试缩略图滑动
|
||||
const manyImages = ref([
|
||||
{ photoUrl: "https://fastly.picsum.photos/id/10/654/400.jpg", photoName: "风景1" },
|
||||
{ photoUrl: "https://fastly.picsum.photos/id/20/654/400.jpg", photoName: "风景2" },
|
||||
{ photoUrl: "https://fastly.picsum.photos/id/30/654/400.jpg", photoName: "风景3" },
|
||||
{ photoUrl: "https://fastly.picsum.photos/id/40/654/400.jpg", photoName: "风景4" },
|
||||
{ photoUrl: "https://fastly.picsum.photos/id/50/654/400.jpg", photoName: "风景5" },
|
||||
{ photoUrl: "https://fastly.picsum.photos/id/60/654/400.jpg", photoName: "风景6" },
|
||||
{ photoUrl: "https://fastly.picsum.photos/id/70/654/400.jpg", photoName: "风景7" },
|
||||
{ photoUrl: "https://fastly.picsum.photos/id/80/654/400.jpg", photoName: "风景8" },
|
||||
{ photoUrl: "https://fastly.picsum.photos/id/90/654/400.jpg", photoName: "风景9" },
|
||||
{ photoUrl: "https://fastly.picsum.photos/id/110/654/400.jpg", photoName: "风景10" }
|
||||
])
|
||||
|
||||
// 处理圆角变化
|
||||
const handleRadiusChange = (e) => {
|
||||
dynamicRadius.value = e.detail.value
|
||||
}
|
||||
|
||||
// 处理高度变化
|
||||
const handleHeightChange = (e) => {
|
||||
dynamicHeight.value = e.detail.value
|
||||
}
|
||||
|
||||
// 处理缩略图显示切换
|
||||
const handleThumbnailToggle = (e) => {
|
||||
showThumbnails.value = e.detail.value
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.demo-container {
|
||||
padding: 20rpx;
|
||||
background-color: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.demo-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-bottom: 40rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.demo-section {
|
||||
margin-bottom: 60rpx;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 20rpx;
|
||||
color: #333;
|
||||
border-left: 6rpx solid #007AFF;
|
||||
padding-left: 16rpx;
|
||||
}
|
||||
|
||||
.control-panel {
|
||||
margin-bottom: 30rpx;
|
||||
padding: 20rpx;
|
||||
background: #f8f9fa;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
.control-panel text {
|
||||
display: block;
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
slider {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.checkbox-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.checkbox-label {
|
||||
margin-left: 16rpx;
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
BIN
src/components/ImageSwiper/images/2025-07-12_180248.jpg
Normal file
BIN
src/components/ImageSwiper/images/2025-07-12_180248.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 130 KiB |
159
src/components/ImageSwiper/index.vue
Normal file
159
src/components/ImageSwiper/index.vue
Normal file
@@ -0,0 +1,159 @@
|
||||
<template>
|
||||
<view class="image-swiper">
|
||||
<swiper
|
||||
class="swiper-box"
|
||||
:style="swiperStyle"
|
||||
:autoplay="false"
|
||||
:interval="3000"
|
||||
:duration="1000"
|
||||
:current="active"
|
||||
@change="handleSwiperChange"
|
||||
>
|
||||
<swiper-item
|
||||
class="swiper-item"
|
||||
v-for="(item, index) in thumbnails"
|
||||
:key="index"
|
||||
>
|
||||
<image :src="item.photoUrl" mode="aspectFill"></image>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
|
||||
<view class="custom-indicator">
|
||||
图片{{ active + 1 }}/{{ thumbnails.length }}
|
||||
</view>
|
||||
|
||||
<!-- 缩略图部分 -->
|
||||
<view
|
||||
v-if="showThumbnails"
|
||||
class="thumbnail-box"
|
||||
:style="thumbnailBoxStyle"
|
||||
>
|
||||
<scroll-view
|
||||
class="thumbnail-scroll"
|
||||
scroll-x="true"
|
||||
:scroll-left="scrollLeft"
|
||||
:scroll-with-animation="true"
|
||||
show-scrollbar="false"
|
||||
>
|
||||
<view class="thumbnail-list">
|
||||
<view
|
||||
v-for="(thumb, index) in thumbnails"
|
||||
:key="index"
|
||||
:class="['thumbnail-item', { active: index === active }]"
|
||||
:id="`thumbnail-${index}`"
|
||||
@click="handleThumbnailClick(index)"
|
||||
>
|
||||
<image :src="thumb.photoUrl" mode="aspectFill"></image>
|
||||
<text>{{ thumb.photoName }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, nextTick } from "vue";
|
||||
|
||||
// Props定义
|
||||
const props = defineProps({
|
||||
// 轮播图圆角大小,支持数字(px)或字符串
|
||||
borderRadius: {
|
||||
type: [Number, String],
|
||||
default: 8,
|
||||
},
|
||||
// 轮播图数据
|
||||
images: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
// 轮播图高度,支持数字(px)或字符串
|
||||
height: {
|
||||
type: [Number, String],
|
||||
default: 200,
|
||||
},
|
||||
// 是否显示缩略图
|
||||
showThumbnails: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 缩略图距离底部的距离,支持数字(px)或字符串
|
||||
thumbnailBottom: {
|
||||
type: [Number, String],
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const active = ref(0);
|
||||
const scrollLeft = ref(0);
|
||||
|
||||
// 计算圆角样式
|
||||
const borderRadiusStyle = computed(() => {
|
||||
const radius =
|
||||
typeof props.borderRadius === "number"
|
||||
? `${props.borderRadius}px`
|
||||
: props.borderRadius;
|
||||
return {
|
||||
borderRadius: radius,
|
||||
};
|
||||
});
|
||||
|
||||
// 计算轮播图样式(包含高度和圆角)
|
||||
const swiperStyle = computed(() => {
|
||||
const radius =
|
||||
typeof props.borderRadius === "number"
|
||||
? `${props.borderRadius}px`
|
||||
: props.borderRadius;
|
||||
const swiperHeight =
|
||||
typeof props.height === "number" ? `${props.height}px` : props.height;
|
||||
return {
|
||||
borderRadius: radius,
|
||||
height: swiperHeight,
|
||||
};
|
||||
});
|
||||
|
||||
// 使用传入的图片数据或默认数据
|
||||
const thumbnails = computed(() => props.images);
|
||||
|
||||
// 计算缩略图底部距离样式
|
||||
const thumbnailBoxStyle = computed(() => {
|
||||
const bottom =
|
||||
typeof props.thumbnailBottom === "number"
|
||||
? `${props.thumbnailBottom}px`
|
||||
: props.thumbnailBottom;
|
||||
return {
|
||||
bottom: bottom,
|
||||
};
|
||||
});
|
||||
|
||||
const handleThumbnailClick = (index) => {
|
||||
active.value = index;
|
||||
scrollToActiveItem(index);
|
||||
};
|
||||
|
||||
// 滚动到选中项
|
||||
const scrollToActiveItem = async (index) => {
|
||||
await nextTick();
|
||||
|
||||
// 计算每个缩略图项的宽度(包括间距)
|
||||
const itemWidth = 58; // 48px宽度 + 10px间距
|
||||
const containerWidth = 300; // 大概的容器宽度
|
||||
const targetScrollLeft = Math.max(
|
||||
0,
|
||||
index * itemWidth - containerWidth / 2 + itemWidth / 2
|
||||
);
|
||||
|
||||
scrollLeft.value = targetScrollLeft;
|
||||
};
|
||||
|
||||
// 监听主轮播图变化,同步缩略图滚动
|
||||
const handleSwiperChange = (e) => {
|
||||
const currentIndex = e.detail.current;
|
||||
active.value = currentIndex;
|
||||
scrollToActiveItem(currentIndex);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "./styles/index.scss";
|
||||
</style>
|
||||
15
src/components/ImageSwiper/prompt.md
Normal file
15
src/components/ImageSwiper/prompt.md
Normal file
@@ -0,0 +1,15 @@
|
||||
## 图片详情组件
|
||||
|
||||
组件名称:图片详情组件
|
||||
|
||||
## 提示词:
|
||||
|
||||
使用 uniapp + vue3 组合式 api 开发微信小程序,要求如下:
|
||||
1、按照提供的图片 100%还原交互设计
|
||||
2、要求布局样式结构简洁明了,class 命名请按照模块名称来命名,例如:.image-swiper
|
||||
3、可以使用 uniapp swiper 内置的组件
|
||||
4、可以使用网络图片地址
|
||||
|
||||
## 备注
|
||||
|
||||
仅供学习、交流使用,请勿用于商业用途。
|
||||
80
src/components/ImageSwiper/styles/index.scss
Normal file
80
src/components/ImageSwiper/styles/index.scss
Normal file
@@ -0,0 +1,80 @@
|
||||
.image-swiper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.swiper-box {
|
||||
overflow: hidden;
|
||||
// 高度和圆角通过内联样式动态设置
|
||||
}
|
||||
|
||||
.swiper-item image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.custom-indicator {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
z-index: 10;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 50px;
|
||||
padding: 3px 8px;
|
||||
font-size: 8px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.thumbnail-box {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
right: 12px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.thumbnail-scroll {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.thumbnail-list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.thumbnail-item {
|
||||
flex-shrink: 0;
|
||||
text-align: center;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&.active {
|
||||
image {
|
||||
border: 1px solid #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.thumbnail-item image {
|
||||
width: 48px;
|
||||
height: 38px;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid transparent;
|
||||
transition: all 0.3s ease;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.thumbnail-item text {
|
||||
color: #fff;
|
||||
font-size: 8px;
|
||||
display: block;
|
||||
margin-top: 4px;
|
||||
transition: all 0.3s ease;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 48px;
|
||||
}
|
||||
Reference in New Issue
Block a user