hy-app 0.6.5 → 0.6.7

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.
@@ -1,224 +1,230 @@
1
- <template>
2
- <view
3
- class="hy-swiper"
4
- :style="{
5
- backgroundColor: bgColor,
6
- height: addUnit(height),
7
- borderRadius: addUnit(radius)
8
- }"
9
- >
10
- <view class="hy-swiper__loading" v-if="loading">
11
- <hy-loading mode="circle"></hy-loading>
12
- </view>
13
- <swiper
14
- v-else
15
- class="hy-swiper__wrapper"
16
- :style="{
17
- flex: '1',
18
- height: addUnit(height)
19
- }"
20
- @change="change"
21
- :circular="circular"
22
- :interval="interval"
23
- :duration="duration"
24
- :autoplay="autoplay"
25
- :current="current"
26
- :currentItemId="currentItemId"
27
- :previousMargin="addUnit(previousMargin)"
28
- :nextMargin="addUnit(nextMargin)"
29
- :acceleration="acceleration"
30
- :displayMultipleItems="list.length > 0 ? displayMultipleItems : 0"
31
- :easingFunction="easingFunction"
32
- >
33
- <swiper-item
34
- class="hy-swiper__wrapper--item"
35
- v-for="(item, index) in list"
36
- :key="index"
37
- >
38
- <slot :record="item" :index="index">
39
- <view class="hy-swiper__wrapper--item__wrapper" :style="[itemStyle(index)]">
40
- <!-- 在nvue中,image图片的宽度默认为屏幕宽度,需要通过flex:1撑开,另外必须设置高度才能显示图片 -->
41
- <image
42
- class="hy-swiper__wrapper--item__wrapper--image"
43
- v-if="getItemType(item) === 'image'"
44
- :src="getSource(item)"
45
- :mode="imgMode"
46
- @tap="clickHandler(index)"
47
- :style="{
48
- height: addUnit(height),
49
- borderRadius: addUnit(radius)
50
- }"
51
- ></image>
52
- <video
53
- class="hy-swiper__wrapper--item__wrapper--video"
54
- v-if="getItemType(item) === 'video'"
55
- :id="`video-${index}`"
56
- :enable-progress-gesture="false"
57
- :src="getSource(item)"
58
- :poster="getPoster(item)"
59
- :title="showTitle && hasTitle(item)"
60
- :style="{
61
- height: addUnit(height)
62
- }"
63
- controls
64
- @tap="clickHandler(index)"
65
- ></video>
66
- <view
67
- v-if="showTitle && hasTitle(item)"
68
- class="hy-swiper__wrapper--item__wrapper--title"
69
- >
70
- <text class="hy-line-1">{{ hasTitle(item) }}</text>
71
- </view>
72
- </view>
73
- </slot>
74
- </swiper-item>
75
- </swiper>
76
- <view class="hy-swiper__indicator" :style="[indicatorStyle]">
77
- <slot name="indicator">
78
- <HySwiperIndicator
79
- v-if="!loading && indicator && !showTitle"
80
- :indicatorActiveColor="indicatorActiveColor"
81
- :indicatorInactiveColor="indicatorInactiveColor"
82
- :length="list.length"
83
- :current="currentIndex"
84
- :indicatorMode="indicatorMode"
85
- ></HySwiperIndicator>
86
- </slot>
87
- </view>
88
- </view>
89
- </template>
90
-
91
- <script lang="ts">
92
- export default {
93
- name: 'hy-swiper',
94
- options: {
95
- addGlobalClass: true,
96
- virtualHost: true,
97
- styleIsolation: 'shared'
98
- }
99
- }
100
- </script>
101
-
102
- <script setup lang="ts">
103
- import { computed, ref, watch, getCurrentInstance } from 'vue'
104
- import type { CSSProperties } from 'vue'
105
- import { addUnit, isVideo } from '../../libs'
106
- import type { ISwiperEmits, SwiperList, SwiperVo } from './typing'
107
- import swiperProps from './props'
108
- // 组件
109
- import HyLoading from '../hy-loading/hy-loading.vue'
110
- import HySwiperIndicator from './hy-swiper-indicator.vue'
111
-
112
- /**
113
- * 一般用于导航轮播,广告展示等场景,可开箱即用
114
- * @displayName hy-swiper
115
- */
116
- defineOptions({})
117
-
118
- const props = defineProps(swiperProps)
119
- const emit = defineEmits<ISwiperEmits>()
120
-
121
- const instance = getCurrentInstance()
122
- const currentIndex = ref<string | number>(0)
123
-
124
- watch(
125
- () => props.current,
126
- (newVal) => {
127
- currentIndex.value = newVal
128
- }
129
- )
130
-
131
- const hasTitle = computed(() => {
132
- return (item: string | Record<string, any>) => {
133
- if (typeof item === 'object') {
134
- return item.title || ''
135
- } else {
136
- return ''
137
- }
138
- }
139
- })
140
-
141
- /**
142
- * @description 轮播图3D效果
143
- * */
144
- const itemStyle = computed(() => {
145
- return (index: number): CSSProperties => {
146
- const style: CSSProperties = {}
147
- // #ifndef APP-NVUE || MP-TOUTIAO
148
- // 左右流出空间的写法不支持nvue和头条
149
- // 只有配置了此二值,才加上对应的圆角,以及缩放
150
- if (props.nextMargin && props.previousMargin) {
151
- style.borderRadius = addUnit(props.radius)
152
- if (index !== currentIndex.value) style.transform = 'scale(0.92)'
153
- }
154
- // #endif
155
- return style
156
- }
157
- })
158
-
159
- /**
160
- * @description 获取目标路径,可能数组中为字符串,对象的形式,额外可指定对象的目标属性名keyName
161
- * */
162
- const getSource = (item: string | Record<string, any>): string => {
163
- if (typeof item === 'string') return item
164
- if (typeof item === 'object' && props.keyName) return item[props.keyName]
165
- return ''
166
- }
167
-
168
- /**
169
- * @description 轮播切换事件
170
- */
171
- const change = (e: SwiperVo) => {
172
- // 当前的激活索引
173
- const { current } = e.detail
174
- pauseVideo(currentIndex.value)
175
- currentIndex.value = current
176
- emit('update:current', currentIndex.value)
177
- emit('change', e.detail)
178
- }
179
-
180
- /**
181
- * @description 切换轮播时,暂停视频播放
182
- * */
183
- const pauseVideo = (index: number | string) => {
184
- const lastItem = getSource(props.list[Number(index)])
185
- if (isVideo(lastItem)) {
186
- // 当视频隐藏时,暂停播放
187
- const video = uni.createVideoContext(`video-${index}`, instance)
188
- video.pause()
189
- }
190
- }
191
-
192
- /**
193
- * @description 当一个轮播item为视频时,获取它的视频海报
194
- * */
195
- const getPoster = (item: string | SwiperList): string => {
196
- return typeof item === 'object' && item.poster ? item.poster : ''
197
- }
198
-
199
- /**
200
- * @description 点击某个item
201
- * */
202
- const clickHandler = (index: number) => {
203
- emit('click', index)
204
- }
205
-
206
- /**
207
- * @description 判断链接是视频还是图片
208
- * */
209
- const getItemType = computed(() => {
210
- return (item: string | Record<string, unknown>) => {
211
- if (typeof item === 'string') return isVideo(item) ? 'video' : 'image'
212
- if (typeof item === 'object' && props.keyName) {
213
- if (!item.type) return isVideo(item[props.keyName] as string) ? 'video' : 'image'
214
- if (item.type === 'image') return 'image'
215
- if (item.type === 'video') return 'video'
216
- return 'image'
217
- }
218
- }
219
- })
220
- </script>
221
-
222
- <style lang="scss" scoped>
223
- @import './index.scss';
224
- </style>
1
+ <template>
2
+ <view
3
+ class="hy-swiper"
4
+ :style="{
5
+ backgroundColor: bgColor,
6
+ height: addUnit(height),
7
+ borderRadius: addUnit(radius)
8
+ }"
9
+ >
10
+ <view class="hy-swiper__loading" v-if="loading">
11
+ <hy-loading mode="circle"></hy-loading>
12
+ </view>
13
+ <swiper
14
+ v-else
15
+ class="hy-swiper__wrapper"
16
+ :style="{
17
+ flex: '1',
18
+ height: addUnit(height)
19
+ }"
20
+ @change="change"
21
+ :circular="circular"
22
+ :interval="interval"
23
+ :duration="duration"
24
+ :autoplay="autoplay"
25
+ :current="current"
26
+ :currentItemId="currentItemId"
27
+ :previousMargin="addUnit(previousMargin)"
28
+ :nextMargin="addUnit(nextMargin)"
29
+ :acceleration="acceleration"
30
+ :displayMultipleItems="list.length > 0 ? displayMultipleItems : 0"
31
+ :easingFunction="easingFunction"
32
+ >
33
+ <swiper-item
34
+ class="hy-swiper__wrapper--item"
35
+ v-for="(item, index) in list"
36
+ :key="index"
37
+ >
38
+ <slot v-if="$slots.default" :record="item" :index="index"> </slot>
39
+ <view v-else class="hy-swiper__wrapper--item__wrapper" :style="[itemStyle(index)]">
40
+ <!-- 在nvue中,image图片的宽度默认为屏幕宽度,需要通过flex:1撑开,另外必须设置高度才能显示图片 -->
41
+ <image
42
+ class="hy-swiper__wrapper--item__wrapper--image"
43
+ v-if="getItemType(item) === 'image'"
44
+ :src="getSource(item)"
45
+ :mode="imgMode"
46
+ @tap="clickHandler(index)"
47
+ :style="{
48
+ height: addUnit(height),
49
+ borderRadius: addUnit(radius)
50
+ }"
51
+ ></image>
52
+ <video
53
+ class="hy-swiper__wrapper--item__wrapper--video"
54
+ v-if="getItemType(item) === 'video'"
55
+ :id="`video-${index}`"
56
+ :enable-progress-gesture="false"
57
+ :src="getSource(item)"
58
+ :poster="getPoster(item)"
59
+ :title="showTitle && hasTitle(item)"
60
+ :style="{
61
+ height: addUnit(height)
62
+ }"
63
+ controls
64
+ @tap="clickHandler(index)"
65
+ ></video>
66
+ <view
67
+ v-if="showTitle && hasTitle(item)"
68
+ class="hy-swiper__wrapper--item__wrapper--title"
69
+ >
70
+ <text class="hy-line-1">{{ hasTitle(item) }}</text>
71
+ </view>
72
+ </view>
73
+ </swiper-item>
74
+ </swiper>
75
+ <view class="hy-swiper__indicator" :style="[indicatorStyle]">
76
+ <slot
77
+ v-if="$slots.indicator"
78
+ name="indicator"
79
+ :current="currentIndex"
80
+ :length="list.length"
81
+ >
82
+ </slot>
83
+ <hy-swiper-indicator
84
+ v-else-if="!loading && indicator && !showTitle"
85
+ :indicatorActiveColor="indicatorActiveColor"
86
+ :indicatorInactiveColor="indicatorInactiveColor"
87
+ :length="list.length"
88
+ :current="currentIndex"
89
+ :indicatorMode="indicatorMode"
90
+ ></hy-swiper-indicator>
91
+ </view>
92
+ </view>
93
+ </template>
94
+
95
+ <script lang="ts">
96
+ export default {
97
+ name: 'hy-swiper',
98
+ options: {
99
+ addGlobalClass: true,
100
+ virtualHost: true,
101
+ styleIsolation: 'shared'
102
+ }
103
+ }
104
+ </script>
105
+
106
+ <script setup lang="ts">
107
+ import { computed, ref, watch, getCurrentInstance } from 'vue'
108
+ import type { CSSProperties } from 'vue'
109
+ import { addUnit, isVideo } from '../../libs'
110
+ import type { ISwiperEmits, SwiperList, SwiperVo } from './typing'
111
+ import swiperProps from './props'
112
+ // 组件
113
+ import HyLoading from '../hy-loading/hy-loading.vue'
114
+ import HySwiperIndicator from './hy-swiper-indicator.vue'
115
+
116
+ /**
117
+ * 一般用于导航轮播,广告展示等场景,可开箱即用
118
+ * @displayName hy-swiper
119
+ */
120
+ defineOptions({})
121
+
122
+ const props = defineProps(swiperProps)
123
+ const emit = defineEmits<ISwiperEmits>()
124
+
125
+ const instance = getCurrentInstance()
126
+ const currentIndex = ref<string | number>(0)
127
+
128
+ watch(
129
+ () => props.current,
130
+ (newVal) => {
131
+ currentIndex.value = newVal
132
+ }
133
+ )
134
+
135
+ const hasTitle = computed(() => {
136
+ return (item: string | Record<string, any>) => {
137
+ if (typeof item === 'object') {
138
+ return item.title || ''
139
+ } else {
140
+ return ''
141
+ }
142
+ }
143
+ })
144
+
145
+ /**
146
+ * 轮播图3D效果
147
+ * */
148
+ const itemStyle = computed(() => {
149
+ return (index: number): CSSProperties => {
150
+ const style: CSSProperties = {}
151
+ // #ifndef APP-NVUE || MP-TOUTIAO
152
+ // 左右流出空间的写法不支持nvue和头条
153
+ // 只有配置了此二值,才加上对应的圆角,以及缩放
154
+ if (props.nextMargin && props.previousMargin) {
155
+ style.borderRadius = addUnit(props.radius)
156
+ if (index !== currentIndex.value) style.transform = 'scale(0.92)'
157
+ }
158
+ // #endif
159
+ return style
160
+ }
161
+ })
162
+
163
+ /**
164
+ * 获取目标路径,可能数组中为字符串,对象的形式,额外可指定对象的目标属性名keyName
165
+ * */
166
+ const getSource = (item: string | Record<string, any>): string => {
167
+ if (typeof item === 'string') return item
168
+ if (typeof item === 'object' && props.keyName) return item[props.keyName]
169
+ return ''
170
+ }
171
+
172
+ /**
173
+ * 轮播切换事件
174
+ */
175
+ const change = (e: SwiperVo) => {
176
+ // 当前的激活索引
177
+ const { current } = e.detail
178
+ pauseVideo(currentIndex.value)
179
+ currentIndex.value = current
180
+ emit('update:current', currentIndex.value)
181
+ emit('change', e.detail)
182
+ }
183
+
184
+ /**
185
+ * 切换轮播时,暂停视频播放
186
+ * */
187
+ const pauseVideo = (index: number | string) => {
188
+ const lastItem = getSource(props.list[Number(index)])
189
+ if (isVideo(lastItem)) {
190
+ // 当视频隐藏时,暂停播放
191
+ // #ifdef MP-WEIXIN
192
+ const video = uni.createVideoContext(`video-${index}`, instance)
193
+ video.pause()
194
+ // #endif
195
+ }
196
+ }
197
+
198
+ /**
199
+ * 当一个轮播item为视频时,获取它的视频海报
200
+ * */
201
+ const getPoster = (item: string | SwiperList): string => {
202
+ return typeof item === 'object' && item.poster ? item.poster : ''
203
+ }
204
+
205
+ /**
206
+ * 点击某个item
207
+ * */
208
+ const clickHandler = (index: number) => {
209
+ emit('click', index)
210
+ }
211
+
212
+ /**
213
+ * 判断链接是视频还是图片
214
+ * */
215
+ const getItemType = computed(() => {
216
+ return (item: string | Record<string, unknown>) => {
217
+ if (typeof item === 'string') return isVideo(item) ? 'video' : 'image'
218
+ if (typeof item === 'object' && props.keyName) {
219
+ if (!item.type) return isVideo(item[props.keyName] as string) ? 'video' : 'image'
220
+ if (item.type === 'image') return 'image'
221
+ if (item.type === 'video') return 'video'
222
+ return 'image'
223
+ }
224
+ }
225
+ })
226
+ </script>
227
+
228
+ <style lang="scss" scoped>
229
+ @import './index.scss';
230
+ </style>
@@ -51,14 +51,14 @@
51
51
 
52
52
 
53
53
  @include b(swiper-indicator) {
54
- &__wrapper {
54
+ @include e(wrapper) {
55
55
  @include flex;
56
56
 
57
- &--line {
57
+ @include m(line){
58
58
  border-radius: 100px;
59
59
  height: 4px;
60
60
 
61
- &__bar {
61
+ @include e(bar) {
62
62
  width: 22px;
63
63
  height: 4px;
64
64
  border-radius: $hy-border-radius-semicircle;
@@ -67,13 +67,13 @@
67
67
  }
68
68
  }
69
69
 
70
- &__dot {
70
+ @include m(dot) {
71
71
  width: 5px;
72
72
  height: 5px;
73
73
  border-radius: $hy-border-radius-semicircle;
74
74
  margin: 0 $hy-border-margin-padding-sm;
75
75
 
76
- &--active {
76
+ @include e(active) {
77
77
  width: 12px;
78
78
  }
79
79
  }
@@ -1,6 +1,5 @@
1
1
  import type { SwiperList } from './typing'
2
2
  import type { CSSProperties, PropType } from 'vue'
3
- import type { SwiperEasingFunction } from '@uni-helper/uni-types'
4
3
 
5
4
  const swiperProps = {
6
5
  /** 轮播图数据 */
@@ -100,7 +99,7 @@ const swiperProps = {
100
99
  },
101
100
  /** 组件高度 */
102
101
  height: {
103
- type: Number,
102
+ type: [String, Number],
104
103
  default: 130
105
104
  },
106
105
  /** 背景颜色 */
@@ -58,24 +58,24 @@
58
58
  item?.badge?.value)
59
59
  )
60
60
  "
61
- :isDot="(item?.badge && item?.badge?.isDot) || propsBadge?.isDot"
62
- :value="(item?.badge && item?.badge?.value) || propsBadge?.value"
63
- :max="(item?.badge && item?.badge?.max) || propsBadge?.max"
64
- :type="(item?.badge && item?.badge?.type) || propsBadge?.type"
61
+ :isDot="(item?.badge && item?.badge?.isDot) || badgeProps?.isDot"
62
+ :value="(item?.badge && item?.badge?.value) || badgeProps?.value"
63
+ :max="(item?.badge && item?.badge?.max) || badgeProps?.max"
64
+ :type="(item?.badge && item?.badge?.type) || badgeProps?.type"
65
65
  :showZero="
66
- (item?.badge && item?.badge?.showZero) || propsBadge?.showZero
66
+ (item?.badge && item?.badge?.showZero) || badgeProps?.showZero
67
67
  "
68
68
  :bgColor="
69
- (item?.badge && item?.badge?.bgColor) || propsBadge?.bgColor
69
+ (item?.badge && item?.badge?.bgColor) || badgeProps?.bgColor
70
70
  "
71
- :color="(item?.badge && item?.badge?.color) || propsBadge?.color"
72
- :shape="(item?.badge && item?.badge?.shape) || propsBadge?.shape"
71
+ :color="(item?.badge && item?.badge?.color) || badgeProps?.color"
72
+ :shape="(item?.badge && item?.badge?.shape) || badgeProps?.shape"
73
73
  :numberType="
74
74
  (item?.badge && item?.badge?.numberType) ||
75
- propsBadge?.numberType
75
+ badgeProps?.numberType
76
76
  "
77
77
  :inverted="
78
- (item?.badge && item?.badge?.inverted) || propsBadge?.inverted
78
+ (item?.badge && item?.badge?.inverted) || badgeProps?.inverted
79
79
  "
80
80
  :customStyle="{
81
81
  marginLeft: '4px'
@@ -103,20 +103,20 @@
103
103
  </view>
104
104
  <slot name="right" />
105
105
  </view>
106
-
107
- <!-- 内容轮播图 -->
108
- <slot v-if="$slots.main" name="main"></slot>
109
- <swiper
110
- v-else-if="list.length"
111
- :current="innerCurrent"
112
- @animationfinish="animationFinish"
113
- :style="{ height: swiperHeight }"
114
- >
115
- <swiper-item class="swiper-item" v-for="(item, i) in list" :key="i">
116
- <slot :record="item" :index="i" />
117
- </swiper-item>
118
- </swiper>
119
106
  </view>
107
+
108
+ <!-- 内容轮播图 -->
109
+ <slot v-if="$slots.main" name="main"></slot>
110
+ <swiper
111
+ v-else-if="isSwiper || list.length"
112
+ :current="innerCurrent"
113
+ @animationfinish="animationFinish"
114
+ :style="{ height: swiperHeight }"
115
+ >
116
+ <swiper-item class="swiper-item" v-for="(item, i) in list" :key="i">
117
+ <slot :record="item" :index="i" />
118
+ </swiper-item>
119
+ </swiper>
120
120
  </template>
121
121
 
122
122
  <script lang="ts">
@@ -325,6 +325,7 @@ const animationFinish = (e: any) => {
325
325
  innerCurrent.value = e.detail.current
326
326
  resize()
327
327
  if (e.detail.source === 'touch') {
328
+ emit('update:current', innerCurrent.value)
328
329
  emit('change', props.list[innerCurrent.value], innerCurrent.value)
329
330
  }
330
331
  }
@@ -55,7 +55,7 @@ const tabsProps = {
55
55
  /** 轮播图高度 */
56
56
  swiperHeight: {
57
57
  type: [String, Number],
58
- default: 'calc(100vh - 44px)'
58
+ default: 'calc(100% - 44px)'
59
59
  },
60
60
  /** 菜单是否可滚动 */
61
61
  scrollable: {
@@ -63,9 +63,16 @@ const tabsProps = {
63
63
  default: true
64
64
  },
65
65
  /**
66
- * @description 徽标props全局定义
66
+ * 徽标props全局定义
67
67
  * */
68
- propsBadge: Object as PropType<HyBadgeProps>,
68
+ badgeProps: Object as PropType<HyBadgeProps>,
69
+ /**
70
+ * 是否出现内容轮播
71
+ * */
72
+ isSwiper: {
73
+ type: Boolean,
74
+ default: false
75
+ },
69
76
  /** 标签左侧图标样式自定义 */
70
77
  iconStyle: Object as PropType<CSSProperties>,
71
78
  /** 定义需要用到的外部样式 */