商城
刀刀
12/31/2024
0 字
0 分钟
视频轮播图动态轮播
思路
在商品详情页中,使用了 uView 组件库的 Awiper 轮播图组件。该组件前面介绍过,可以设置视频和图片在轮播图内。
今天测试提了一个需求:在视频播放的时候轮播图还在自动轮播,能不能视频播放时停止自动轮播,结束或暂停播放后再继续自动轮播。
首先第一件事就是查阅文档,文档上提供了 click
点击方法,可以判断用户点击的是不是视频,点击一次停止轮播,再次点击继续轮播。
但是这并不是最好的选择,他无法侦听到视频播放结束的事件。此时官方文档没有能解决我们需求的方法,官方的组件也无法满足我们的需求,我们可以复制其底层代码,自己添加事件。
本项目 uView 通过 hBuilder 导入,因此找到 uni-module 文件夹,找到 u-swiper.vue
组件,复制粘贴到自己创建的组件文件内。
源码赏析
首先看看别人封装的组件源码,学习学习。
他们是获取到父组件传入的数组,通过原生 swiper
轮播图组件,循环数组内容渲染到 swiper-item
上,通过 v-if
判断当前对象的类型,图片类型用 image
显示,视频类型用 video
显示。代码如下:
<swiper @change="change">
<swiper-item
v-for="(item, index) in list"
:key="index"
>
<view
>
<!-- 在nvue中,image图片的宽度默认为屏幕宽度,需要通过flex:1撑开,另外必须设置高度才能显示图片 -->
<image
v-if="getItemType(item) === 'image'"
:src="getSource(item)"
:mode="imgMode"
@tap="clickHandler(index)"></image>
<video
v-if="getItemType(item) === 'video'"
:id="`video-${index}`"
:enable-progress-gesture="false"
:src="getSource(item)"
@tap="clickHandler(index)"></video>
</view>
</swiper-item>
</swiper>
<script>
export default {
methods: {
getSource(item) {
if (typeof item === 'string') return item
if (typeof item === 'object' && this.keyName) return item[this.keyName]
else uni.$u.error('请按格式传递列表参数')
return ''
},
}
}
</script>
这也就是为什么他要求我们在传入数组时以对象的形式,包括路径和类型的参数。
其中,视频与图片都有 @tap
点击事件,对应文档提供的 click
点击事件,其事件代码如下所示:
// 点击某个item
clickHandler(index) {
this.$emit('click', index)
}
而它的轮播图组件的 change
事件则会判断当前项是否为视频,如果是视频组件,则让其暂停播放(为啥不让轮播暂停呢)。代码如下所示:
// 轮播切换事件
change(e) {
// 当前的激活索引
const {
current
} = e.detail
this.pauseVideo(this.currentIndex)
this.currentIndex = current
this.$emit('change', e.detail)
},
// 切换轮播时,暂停视频播放
pauseVideo(index) {
const lastItem = this.getSource(this.list[index])
if (uni.$u.test.video(lastItem)) {
// 当视频隐藏时,暂停播放
const video = uni.createVideoContext(`video-${index}`, this)
video.pause()
}
},
// 当一个轮播item为视频时,获取它的视频海报
getPoster(item) {
return typeof item === 'object' && item.poster ? item.poster : ''
},
修改
接下来就好办多了,为视频 video
组件添加播放 play
、暂停 pause
、停止 ended
事件,触发后分别通过 $emit()
子传父自定义事件通知父组件,如下所示:
<video @tap="clickHandler(index)" @ended="noPlay()" @pause="noPlay()" @play="startPlay()" ></video>
<script>
export default {
methods: {
startPlay() {
this.$emit('startPlay')
},
noPlay() {
this.$emit('noPlay')
},
}
}
</script>
父组件通过自定义事件动态修改自动轮播的参数:
<MySwiper keyName="url" :autoplay="autoplay" :list="bannerList" height="570rpx" indicator indicatorMode="dot" indicatorActiveColor="#f88d55" @noPlay="noPlay" @startPlay="startPlay"></MySwiper>
<script>
export default {
startPlay() {
this.autoplay = false
},
noPlay() {
this.autoplay = true
},
}
</script>
现在就能够实现效果了。
微信支付
商城开通了微信支付,查阅 UniApp
支付文档 ,代码示例如下:
// 仅作为示例,非真实参数信息。
uni.requestPayment({
provider: 'wxpay',
timeStamp: String(Date.now()),
nonceStr: 'A1B2C3D4E5',
package: 'prepay_id=wx20180101abcdefg',
signType: 'MD5',
paySign: '',
success: function (res) {
console.log('success:' + JSON.stringify(res));
},
fail: function (err) {
console.log('fail:' + JSON.stringify(err));
}
});
可以看到,在 APP 模块中需要传到 orderInfo
对象内的参数在微信小程序中直接传递即可。其中参数如下:
参数名 | 类型 | 必填 | 说明 | 平台差异说明 |
---|---|---|---|---|
timeStamp | String | 微信小程序必填 | 时间戳从1970年1月1日至今的秒数,即当前的时间 | 微信小程序 |
nonceStr | String | 微信小程序必填 | 随机字符串,长度为32个字符以下。 | 微信小程序 |
package | String | 微信小程序必填 | 统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=xx。 | 微信小程序 |
signType | String | 微信小程序必填 | 签名算法,应与后台下单时的值一致 | 微信小程序 |
paySign | String | 微信小程序必填 | 签名,具体签名方案参见 微信小程序支付文档 | 微信小程序 |
后端很贴心都把数据返回了,直接拿来使用即可。
BUG
高度100vh与上拉加载冲突
测试和我说某页面上拉加载更多没反应,于是开始复现。发现他没有调接口获取新数据,于是开始排查原因。
首先看看他有没有触发 onReachBottom
钩子函数,添加 connsole.log()
后查看控制台打印,发现并没有任何打印,说明没触发该钩子。
可是页面已经滚动到底部了,为什么没触发呢?百度后得知,我给外层 view
设置了高度 100vh 并 overflow: auto
的缘故,页面滚动只在该标签内滚动,而onReachBottom
监听的是页面的滚动,因此不会触发。
把外层 view
改为 min-height
和去掉 overflow
即可。代码如下:
<style lang="scss" scoped>
.order {
width: 100vw;
min-height: 100vh;
background-color: #f9f8fb;
padding-bottom: 30rpx;
box-sizing: border-box;
}
</style>