跳转到内容

商城

刀刀

12/31/2024

0 字

0 分钟

视频轮播图动态轮播

思路

在商品详情页中,使用了 uView 组件库的 Awiper 轮播图组件。该组件前面介绍过,可以设置视频和图片在轮播图内。

今天测试提了一个需求:在视频播放的时候轮播图还在自动轮播,能不能视频播放时停止自动轮播,结束或暂停播放后再继续自动轮播。

首先第一件事就是查阅文档,文档上提供了 click 点击方法,可以判断用户点击的是不是视频,点击一次停止轮播,再次点击继续轮播。

但是这并不是最好的选择,他无法侦听到视频播放结束的事件。此时官方文档没有能解决我们需求的方法,官方的组件也无法满足我们的需求,我们可以复制其底层代码,自己添加事件。

本项目 uView 通过 hBuilder 导入,因此找到 uni-module 文件夹,找到 u-swiper.vue 组件,复制粘贴到自己创建的组件文件内。

源码赏析

首先看看别人封装的组件源码,学习学习。

他们是获取到父组件传入的数组,通过原生 swiper 轮播图组件,循环数组内容渲染到 swiper-item 上,通过 v-if 判断当前对象的类型,图片类型用 image 显示,视频类型用 video 显示。代码如下:

html
<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 点击事件,其事件代码如下所示:

js
// 点击某个item
clickHandler(index) {
	this.$emit('click', index)
}

而它的轮播图组件的 change 事件则会判断当前项是否为视频,如果是视频组件,则让其暂停播放(为啥不让轮播暂停呢)。代码如下所示:

js
// 轮播切换事件
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() 子传父自定义事件通知父组件,如下所示:

vue
<video @tap="clickHandler(index)" @ended="noPlay()" @pause="noPlay()" @play="startPlay()" ></video>

<script>
export default {
    methods: {
        startPlay() {
				this.$emit('startPlay')
			},
			noPlay() {
				this.$emit('noPlay')
			},
    }
}
</script>

父组件通过自定义事件动态修改自动轮播的参数:

vue
<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 支付文档 ,代码示例如下:

js
// 仅作为示例,非真实参数信息。
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 对象内的参数在微信小程序中直接传递即可。其中参数如下:

参数名类型必填说明平台差异说明
timeStampString微信小程序必填时间戳从1970年1月1日至今的秒数,即当前的时间微信小程序
nonceStrString微信小程序必填随机字符串,长度为32个字符以下。微信小程序
packageString微信小程序必填统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=xx。微信小程序
signTypeString微信小程序必填签名算法,应与后台下单时的值一致微信小程序
paySignString微信小程序必填签名,具体签名方案参见 微信小程序支付文档微信小程序

后端很贴心都把数据返回了,直接拿来使用即可。

BUG

高度100vh与上拉加载冲突

测试和我说某页面上拉加载更多没反应,于是开始复现。发现他没有调接口获取新数据,于是开始排查原因。

首先看看他有没有触发 onReachBottom 钩子函数,添加 connsole.log() 后查看控制台打印,发现并没有任何打印,说明没触发该钩子。

可是页面已经滚动到底部了,为什么没触发呢?百度后得知,我给外层 view 设置了高度 100vh 并 overflow: auto 的缘故,页面滚动只在该标签内滚动,而onReachBottom 监听的是页面的滚动,因此不会触发。

把外层 view 改为 min-height 和去掉 overflow 即可。代码如下:

css
<style lang="scss" scoped>
	.order {
		width: 100vw;
		min-height: 100vh;
		background-color: #f9f8fb;
		padding-bottom: 30rpx;
		box-sizing: border-box;
	}
</style>