前言
问题:pc端显示竖屏/横屏手机视频时,宽度不同,布局比较混乱。
解决:统一视频外层div宽度(根据实际情况),设置视频样式
objectFit: 'scale-down'无论容器的大小如何,图片都会保持其原始的宽高比,并且不会放大以填充容器。如果容器比图片小,图片会根据需要进行缩小。竖屏视频样式问题:由于外层div宽度固定,横屏视频可以占满宽度,竖屏视频自适应宽度会有拉伸变形。
竖屏视频样式问题解决:使用抖音视频展示方式,水平居中并按比例高度自适应外层div,横向留白使用第一帧视频图片并模糊化设置为当前div背景图,与视频统一展示。
css样式设置:
获取视频第一帧做背景图,并将背景图模糊化,设置为视频背景统一视图,从而解决视频无法自适应宽度导致的留白问题。
效果
css实现
设置父子position定位,在两张图片设置z-index层级,在层级低的图片设置filter模糊效果和opacity透明度。 第一张图片:视频默认显示图片,水平居中,按比例高度占满。 第二张图片:获取视频第一帧,设置模糊和透明度,占满整个div。
<div
style={{
height: 180,
overflow: 'hidden',
borderTopLeftRadius: '6px',
borderTopRightRadius: '6px',
position: 'relative',
}}
>
<img
id={`myVideo`}
src={'图片链接'}
alt="图片错误"
style={{
display: 'block',
width: '100%',
height: '100%',
objectFit: 'scale-down',
position: 'absolute',
zIndex: 2,
}}
/>
<img
id={`myVideo`}
src={'截取的视频的第一帧图片'}
style={{
display: 'block',
width: '100%',
height: '100%',
objectFit: 'fill',
background: '#000000',
position: 'absolute',
zIndex: 1,
filter: 'blur(20px)',
opacity: 0.8,
}}
/>
</div>
获取视频第一帧
通过getDataURL创建video元素并设置属性,video.currentTime = 1将currentTime属性设置为1,这样视频就会从第1秒开始播放,便于获取第一帧。
video.addEventListener('loadeddata', function () {})当视频数据加载完成时,将视频通过canvas绘制成图片,并将图片通过toDataURL转换为base64码。通过base64码在<img/>中显示图片。
/*
* videoId:视频id
* url:视频路径
* callBack:回调函数
*/
export const getVideoFirstFrame = (videoId: string, url: string, callBack: Function) => {
const getDataURL = (videoId: string, url: string) => {
return new Promise((resolve, reject) => {
let dataURL = '';
let video = document.createElement('video');
video.setAttribute('id', videoId);
video?.setAttribute('crossOrigin', 'anonymous');
video.setAttribute('src', url);
video?.setAttribute('preload', 'auto');
// video?.setAttribute('style',' objectFit: fill')
video.currentTime = 1;
video.addEventListener('loadeddata', function () {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
const dataURL = canvas.toDataURL('image/jpeg', 1); // 转换为base64
resolve(dataURL);
// 清理资源
video.removeAttribute('src');
canvas.width = 0;
canvas.height = 0;
});
video.addEventListener('error', (error) => {
reject(new Error('Failed to load video'));
});
});
};
getDataURL(videoId, url).then((res) => {
callBack(res);
});
};
// 调用
const ruleSize = async (nItemObj: { url: string; id: number }) => {
let getRes = await getFileData(nItemObj?.url);
console.log(getRes)
};
通过url获取图片信息
base64转换成File
// base64转换成File
export const base64ToFile = (dataurl: string, filename?: string) => {
let newFilename = filename || 'img';
var arr = dataurl.split(','),
mime = arr[0]?.match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
let result = new File([u8arr], newFilename, { type: mime });
return result;
};
将小数转换成分数
用于获取图片宽高比例
// 将小数转换成分数
export const decimalToFraction = (decimal: number) => {
if (decimal < 0) {
return '-' + decimalToFraction(-decimal);
}
var tolerance = 1.0e-6;
var h1 = 1;
var h2 = 0;
var k1 = 0;
var k2 = 1;
var b = decimal;
do {
var a = Math.floor(b);
var num = h1 * a + h2;
var den = k1 * a + k2;
h2 = h1;
k2 = k1;
h1 = num;
k1 = den;
b = 1 / (b - a);
} while (Math.abs(decimal - num / den) > decimal * tolerance);
return num + '/' + den;
};
将图片url转成base64和图片信息
// 将图片url转成base64
const getDataURL = (url: string) => {
return new Promise((resolve, reject) => {
let dataURL = '';
let img = new Image();
img.setAttribute('crossOrigin', 'anonymous'); //关键
img.src = url;
let imgName = url?.split('/')?.pop();
img.onload = function () {
const canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
ctx?.drawImage(img, 0, 0, canvas.width, canvas.height);
dataURL = canvas.toDataURL('image/jpeg', 1); //转换为base64
let fileValue = base64ToFile(dataURL, imgName);
// 宽高比例 返回1为1:1 返回0.75为3:4
let aspectRatioValue = img?.width / img?.height;
const getaspectRatio = (value: number) => {
let getFraction = decimalToFraction(value);
let aspectRatio = getFraction?.replace('/', ':');
return aspectRatio;
};
let imgInfo = {
file: fileValue,
videoWidth: img?.width, //'宽'
videoHeight: img?.height, //'高'
fileValueSize: fileValue?.size, //'大小'
fileValueName: fileValue?.name, //'名称'
aspectRatioValue: aspectRatioValue, // 宽高值
aspectRatio: getaspectRatio(aspectRatioValue), // 宽高比例
};
resolve(imgInfo);
};
});
};
将url转换成fiel文件并获取数据
// 将url转换成fiel文件并获取数据
export const getFileData = async (url: string, callback?: Function) => {
let result=null
await getDataURL(url).then((res) => {
result=res
});
return result
};
图片信息
如有问题,请多多指教。🎃