*高端的食材,往往只需要最朴素的烹饪方式,本文用css旋转定位实现视频全屏播放,朴实无华,简单实用,本文为原创,分享请标明出处*
实习入职第三周,在经过两周的改bug和切图之后,组里说给我一个有挑战性的需求,做一个视频全屏播放的功能
简单来说,就是点击按钮,将视频全屏播放,宽高比例过1.8的横屏播放,小于1.8的仍然竖屏播放,就像下面这样
看完需求我的思考如下:
1.在原页面操作属实麻烦,需要点击全屏按钮跳转到新页面播放
2.由于需要保留侧边栏的点赞关注等功能,所以需要组件分离复用
3.由于存在横竖屏之分,所以跳转页面时需要传递视频宽高比,新页 面需要分别写出横屏和竖屏的css样式
开工:
项目中视频用的是uniapp的video组件,底部的滑动条用的是uniapp的slider组件,我于是乎我在uniapp的文档中查到一个属性
由于我们的项目将全屏按钮隐藏掉了,而且这个属性不能手动设置判断的宽高比,所以我选择弃用现有的轮子,另辟蹊径
有可能是前两周切图css写多了,一下就想到既然是横屏直接将视图旋转90度不久好了吗,于是我开始着手尝试
1.直接将视频顺时针旋转90度,并且将视频宽度改为100vh,高度改为100vw,使其充满整个屏幕
.full-page-video-horizontal {
width: 100vh;
height: 100vw;
transform: rotate(90deg);
}
效果如下
很明显,这里出现了中心点偏移的情况,css3旋转的中心点默认是元素的中心点,所以我们将宽高改变后元素的中心点由原来的(50vw,50vh)变成了(50vh,50vw),所以接下来要用相对定位将屏幕中心点(即整个元素)移回原来的坐标
复位
.full-page-video-horizontal {
width: 100vh;
height: 100vw;
transform: rotate(90deg);
+ position: relative;
+ right: calc(50vh - 50vw);
+ top: calc(50vh - 50vw)
}
视频旋转完成了,接下来是对slider的处理,这里有一个大坑,因为我们直接将slider也旋转90度再复位到屏幕底部,但是因为uniapp的slider组件并没有给出相应的方向属性,所以在我们把视图旋转过来之后,虽然滑动条竖向显示了,但是它仍然只能横向拖动,简单来说就是:视图旋转了,逻辑没有跟着旋转
所以当横屏播放时,我们也弃用slider自带的拖动功能,使用touchstart和touchend替代拖动和点击事件
拖动开始,将当前的y坐标保存到状态:
touchStart(e) {
this.currentVideoContext.pause()
this.nowY = e.changedTouches[0].pageY
},
拖动结束,计算当前y和状态中y的差值,得出偏移量,计算偏移量和屏幕总高度的比,并等比移动进度条
touchEnd(e) {
const {
windowWidth,
windowHeight
} = uni.getSystemInfoSync();
let sliderWidth = windowHeight * 0.85
let y = e.changedTouches[0].pageY
let dy = y - this.nowY
let value = dy / sliderWidth
const {
duration,
currentTime
} = this.progressTime;
const time = duration * (value + (currentTime / duration));
this.currentVideoContext.seek(time)
this.currentVideoContext.play()
},
模拟点击事件,即当拖动的距离足够小时,直接记录当前y坐标,获取视口高度,得出当前y坐标在整个视口的相对位置,并且把进度条调到整个进度条的同比相对位置
tapSlider(e) {
const {
windowWidth,
windowHeight
} = uni.getSystemInfoSync();
let begin = windowHeight * 0.07
let y = e.changedTouches[0].pageY
let dy = y - begin
let rate = dy / (windowHeight * 0.85)
const {
duration,
currentTime
} = this.progressTime;
let time = duration * rate
this.currentVideoContext.seek(time)
},
PS:由于拖动进度条的时候视频仍处于播放中,进度状态不停的在更新,会导致拖动时有闪动的情况,所以需要在拖动开始时暂停视频,在拖动结束后再播放,但是uniapp的slider组件没有拖动开始的属性,只有sliderChanging,它会在拖动中高频率触发,所以我们写一个节流函数让它3秒只触发一次暂停视频,减少不必要的内存消耗
//进度条拖拽节流
sliderChanging() {
if (this.t) return
this.t = setTimeout(() => {
this.t = null
}, 3000)
this.currentVideoContext.pause()
},
具体实现的一些细节需要各位自行写出代码编译尝试,祝大家学有所得