使用纯html,css,js实现西瓜,抖音视频上传,视频帧选取封面功能,只做了功能,部分优化可以自行修改
效果图片预览:
效果视频预览:
仿西瓜,抖音视频上传封面图功能
完整代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>视频帧提取封面</title>
<style>
* {
margin: 0;
padding: 0;
}
img {
width: 100%;
height: auto;
vertical-align: bottom;
}
body {
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background-color: #fff;
}
.imgs {
width: 455px;
min-height: 256px;
margin: 0 auto;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
border: 2px solid #ebebeb;
margin-bottom: 30px;
background-color: #fff;
}
.btns {
display: flex;
align-items: center;
justify-content: center;
}
.button {
position: relative;
width: 100px;
height: 36px;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
background-color: #fe3355;
border-radius: 5px;
margin-bottom: 50px;
}
.button input {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
cursor: pointer;
}
.imgs_list {
position: relative;
min-width: 300px;
min-height: 100px;
background-color: #fff;
border: 2px solid #ebebeb;
}
.imgs_list_box {
display: flex;
align-items: center;
justify-content: center;
}
.img_item {
height: 100px;
}
.img_item img {
width: auto;
height: 100%;
}
/* 隐藏默认的滑块样式 */
input[type="range"] {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
width: 100%;
height: 10px;
background-color: transparent;
border-radius: 5px;
}
/* 自定义滑块的样式 */
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 100px;
background-color: #fe3355;
cursor: pointer;
border: 2px solid #fff;
box-sizing: border-box;
}
.schedule {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
</style>
</head>
<body>
<div class="conts">
<div class="imgs">
<img id="top_img" src="" alt="" />
</div>
<div class="btns">
<div class="button">
<span>选择视频</span>
<input type="file" id="video-file" accept="video/*" />
</div>
</div>
<div class="imgs_list">
<div class="imgs_list_box"></div>
<div class="schedule">
<input id="media" type="range" min="0" max="100" value="0" />
</div>
</div>
</div>
<script>
const ranges = document.querySelector("#media");
let video_file = null;
document
.querySelector("#video-file")
.addEventListener("change", async function () {
const file = this.files[0];
video_file = file;
let reader = new FileReader();
//获取视频时长
reader.onload = function (e) {
let video = document.createElement("video");
video.src = e.target.result;
video.addEventListener("loadedmetadata", function () {
let duration = Math.floor(video.duration); //取整
ranges.max = duration;
ranges.value = 0;
var count = 7; // 总共取出的数的数量
var step = Math.floor(duration / (count - 1)); // 步长
var result = []; // 存储结果的数组
for (var i = 0; i < count; i++) {
result.push(i * step);
}
drawCover(0); //先渲染一下封面
// 生成7张图片并渲染上去
document.querySelector(".imgs_list_box").innerHTML = "";
result.forEach(async (item) => {
const res = await captureFrame(video_file, item);
let el = document.createElement("div");
el.setAttribute("class", "img_item");
el.innerHTML = ` <img src="${res.url}" />`;
document.querySelector(".imgs_list_box").appendChild(el);
});
});
};
reader.readAsDataURL(file);
});
//控件移动触发
const debouncedHandleInput = debounce(moveChang, 200);
ranges.addEventListener("input", debouncedHandleInput);
// 滑块选取封面
function moveChang() {
drawCover(this.value);
}
//渲染顶部封面
async function drawCover(time) {
const res = await captureFrame(video_file, time);
document.querySelector("#top_img").setAttribute("src", res.url);
}
// 防抖函数
function debounce(fun, time) {
let timer;
return function (...val) {
clearTimeout(timer);
timer = setTimeout(() => {
fun.apply(this, val);
}, time);
};
}
// 获取视频帧的封面
function captureFrame(videoFile, time = 0) {
return new Promise((succeed) => {
const video = document.createElement("video");
video.currentTime = time;
video.muted = true;
video.autoplay = true;
video.oncanplay = async () => {
const res = await drawVideo(video);
succeed(res);
};
video.src = URL.createObjectURL(videoFile);
});
}
// 画视频
function drawVideo(video) {
return new Promise((res) => {
const cvs = document.createElement("canvas");
const ctx = cvs.getContext("2d");
cvs.width = video.videoWidth;
cvs.height = video.videoHeight;
ctx.drawImage(video, 0, 0, cvs.width, cvs.height);
// document.body.appendChild(cvs);
cvs.toBlob((blob) => {
res({
blob,
url: URL.createObjectURL(blob),
});
});
});
}
</script>
</body>
</html>