hookehuyr

✨ feat: 新增详情页产品显示切换组件测试

...@@ -18,12 +18,14 @@ declare module 'vue' { ...@@ -18,12 +18,14 @@ declare module 'vue' {
18 ElInput: typeof import('element-ui/lib/input')['default'] 18 ElInput: typeof import('element-ui/lib/input')['default']
19 ElRow: typeof import('element-ui/lib/row')['default'] 19 ElRow: typeof import('element-ui/lib/row')['default']
20 HagerBox: typeof import('./src/components/common/hagerBox.vue')['default'] 20 HagerBox: typeof import('./src/components/common/hagerBox.vue')['default']
21 + HagerCarousel: typeof import('./src/components/hagerCarousel.vue')['default']
21 HagerFooter: typeof import('./src/components/common/hagerFooter.vue')['default'] 22 HagerFooter: typeof import('./src/components/common/hagerFooter.vue')['default']
22 HagerHeader: typeof import('./src/components/common/hagerHeader.vue')['default'] 23 HagerHeader: typeof import('./src/components/common/hagerHeader.vue')['default']
23 Navbar: typeof import('./src/components/navbar.vue')['default'] 24 Navbar: typeof import('./src/components/navbar.vue')['default']
24 RouterLink: typeof import('vue-router')['RouterLink'] 25 RouterLink: typeof import('vue-router')['RouterLink']
25 RouterView: typeof import('vue-router')['RouterView'] 26 RouterView: typeof import('vue-router')['RouterView']
26 SlideComp: typeof import('./src/components/slideComp.vue')['default'] 27 SlideComp: typeof import('./src/components/slideComp.vue')['default']
28 + TagerCarousel: typeof import('./src/components/tagerCarousel.vue')['default']
27 VideoPlayer: typeof import('./src/components/videoPlayer.vue')['default'] 29 VideoPlayer: typeof import('./src/components/videoPlayer.vue')['default']
28 } 30 }
29 } 31 }
......
1 +<!--
2 + * @Date: 2024-09-27 19:49:03
3 + * @LastEditors: hookehuyr hookehuyr@gmail.com
4 + * @LastEditTime: 2024-09-27 20:09:22
5 + * @FilePath: /hager/src/components/hagerCarousel.vue
6 + * @Description: 文件描述
7 +-->
8 +<template>
9 + <div class="hager-carousel">
10 + <div class="image-switcher">
11 + <!-- 缩略图区域 -->
12 + <div class="thumbnail-container">
13 + <!-- 上箭头 -->
14 + <div class="arrow-up" @click="prevImage">▲</div>
15 +
16 + <!-- 缩略图列表 -->
17 + <div class="thumbnails">
18 + <div
19 + v-for="(image, index) in visibleThumbnails"
20 + :key="index"
21 + :class="['thumbnail', { active: selectedImage === (startIndex + index) }]"
22 + @click="selectImage(startIndex + index)"
23 + >
24 + <img :src="image" alt="thumbnail">
25 + </div>
26 + </div>
27 +
28 + <!-- 下箭头 -->
29 + <div class="arrow-down" @click="nextImage">▼</div>
30 + </div>
31 +
32 + <!-- 右边大图区域 -->
33 + <div class="main-image" :class="{ 'fade-out': isTransitioning, 'fade-in': !isTransitioning }">
34 + <img :src="images[selectedImage]" alt="main image">
35 + </div>
36 + </div>
37 + </div>
38 +</template>
39 +
40 +<script>
41 +import mixin from "common/mixin";
42 +
43 +export default {
44 + mixins: [mixin.init],
45 + data() {
46 + return {
47 + selectedImage: 0, // 当前选中的图片索引
48 + startIndex: 0, // 当前显示的缩略图起始索引
49 + thumbnailsToShow: 4, // 每次显示4个缩略图
50 + isTransitioning: false, // 控制大图的切换动画
51 + images: [
52 + "https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg",
53 + "https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg",
54 + "https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg",
55 + "https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg",
56 + "https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg",
57 + "https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg",
58 + "https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg",
59 + ],
60 + };
61 + },
62 + mounted() {},
63 + computed: {
64 + // 计算当前显示的缩略图
65 + visibleThumbnails() {
66 + return this.images.slice(this.startIndex, this.startIndex + this.thumbnailsToShow);
67 + },
68 + endIndex() {
69 + return this.startIndex + this.thumbnailsToShow - 1;
70 + }
71 + },
72 + methods: {
73 + // 选择某个图片并更新大图和选中状态
74 + selectImage(index) {
75 + this.isTransitioning = true; // 开始大图的淡出动画
76 + setTimeout(() => {
77 + this.selectedImage = index; // 切换大图
78 + this.isTransitioning = false; // 动画结束
79 + this.ensureVisibleThumbnail(); // 保证选中的缩略图在可视区域
80 + }, 500); // 动画时间为500ms
81 + },
82 + // 控制缩略图上下滚动
83 + scrollThumbnails(direction) {
84 + if (direction === 'up' && this.startIndex > 0) {
85 + this.startIndex--;
86 + } else if (direction === 'down' && this.endIndex < this.images.length - 1) {
87 + this.startIndex++;
88 + }
89 + },
90 + // 确保选中的缩略图在可见范围内
91 + ensureVisibleThumbnail() {
92 + if (this.selectedImage < this.startIndex) {
93 + // 如果选中的缩略图在当前显示范围的上方,则向上滚动
94 + this.startIndex = this.selectedImage;
95 + } else if (this.selectedImage > this.endIndex) {
96 + // 如果选中的缩略图在当前显示范围的下方,则向下滚动
97 + this.startIndex = this.selectedImage - this.thumbnailsToShow + 1;
98 + }
99 + },
100 + // 切换到下一张图片
101 + nextImage() {
102 + if (this.selectedImage < this.images.length - 1) {
103 + this.selectImage(this.selectedImage + 1);
104 + }
105 + },
106 + // 切换到上一张图片
107 + prevImage() {
108 + if (this.selectedImage > 0) {
109 + this.selectImage(this.selectedImage - 1);
110 + }
111 + }
112 + },
113 +};
114 +</script>
115 +
116 +<style lang="less" scoped>
117 +.hager-carousel {
118 + .image-switcher {
119 + display: flex;
120 + align-items: center;
121 + }
122 +
123 + .thumbnail-container {
124 + display: flex;
125 + flex-direction: column;
126 + align-items: center;
127 + margin-right: 20px;
128 + }
129 +
130 + .arrow-up,
131 + .arrow-down {
132 + cursor: pointer;
133 + padding: 5px;
134 + font-size: 18px;
135 + user-select: none;
136 + }
137 +
138 + .thumbnails {
139 + display: flex;
140 + flex-direction: column;
141 + align-items: center;
142 + max-height: 220px; /* 限制缩略图容器的高度 */
143 + overflow: hidden;
144 + position: relative; /* 为缩略图滚动效果提供基础 */
145 + }
146 +
147 + .thumbnail {
148 + width: 50px;
149 + height: 50px;
150 + margin-bottom: 10px;
151 + cursor: pointer;
152 + border: 2px solid transparent;
153 + transition: border 0.3s;
154 + }
155 +
156 + .thumbnail img {
157 + width: 100%;
158 + height: 100%;
159 + object-fit: cover;
160 + transition: transform 0.5s ease-in-out; /* 缩略图切换时的动画效果 */
161 + }
162 +
163 + .thumbnail.active {
164 + border: 2px solid #00f; /* 选中的缩略图边框样式 */
165 + }
166 +
167 + .main-image {
168 + width: 300px;
169 + height: 300px;
170 + position: relative;
171 + transition: opacity 0.5s ease-in-out; /* 大图切换时的淡入淡出效果 */
172 + opacity: 1;
173 + }
174 +
175 + .main-image img {
176 + width: 100%;
177 + height: 100%;
178 + object-fit: cover;
179 + position: absolute;
180 + }
181 +
182 + .main-image.fade-out {
183 + opacity: 0; /* 当切换时,将大图的透明度渐变为0 */
184 + }
185 +
186 + .main-image.fade-in {
187 + opacity: 1; /* 切换后,图片渐渐显现 */
188 + }
189 +
190 + .thumbnails-wrapper {
191 + transition: transform 0.5s ease-in-out; /* 缩略图滑动时的动画效果 */
192 + display: flex;
193 + flex-direction: column;
194 + }
195 +}
196 +</style>
1 <!-- 1 <!--
2 * @Date: 2024-08-27 10:06:30 2 * @Date: 2024-08-27 10:06:30
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2024-09-26 17:18:46 4 + * @LastEditTime: 2024-09-27 19:51:44
5 * @FilePath: /hager/src/views/index.vue 5 * @FilePath: /hager/src/views/index.vue
6 * @Description: 文件描述 6 * @Description: 文件描述
7 --> 7 -->
8 <template> 8 <template>
9 <div> 9 <div>
10 <hager-box style="background-color: #fff;"> 10 <hager-box style="background-color: #fff;">
11 - <div v-for="(item, index) in 10" :key="index"> 11 + <hager-carousel></hager-carousel>
12 - <div style="height: 5rem;">{{ index + 1 }}</div>
13 - </div>
14 </hager-box> 12 </hager-box>
15 <hager-box style="background-color: #f1f1f1;"> 13 <hager-box style="background-color: #f1f1f1;">
16 <div v-for="(item, index) in 10" :key="index"> 14 <div v-for="(item, index) in 10" :key="index">
...@@ -23,6 +21,7 @@ ...@@ -23,6 +21,7 @@
23 <script> 21 <script>
24 import mixin from '@/common/mixin'; 22 import mixin from '@/common/mixin';
25 import hagerBox from '@/components/common/hagerBox'; 23 import hagerBox from '@/components/common/hagerBox';
24 +import hagerCarousel from '@/components/hagerCarousel';
26 25
27 export default { 26 export default {
28 mixins: [mixin.init], 27 mixins: [mixin.init],
......