uview-plus 3.5.10 → 3.5.16

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.
@@ -0,0 +1,19 @@
1
+ export default {
2
+ props: {
3
+ // PDF文件地址
4
+ src: {
5
+ type: String,
6
+ default: ''
7
+ },
8
+ // 组件高度
9
+ height: {
10
+ type: String,
11
+ default: '700px'
12
+ },
13
+ // pdfjs资源域名
14
+ baseUrl: {
15
+ type: String,
16
+ default: 'https://uview-plus.jiangruyi.com/h5'
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,52 @@
1
+ <template>
2
+ <view class="up-pdf-reader" :style="{ height: height }">
3
+ <web-view :fullscreen="false"
4
+ :src="viewerUrl" :style="{ width: '750rpx', height: height }"
5
+ :webview-styles="{ width: '750rpx', height: height }"
6
+ frameborder="0"
7
+ ></web-view>
8
+ </view>
9
+ </template>
10
+
11
+ <script>
12
+ import props from './props.js';
13
+
14
+ /**
15
+ * pdfReader PDF阅读器
16
+ * @description 基于pdf.js的PDF阅读器组件
17
+ * @tutorial https://uview-plus.jiangruyi.com/components/pdfReader.html
18
+ * @property {String} src PDF文件地址
19
+ * @property {String} height 组件高度,默认为'700px'
20
+ * @property {String} pdfjsDomain pdfjs资源域名,默认为'https://uview-plus.jiangruyi.com/h5'
21
+ * @example <up-pdf-reader src="https://example.com/file.pdf"></up-pdf-reader>
22
+ */
23
+ export default {
24
+ name: 'up-pdf-reader',
25
+ mixins: [props],
26
+ data() {
27
+ return {
28
+ baseUrlInner: 'https://uview-plus.jiangruyi.com/h5',
29
+ viewerUrl: ''
30
+ }
31
+ },
32
+ watch: {
33
+ baseUrl: function (val) {
34
+ this.baseUrl = val;
35
+ },
36
+ src: function (val) {
37
+ this.viewerUrl = `${this.baseUrlInner}/static/pdfjs/web/viewer.html?file=` + encodeURIComponent(val);
38
+ }
39
+ },
40
+ mounted() {
41
+ if (this.baseUrl) {
42
+ this.baseUrlInner = this.baseUrl;
43
+ }
44
+ this.viewerUrl = `${this.baseUrlInner}/static/pdfjs/web/viewer.html?file=` + encodeURIComponent(this.src);
45
+ }
46
+ }
47
+ </script>
48
+
49
+ <style lang="scss" scoped>
50
+ .up-pdf-reader {
51
+ }
52
+ </style>
@@ -0,0 +1,463 @@
1
+ <template>
2
+ <view class="u-short-video">
3
+ <!-- 顶部导航区域 -->
4
+ <view class="u-short-video__header">
5
+ <slot name="menu">
6
+ <view class="u-short-video__header__menu">
7
+ <up-icon name="grid" size="24"></up-icon>
8
+ </view>
9
+ </slot>
10
+
11
+ <up-tabs
12
+ :list="tabsList"
13
+ :current="currentTab"
14
+ lineColor="#ddd"
15
+ :activeStyle="{
16
+ color: '#ddd',
17
+ fontWeight: 400,
18
+ transform: 'scale(1)'
19
+ }"
20
+ :inactiveStyle="{
21
+ color: '#bbb',
22
+ transform: 'scale(1)'
23
+ }"
24
+ @change="handleTabChange"
25
+ class="u-short-video__header__tabs"
26
+ ></up-tabs>
27
+
28
+ <slot name="search">
29
+ <view class="u-short-video__header__search">
30
+ <up-icon name="search" size="24"></up-icon>
31
+ </view>
32
+ </slot>
33
+ </view>
34
+
35
+ <!-- 视频内容区域 -->
36
+ <swiper
37
+ :vertical="true"
38
+ :autoplay="false"
39
+ @change="handleSwiperChange"
40
+ :current="currentVideo"
41
+ class="u-short-video__content"
42
+ >
43
+ <swiper-item v-for="(item, index) in videoList" :key="index">
44
+ <view class="u-short-video__content__item">
45
+ <!-- 视频播放区域 -->
46
+ <view class="u-short-video__content__video">
47
+ <video
48
+ :id="'video-' + index"
49
+ :src="item.videoUrl"
50
+ :autoplay="index === currentVideo"
51
+ :controls="false"
52
+ :show-fullscreen-btn="false"
53
+ :show-play-btn="false"
54
+ :show-center-play-btn="false"
55
+ :enable-progress-gesture="true"
56
+ :loop="true"
57
+ :playback-rate="item.playbackRate || 1.0"
58
+ @play="onVideoPlay"
59
+ @pause="onVideoPause"
60
+ @ended="onVideoEnded"
61
+ @timeupdate="onTimeUpdate"
62
+ @loadedmetadata="onLoadedMetadata"
63
+ style="width: 100%; height: 100%;"
64
+ ></video>
65
+
66
+ <!-- 倍速设置按钮 -->
67
+ <!-- <view class="u-short-video__content__video__speed" @click="showSpeedOptions(index)">
68
+ <text class="speed-text">{{ item.playbackRate || 1.0 }}x</text>
69
+ <up-icon name="arrow-down" size="12" color="#fff"></up-icon>
70
+ </view> -->
71
+ </view>
72
+
73
+ <!-- 作者信息 -->
74
+ <view class="u-short-video__content__author">
75
+ <view class="u-short-video__content__author__avatar">
76
+ <u-avatar :src="item.author.avatar" size="50px"></u-avatar>
77
+ </view>
78
+ <view class="u-short-video__content__author__info">
79
+ <text class="u-short-video__content__author__name">{{ item.author.name }}</text>
80
+ <text class="u-short-video__content__author__desc">{{ item.author.desc }}</text>
81
+ </view>
82
+ <view class="u-short-video__content__author__follow">
83
+ <up-button type="primary" size="mini">关注</up-button>
84
+ </view>
85
+ </view>
86
+
87
+ <!-- 右侧操作区域 -->
88
+ <view class="u-short-video__content__actions">
89
+ <slot name="actions" :item="item" :index="index">
90
+ <view class="u-short-video__content__actions__item" @click="handleLike(item, index)">
91
+ <up-icon color="#eee" :name="item.isLiked ? 'thumb-up-fill' : 'thumb-up'" size="32px"></up-icon>
92
+ <text class="u-short-video__content__actions__text">{{ item.likeCount }}</text>
93
+ </view>
94
+ <view class="u-short-video__content__actions__item" @click="handleComment(item, index)">
95
+ <up-icon color="#eee" name="chat" size="32px"></up-icon>
96
+ <text class="u-short-video__content__actions__text">{{ item.commentCount }}</text>
97
+ </view>
98
+ <view class="u-short-video__content__actions__item" @click="handleShare(item, index)">
99
+ <up-icon color="#eee" name="share" size="32px"></up-icon>
100
+ <text class="u-short-video__content__actions__text">{{ item.shareCount }}</text>
101
+ </view>
102
+ <view class="u-short-video__content__actions__item" @click="handleCollect(item, index)">
103
+ <up-icon color="#eee" :name="item.isCollected ? 'bookmark-fill' : 'bookmark'" size="32px"></up-icon>
104
+ <text class="u-short-video__content__actions__text">{{ item.collectCount }}</text>
105
+ </view>
106
+ </slot>
107
+ </view>
108
+ </view>
109
+ </swiper-item>
110
+ </swiper>
111
+
112
+ <!-- 倍速选择弹窗 -->
113
+ <up-action-sheet
114
+ :show="showSpeedSheet"
115
+ :actions="speedOptions"
116
+ title="播放速度"
117
+ @close="showSpeedSheet = false"
118
+ @select="selectSpeed"
119
+ ></up-action-sheet>
120
+
121
+ <!-- 底部导航栏 -->
122
+ <view class="u-short-video__footer">
123
+ <!-- 进度条 -->
124
+ <view class="u-short-video__progress" style="z-index: 999;">
125
+ <up-slider
126
+ :value="videoList[currentVideo]?.progress"
127
+ :min="0"
128
+ :max="100"
129
+ :step="1"
130
+ :show-value="false"
131
+ :innerStyle="{padding: 0}"
132
+ activeColor="rgba(255,255,255,0.32)"
133
+ inactive-color="rgba(255,255,255,0.3)"
134
+ block-size="6px"
135
+ block-color="rgba(255,255,255,0.5)"
136
+ height="1px"
137
+ @changing="onProgressChanging"
138
+ @change="onProgressChange"
139
+ ></up-slider>
140
+ </view>
141
+
142
+ <slot name="tabbar">
143
+ <up-tabbar
144
+ :fixed="true"
145
+ :placeholder="true"
146
+ :safeAreaInsetBottom="true"
147
+ borderColor="rgba(255,255,255,0.25) !important"
148
+ backgroundColor="rgba(255,255,255,0.05)"
149
+ >
150
+ <up-tabbar-item
151
+ @click="goNext"
152
+ text="首页"
153
+ icon="home"
154
+ >
155
+ </up-tabbar-item>
156
+ <up-tabbar-item
157
+ text="放映厅"
158
+ icon="photo"
159
+ ></up-tabbar-item>
160
+ <up-tabbar-item
161
+ text="直播"
162
+ icon="play-right"
163
+ ></up-tabbar-item>
164
+ <up-tabbar-item
165
+ text="我的"
166
+ icon="account"
167
+ ></up-tabbar-item>
168
+ </up-tabbar>
169
+ </slot>
170
+ </view>
171
+ </view>
172
+ </template>
173
+
174
+ <script>
175
+ export default {
176
+ name: 'u-short-video',
177
+ props: {
178
+ // tabs标签列表
179
+ tabsList: {
180
+ type: Array,
181
+ default: () => [
182
+ { name: '推荐' },
183
+ { name: '关注' },
184
+ { name: '朋友' },
185
+ { name: '本地' }
186
+ ]
187
+ },
188
+ // 视频列表数据
189
+ videoList: {
190
+ type: Array,
191
+ default: () => []
192
+ },
193
+ // 当前选中的tab索引
194
+ currentTab: {
195
+ type: Number,
196
+ default: 0
197
+ },
198
+ // 当前播放的视频索引
199
+ currentVideo: {
200
+ type: Number,
201
+ default: 0
202
+ }
203
+ },
204
+ data() {
205
+ return {
206
+ progressValue: 0,
207
+ showSpeedSheet: false,
208
+ currentSpeedVideoIndex: 0,
209
+ speedOptions: [
210
+ { name: '0.5x', value: 0.5 },
211
+ { name: '0.75x', value: 0.75 },
212
+ { name: '1.0x', value: 1.0 },
213
+ { name: '1.25x', value: 1.25 },
214
+ { name: '1.5x', value: 1.5 },
215
+ { name: '2.0x', value: 2.0 }
216
+ ]
217
+ }
218
+ },
219
+ methods: {
220
+ // 处理tab切换
221
+ handleTabChange(index) {
222
+ this.$emit('tabChange', index);
223
+ },
224
+ // 处理swiper切换
225
+ handleSwiperChange(e) {
226
+ const currentIndex = e.detail.current;
227
+ // 暂停当前播放的视频
228
+ this.pauseCurrentVideo();
229
+ // 播放新切换到的视频
230
+ this.$nextTick(() => {
231
+ this.playVideo(currentIndex);
232
+ });
233
+ this.$emit('videoChange', currentIndex);
234
+ },
235
+ // 处理点赞
236
+ handleLike(item, index) {
237
+ this.$emit('like', { item, index });
238
+ },
239
+ // 处理评论
240
+ handleComment(item, index) {
241
+ this.$emit('comment', { item, index });
242
+ },
243
+ // 处理分享
244
+ handleShare(item, index) {
245
+ this.$emit('share', { item, index });
246
+ },
247
+ // 处理收藏
248
+ handleCollect(item, index) {
249
+ this.$emit('collect', { item, index });
250
+ },
251
+ // 进度条拖动中
252
+ onProgressChanging(value) {
253
+ // 更新当前视频的进度值
254
+ if (this.videoList[this.currentVideo]) {
255
+ this.videoList[this.currentVideo]['progressValue'] = value.detail.value
256
+ }
257
+ this.$emit('progressChanging', {
258
+ progress: value.detail.value,
259
+ index: this.currentVideo
260
+ });
261
+ },
262
+ // 进度条值改变
263
+ onProgressChange(value) {
264
+ // 更新当前视频的进度值
265
+ if (this.videoList[this.currentVideo]) {
266
+ this.$set(this.videoList[this.currentVideo], 'progressValue', value.detail.value);
267
+ }
268
+ this.$emit('progressChange', {
269
+ progress: value.detail.value,
270
+ index: this.currentVideo
271
+ });
272
+ },
273
+ // 显示倍速选项
274
+ showSpeedOptions(index) {
275
+ this.currentSpeedVideoIndex = index;
276
+ this.showSpeedSheet = true;
277
+ },
278
+ // 选择倍速
279
+ selectSpeed(action) {
280
+ const videoContext = uni.createVideoContext('video-' + this.currentSpeedVideoIndex, this);
281
+ videoContext.playbackRate(action.value);
282
+
283
+ // 更新视频倍速数据
284
+ this.$set(this.videoList[this.currentSpeedVideoIndex], 'playbackRate', action.value);
285
+ this.showSpeedSheet = false;
286
+ },
287
+ // 播放指定索引的视频
288
+ playVideo(index) {
289
+ const videoContext = uni.createVideoContext('video-' + index, this);
290
+ videoContext.play();
291
+ },
292
+ // 暂停当前视频
293
+ pauseCurrentVideo() {
294
+ const videoContext = uni.createVideoContext('video-' + this.currentVideo, this);
295
+ videoContext.pause();
296
+ },
297
+ // 视频播放事件
298
+ onVideoPlay(e) {
299
+ this.$emit('videoPlay', { index: this.currentVideo, event: e });
300
+ },
301
+ // 视频暂停事件
302
+ onVideoPause(e) {
303
+ this.$emit('videoPause', { index: this.currentVideo, event: e });
304
+ },
305
+ // 视频结束事件
306
+ onVideoEnded(e) {
307
+ this.$emit('videoEnded', { index: this.currentVideo, event: e });
308
+ },
309
+ // 视频时间更新事件
310
+ onTimeUpdate(e) {
311
+ const progress = (e.detail.currentTime / e.detail.duration) * 100;
312
+ if (this.videoList[this.currentVideo]) {
313
+ this.$set(this.videoList[this.currentVideo], 'progress', progress);
314
+ }
315
+ this.$emit('timeUpdate', { index: this.currentVideo, event: e });
316
+ },
317
+ // 视频元数据加载完成事件
318
+ onLoadedMetadata(e) {
319
+ this.$emit('loadedMetadata', { index: this.currentVideo, event: e });
320
+ }
321
+ }
322
+ }
323
+ </script>
324
+
325
+ <style lang="scss" scoped>
326
+ .u-short-video {
327
+ width: 100%;
328
+ height: 100vh;
329
+ position: relative;
330
+
331
+ &__header {
332
+ position: absolute;
333
+ top: 0;
334
+ left: 0;
335
+ right: 0;
336
+ z-index: 10;
337
+ display: flex;
338
+ flex-direction: row;
339
+ align-items: center;
340
+ justify-content: space-between;
341
+ padding: 10px 15px;
342
+ background-color: rgba(255, 255, 255, 0.05);
343
+ opacity: 1;
344
+
345
+ &__menu, &__search {
346
+ width: 40px;
347
+ height: 40px;
348
+ display: flex;
349
+ align-items: center;
350
+ justify-content: center;
351
+ color: #fff;
352
+ }
353
+
354
+ &__tabs {
355
+ flex: 1;
356
+ margin: 0 10px;
357
+ }
358
+ }
359
+
360
+ &__content {
361
+ width: 100%;
362
+ height: 100%;
363
+
364
+ &__item {
365
+ width: 100%;
366
+ height: 100%;
367
+ position: relative;
368
+ }
369
+
370
+ &__video {
371
+ width: 100%;
372
+ height: 100%;
373
+ position: relative;
374
+
375
+ &__speed {
376
+ position: absolute;
377
+ top: 15px;
378
+ right: 15px;
379
+ z-index: 10;
380
+ background-color: rgba(0, 0, 0, 0.3);
381
+ border-radius: 20px;
382
+ padding: 5px 10px;
383
+ display: flex;
384
+ align-items: center;
385
+
386
+ .speed-text {
387
+ color: #fff;
388
+ font-size: 12px;
389
+ margin-right: 4px;
390
+ }
391
+ }
392
+ }
393
+
394
+ &__author {
395
+ position: absolute;
396
+ left: 15px;
397
+ bottom: 100px;
398
+ display: flex;
399
+ flex-direction: row;
400
+ align-items: center;
401
+ z-index: 10;
402
+
403
+ &__info {
404
+ margin-left: 10px;
405
+ display: flex;
406
+ flex-direction: column;
407
+ justify-content: center;
408
+ }
409
+
410
+ &__name {
411
+ color: #eee;
412
+ font-size: 16px;
413
+ font-weight: bold;
414
+ margin-bottom: 5px;
415
+ }
416
+
417
+ &__desc {
418
+ color: rgba(255, 255, 255, 0.8);
419
+ font-size: 14px;
420
+ }
421
+
422
+ &__follow {
423
+ margin-left: 15px;
424
+ }
425
+ }
426
+
427
+ &__actions {
428
+ position: absolute;
429
+ right: 15px;
430
+ bottom: 100px;
431
+ display: flex;
432
+ flex-direction: column;
433
+ align-items: center;
434
+ z-index: 10;
435
+
436
+ &__item {
437
+ display: flex;
438
+ flex-direction: column;
439
+ align-items: center;
440
+ margin-bottom: 20px;
441
+ color: #fff;
442
+ }
443
+
444
+ &__text {
445
+ color: #fff;
446
+ font-size: 12px;
447
+ margin-top: 5px;
448
+ }
449
+ }
450
+ }
451
+
452
+ &__footer {
453
+ position: absolute;
454
+ bottom: 0;
455
+ left: 0;
456
+ right: 0;
457
+ z-index: 10;
458
+ }
459
+
460
+ &__progress {
461
+ }
462
+ }
463
+ </style>
@@ -86,6 +86,10 @@ export const props = defineMixin({
86
86
  height: {
87
87
  type: String,
88
88
  default: () => defProps.slider.height
89
- }
89
+ },
90
+ innerStyle: {
91
+ type: Object,
92
+ default: () => defProps.slider.innerStyle
93
+ },
90
94
  }
91
95
  })
@@ -22,6 +22,7 @@ export default {
22
22
  disabled:false,
23
23
  blockStyle: {},
24
24
  useNative: false,
25
- height: '2px'
25
+ height: '2px',
26
+ innerStyle: {}
26
27
  }
27
28
  }
@@ -7,9 +7,7 @@
7
7
  <view ref="u-slider-inner" class="u-slider-inner" @click="onClick"
8
8
  @onTouchStart="onTouchStart2($event, 1)" @touchmove="onTouchMove2($event, 1)"
9
9
  @touchend="onTouchEnd2($event, 1)" @touchcancel="onTouchEnd2($event, 1)"
10
- :class="[disabled ? 'u-slider--disabled' : '']" :style="{
11
- height: (isRange && showValue) ? (getPx(blockSize) + 24) + 'px' : (getPx(blockSize)) + 'px',
12
- }"
10
+ :class="[disabled ? 'u-slider--disabled' : '']" :style="innerStyleCpu"
13
11
  >
14
12
  <view ref="u-slider__base"
15
13
  class="u-slider__base"
@@ -177,6 +175,13 @@
177
175
  },
178
176
  created() {
179
177
  },
178
+ computed: {
179
+ innerStyleCpu() {
180
+ let style = this.innerStyle;
181
+ style.height = (this.isRange && this.showValue) ? (getPx(this.blockSize) + 24) + 'px' : (getPx(this.blockSize)) + 'px';
182
+ return style;
183
+ }
184
+ },
180
185
  async mounted() {
181
186
  // 获取滑块条的尺寸信息
182
187
  if (!this.useNative) {
@@ -18,6 +18,11 @@ export const props = defineMixin({
18
18
  type: Boolean,
19
19
  default: () => defProps.tabbar.border
20
20
  },
21
+ // 上方边框颜色
22
+ borderColor: {
23
+ type: Boolean,
24
+ default: () => defProps.tabbar.borderColor
25
+ },
21
26
  // 元素层级z-index
22
27
  zIndex: {
23
28
  type: [String, Number],
@@ -42,6 +47,11 @@ export const props = defineMixin({
42
47
  placeholder: {
43
48
  type: Boolean,
44
49
  default: () => defProps.tabbar.placeholder
50
+ },
51
+ // 背景色
52
+ backgroundColor: {
53
+ type: String,
54
+ default: () => defProps.tabbar.backgroundColor
45
55
  }
46
56
  }
47
57
  })
@@ -17,6 +17,8 @@ export default {
17
17
  activeColor: '#1989fa',
18
18
  inactiveColor: '#7d7e80',
19
19
  fixed: true,
20
- placeholder: true
20
+ placeholder: true,
21
+ borderColor: '',
22
+ backgroundColor: ''
21
23
  }
22
24
  }
@@ -42,6 +42,7 @@
42
42
  * @property {String} inactiveColor 未选中标签的颜色(默认 '#7d7e80' )
43
43
  * @property {Boolean} fixed 是否固定在底部(默认 true )
44
44
  * @property {Boolean} placeholder fixed定位固定在底部时,是否生成一个等高元素防止塌陷(默认 true )
45
+ * @property {String} backgroundColor 背景色(默认 '#ffffff' )
45
46
  * @property {Object} customStyle 定义需要用到的外部样式
46
47
  *
47
48
  * @example <u-tabbar :value="value2" :placeholder="false" @change="name => value2 = name" :fixed="false" :safeAreaInsetBottom="false"><u-tabbar-item text="首页" icon="home" dot ></u-tabbar-item></u-tabbar>
@@ -59,6 +60,12 @@
59
60
  const style = {
60
61
  zIndex: this.zIndex
61
62
  }
63
+ if (this.borderColor) {
64
+ style.borderColor = this.borderColor
65
+ }
66
+ if (this.backgroundColor) {
67
+ style.backgroundColor = this.backgroundColor
68
+ }
62
69
  // 合并来自父组件的customStyle样式
63
70
  return deepMerge(style, addStyle(this.customStyle))
64
71
  },
@@ -7,7 +7,7 @@ export const props = defineMixin({
7
7
  type: [String, Number, null],
8
8
  default: () => defProps.tabbarItem.name
9
9
  },
10
- // uView内置图标或者绝对路径的图片
10
+ // uview-plus内置图标或者绝对路径的图片
11
11
  icon: {
12
12
  icon: String,
13
13
  default: () => defProps.tabbarItem.icon
@@ -31,7 +31,11 @@ export const props = defineMixin({
31
31
  badgeStyle: {
32
32
  type: [Object, String],
33
33
  default: () => defProps.tabbarItem.badgeStyle
34
+ },
35
+ // 模式,默认普通模式,midButton中间按钮模式
36
+ mode: {
37
+ type: String,
38
+ default: () => defProps.tabbarItem.mode
34
39
  }
35
-
36
40
  }
37
41
  })
@@ -15,6 +15,7 @@ export default {
15
15
  badge: null,
16
16
  dot: false,
17
17
  text: '',
18
- badgeStyle: 'top: 6px;right:2px;'
18
+ badgeStyle: 'top: 6px;right:2px;',
19
+ mode: ''
19
20
  }
20
21
  }