uniapp-dyckui 4.1.3 → 4.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -60,7 +60,7 @@
60
60
  </template>
61
61
 
62
62
  <script setup lang="ts">
63
- import { nextTick, onMounted, onUnmounted, ref, watch, withDefaults } from 'vue'
63
+ import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
64
64
 
65
65
  // Props
66
66
  interface Props {
@@ -597,3 +597,4 @@ onUnmounted(() => {
597
597
  color: white;
598
598
  }
599
599
  </style>
600
+
@@ -1,245 +1,246 @@
1
- <template>
2
- <view class="sw-swiper">
3
- <view
4
- class="swiper-wrapper"
5
- :style="{
6
- transform: `translateX(-${currentIndex * 100}%)`,
7
- transition: `transform ${duration}ms ease`,
8
- }"
9
- >
10
- <view
11
- v-for="(item, index) in items"
12
- :key="index"
13
- class="swiper-item"
14
- >
15
- <slot :item="item" :index="index" />
16
- </view>
17
- </view>
18
-
19
- <!-- 指示器 -->
20
- <view v-if="showIndicators" class="swiper-indicators">
21
- <view
22
- v-for="(item, index) in items"
23
- :key="index"
24
- class="indicator-item"
25
- :class="{ active: index === currentIndex }"
26
- @click="currentIndex = index"
27
- />
28
- </view>
29
-
30
- <!-- 左右箭头 -->
31
- <view
32
- v-if="showArrows"
33
- class="swiper-arrow swiper-arrow-left"
34
- @click="prev"
35
- />
36
- <view
37
- v-if="showArrows"
38
- class="swiper-arrow swiper-arrow-right"
39
- @click="next"
40
- />
41
- </view>
42
- </template>
43
-
44
- <script setup lang="ts">
45
- import { onMounted, onUnmounted, ref, watch, withDefaults } from 'vue'
46
-
47
- interface Props {
48
- items: any[]
49
- initialIndex?: number
50
- autoPlay?: boolean
51
- interval?: number
52
- duration?: number
53
- showIndicators?: boolean
54
- showArrows?: boolean
55
- loop?: boolean
56
- }
57
-
58
- const props = withDefaults(defineProps<Props>(), {
59
- initialIndex: 0,
60
- autoPlay: true,
61
- interval: 3000,
62
- duration: 300,
63
- showIndicators: true,
64
- showArrows: false,
65
- loop: true,
66
- })
67
-
68
- const emit = defineEmits<{
69
- (e: 'change', index: number): void
70
- (e: 'prev', index: number): void
71
- (e: 'next', index: number): void
72
- }>()
73
-
74
- const currentIndex = ref(props.initialIndex)
75
- let timer: any = null
76
-
77
- // 自动播放
78
- function startAutoPlay() {
79
- if (props.autoPlay && props.items.length > 1) {
80
- timer = setInterval(() => {
81
- next()
82
- }, props.interval)
83
- }
84
- }
85
-
86
- function stopAutoPlay() {
87
- if (timer) {
88
- clearInterval(timer)
89
- timer = null
90
- }
91
- }
92
-
93
- // 上一张
94
- function prev() {
95
- if (props.loop) {
96
- currentIndex.value = currentIndex.value === 0 ? props.items.length - 1 : currentIndex.value - 1
97
- }
98
- else if (currentIndex.value > 0) {
99
- currentIndex.value--
100
- }
101
- emit('prev', currentIndex.value)
102
- emit('change', currentIndex.value)
103
- }
104
-
105
- // 下一张
106
- function next() {
107
- if (props.loop) {
108
- currentIndex.value = currentIndex.value === props.items.length - 1 ? 0 : currentIndex.value + 1
109
- }
110
- else if (currentIndex.value < props.items.length - 1) {
111
- currentIndex.value++
112
- }
113
- emit('next', currentIndex.value)
114
- emit('change', currentIndex.value)
115
- }
116
-
117
- // 监听items变化
118
- watch(() => props.items, (newItems) => {
119
- if (newItems.length < currentIndex.value + 1) {
120
- currentIndex.value = Math.min(currentIndex.value, newItems.length - 1)
121
- }
122
- stopAutoPlay()
123
- startAutoPlay()
124
- }, { deep: true })
125
-
126
- // 监听自动播放设置
127
- watch(() => props.autoPlay, (autoPlay) => {
128
- if (autoPlay) {
129
- startAutoPlay()
130
- }
131
- else {
132
- stopAutoPlay()
133
- }
134
- })
135
-
136
- onMounted(() => {
137
- startAutoPlay()
138
- })
139
-
140
- onUnmounted(() => {
141
- stopAutoPlay()
142
- })
143
-
144
- // 暴露方法
145
- defineExpose({
146
- prev,
147
- next,
148
- currentIndex,
149
- })
150
- </script>
151
-
152
- <style lang="less" scoped>
153
- // 轮播图组件样式
154
- .sw-swiper {
155
- position: relative;
156
- width: 100%;
157
- overflow: hidden;
158
-
159
- .swiper-wrapper {
160
- display: flex;
161
- width: 100%;
162
- height: 100%;
163
- }
164
-
165
- .swiper-item {
166
- flex-shrink: 0;
167
- width: 100%;
168
- height: 100%;
169
- }
170
-
171
- // 指示器
172
- .swiper-indicators {
173
- position: absolute;
174
- bottom: 32rpx;
175
- left: 50%;
176
- transform: translateX(-50%);
177
- display: flex;
178
- gap: 16rpx;
179
-
180
- .indicator-item {
181
- width: 16rpx;
182
- height: 16rpx;
183
- border-radius: 50%;
184
- background-color: rgba(255, 255, 255, 0.5);
185
- cursor: pointer;
186
- transition: all 0.3s ease;
187
-
188
- &.active {
189
- width: 16rpx;
190
- height: 16rpx;
191
- background-color: #fff;
192
- }
193
- }
194
- }
195
-
196
- // 箭头
197
- .swiper-arrow {
198
- position: absolute;
199
- top: 50%;
200
- transform: translateY(-50%);
201
- width: 76rpx;
202
- height: 76rpx;
203
- border-radius: 50%;
204
- background-color: rgba(255, 255, 255, 0.85);
205
- border: none;
206
- display: flex;
207
- align-items: center;
208
- justify-content: center;
209
- cursor: pointer;
210
- z-index: 10;
211
- transition: all 0.3s ease;
212
- box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.15);
213
-
214
- &:hover {
215
- background-color: rgba(255, 255, 255, 1);
216
- transform: translateY(-50%) scale(1.1);
217
- }
218
-
219
- &:before {
220
- content: '';
221
- width: 24rpx;
222
- height: 24rpx;
223
- border-top: 4rpx solid #333;
224
- border-left: 4rpx solid #333;
225
- display: inline-block;
226
- }
227
-
228
- &.swiper-arrow-left {
229
- left: 30rpx;
230
-
231
- &:before {
232
- transform: rotate(-45deg);
233
- }
234
- }
235
-
236
- &.swiper-arrow-right {
237
- right: 30rpx;
238
-
239
- &:before {
240
- transform: rotate(135deg);
241
- }
242
- }
243
- }
244
- }
245
- </style>
1
+ <template>
2
+ <view class="sw-swiper">
3
+ <view
4
+ class="swiper-wrapper"
5
+ :style="{
6
+ transform: `translateX(-${currentIndex * 100}%)`,
7
+ transition: `transform ${duration}ms ease`,
8
+ }"
9
+ >
10
+ <view
11
+ v-for="(item, index) in items"
12
+ :key="index"
13
+ class="swiper-item"
14
+ >
15
+ <slot :item="item" :index="index" />
16
+ </view>
17
+ </view>
18
+
19
+ <!-- 指示器 -->
20
+ <view v-if="showIndicators" class="swiper-indicators">
21
+ <view
22
+ v-for="(item, index) in items"
23
+ :key="index"
24
+ class="indicator-item"
25
+ :class="{ active: index === currentIndex }"
26
+ @click="currentIndex = index"
27
+ />
28
+ </view>
29
+
30
+ <!-- 左右箭头 -->
31
+ <view
32
+ v-if="showArrows"
33
+ class="swiper-arrow swiper-arrow-left"
34
+ @click="prev"
35
+ />
36
+ <view
37
+ v-if="showArrows"
38
+ class="swiper-arrow swiper-arrow-right"
39
+ @click="next"
40
+ />
41
+ </view>
42
+ </template>
43
+
44
+ <script setup lang="ts">
45
+ import { onMounted, onUnmounted, ref, watch } from 'vue'
46
+
47
+ interface Props {
48
+ items: any[]
49
+ initialIndex?: number
50
+ autoPlay?: boolean
51
+ interval?: number
52
+ duration?: number
53
+ showIndicators?: boolean
54
+ showArrows?: boolean
55
+ loop?: boolean
56
+ }
57
+
58
+ const props = withDefaults(defineProps<Props>(), {
59
+ initialIndex: 0,
60
+ autoPlay: true,
61
+ interval: 3000,
62
+ duration: 300,
63
+ showIndicators: true,
64
+ showArrows: false,
65
+ loop: true,
66
+ })
67
+
68
+ const emit = defineEmits<{
69
+ (e: 'change', index: number): void
70
+ (e: 'prev', index: number): void
71
+ (e: 'next', index: number): void
72
+ }>()
73
+
74
+ const currentIndex = ref(props.initialIndex)
75
+ let timer: any = null
76
+
77
+ // 自动播放
78
+ function startAutoPlay() {
79
+ if (props.autoPlay && props.items.length > 1) {
80
+ timer = setInterval(() => {
81
+ next()
82
+ }, props.interval)
83
+ }
84
+ }
85
+
86
+ function stopAutoPlay() {
87
+ if (timer) {
88
+ clearInterval(timer)
89
+ timer = null
90
+ }
91
+ }
92
+
93
+ // 上一张
94
+ function prev() {
95
+ if (props.loop) {
96
+ currentIndex.value = currentIndex.value === 0 ? props.items.length - 1 : currentIndex.value - 1
97
+ }
98
+ else if (currentIndex.value > 0) {
99
+ currentIndex.value--
100
+ }
101
+ emit('prev', currentIndex.value)
102
+ emit('change', currentIndex.value)
103
+ }
104
+
105
+ // 下一张
106
+ function next() {
107
+ if (props.loop) {
108
+ currentIndex.value = currentIndex.value === props.items.length - 1 ? 0 : currentIndex.value + 1
109
+ }
110
+ else if (currentIndex.value < props.items.length - 1) {
111
+ currentIndex.value++
112
+ }
113
+ emit('next', currentIndex.value)
114
+ emit('change', currentIndex.value)
115
+ }
116
+
117
+ // 监听items变化
118
+ watch(() => props.items, (newItems) => {
119
+ if (newItems.length < currentIndex.value + 1) {
120
+ currentIndex.value = Math.min(currentIndex.value, newItems.length - 1)
121
+ }
122
+ stopAutoPlay()
123
+ startAutoPlay()
124
+ }, { deep: true })
125
+
126
+ // 监听自动播放设置
127
+ watch(() => props.autoPlay, (autoPlay) => {
128
+ if (autoPlay) {
129
+ startAutoPlay()
130
+ }
131
+ else {
132
+ stopAutoPlay()
133
+ }
134
+ })
135
+
136
+ onMounted(() => {
137
+ startAutoPlay()
138
+ })
139
+
140
+ onUnmounted(() => {
141
+ stopAutoPlay()
142
+ })
143
+
144
+ // 暴露方法
145
+ defineExpose({
146
+ prev,
147
+ next,
148
+ currentIndex,
149
+ })
150
+ </script>
151
+
152
+ <style lang="less" scoped>
153
+ // 轮播图组件样式
154
+ .sw-swiper {
155
+ position: relative;
156
+ width: 100%;
157
+ overflow: hidden;
158
+
159
+ .swiper-wrapper {
160
+ display: flex;
161
+ width: 100%;
162
+ height: 100%;
163
+ }
164
+
165
+ .swiper-item {
166
+ flex-shrink: 0;
167
+ width: 100%;
168
+ height: 100%;
169
+ }
170
+
171
+ // 指示器
172
+ .swiper-indicators {
173
+ position: absolute;
174
+ bottom: 32rpx;
175
+ left: 50%;
176
+ transform: translateX(-50%);
177
+ display: flex;
178
+ gap: 16rpx;
179
+
180
+ .indicator-item {
181
+ width: 16rpx;
182
+ height: 16rpx;
183
+ border-radius: 50%;
184
+ background-color: rgba(255, 255, 255, 0.5);
185
+ cursor: pointer;
186
+ transition: all 0.3s ease;
187
+
188
+ &.active {
189
+ width: 16rpx;
190
+ height: 16rpx;
191
+ background-color: #fff;
192
+ }
193
+ }
194
+ }
195
+
196
+ // 箭头
197
+ .swiper-arrow {
198
+ position: absolute;
199
+ top: 50%;
200
+ transform: translateY(-50%);
201
+ width: 76rpx;
202
+ height: 76rpx;
203
+ border-radius: 50%;
204
+ background-color: rgba(255, 255, 255, 0.85);
205
+ border: none;
206
+ display: flex;
207
+ align-items: center;
208
+ justify-content: center;
209
+ cursor: pointer;
210
+ z-index: 10;
211
+ transition: all 0.3s ease;
212
+ box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.15);
213
+
214
+ &:hover {
215
+ background-color: rgba(255, 255, 255, 1);
216
+ transform: translateY(-50%) scale(1.1);
217
+ }
218
+
219
+ &:before {
220
+ content: '';
221
+ width: 24rpx;
222
+ height: 24rpx;
223
+ border-top: 4rpx solid #333;
224
+ border-left: 4rpx solid #333;
225
+ display: inline-block;
226
+ }
227
+
228
+ &.swiper-arrow-left {
229
+ left: 30rpx;
230
+
231
+ &:before {
232
+ transform: rotate(-45deg);
233
+ }
234
+ }
235
+
236
+ &.swiper-arrow-right {
237
+ right: 30rpx;
238
+
239
+ &:before {
240
+ transform: rotate(135deg);
241
+ }
242
+ }
243
+ }
244
+ }
245
+ </style>
246
+