当前位置:网站首页>H5 native player [learn video]
H5 native player [learn video]
2022-06-25 05:05:00 【I am Feng Feng Yi】
This is a pure native H5 player , Although there are many third-party libraries on the Internet , But the foundation is solid , It will help you go further .
Big factories also attach great importance to the foundation , Besides, those third-party libraries are also built on the basis of little by little , So students who are interested in learning can download it to learn .
I have commented on all the details in the code .
You are also very welcome to expand , Interested in expanding functions , You can start another branch , Better write a document , Explain what features have been added .
This is the use of H5 Of video A video player made of tags
Just for learning , So there may be problems with the existing functions , Of course, the function is certainly incomplete .
But as learning H5 Of video, It should be possible .
index.htmlI started writing the code for the player
coreIt's the back folder where I separate the code .
The written functions are
- Play and pause
- Progress bar animation , Progress bar drag
- Playing time
- Volume control
- Multiple play
- Full screen
Of course, this is not the case OK 了 , You can add to the existing ones , On the one hand, it can exercise your thinking , On the other hand, you can hone your code reading ability .
The functions I think of
- When playing , When the mouse hovers too long or moves out of the player for a period of time , The controller should disappear .
- Web full screen
- Clarity adjustment
- Click the progress bar to jump
- bullet chat
- Keyboard events , Use the keyboard to adjust the progress and volume
effect 
If you don't want to download the file , You can see the core code
Core code
// Incoming video resource path , Return to one videoWrapperDOM
function createVideo({
videoUrl,
width,
height,
dragSvg = ""
}) {
const videoWrapperDOM = initWrapperDOM(width, height);
const video = document.createElement('video');
video.classList.add("own-video")
video.src = videoUrl;
videoWrapperDOM.appendChild(video);
function initWrapperDOM(width, height) {
// Initialize the outer layer DOM
const videoWrapperDOM = document.createElement("div");
videoWrapperDOM.classList.add("own-video-wrapper")
videoWrapperDOM.style.width = width + "px";
videoWrapperDOM.style.height = height + "px";
return videoWrapperDOM;
}
let timeFrameId = null; // Play time to show the animation
const videoControl = {
paused: true,// that video The one you brought is not easy to use
videoDOM: null,
play(playBtn) {
this.videoDOM.play();
updateTime();
playBtn.classList.remove("pause");
playBtn.classList.add("play");
this.paused = false;
},
pause(playBtn) {
this.videoDOM.pause();
cancelAnimationFrame(timeFrameId);
playBtn.classList.remove("play");
playBtn.classList.add("pause");
this.paused = true;
},
setVolume(v) {
v = v < 0 ? 0 : v;
this.videoDOM.volume = v;
},
w: 960, // The initial size of the player
h: 540,
setVideoDOM(video, w, h) {
// It seems strange
// This should be divided into a module , Then privatize , Methods of external exposure , But I didn't do that as an exercise
this.videoDOM = video;
this.w = w;
this.h = h;
this.setVolume(.5);
},
setFullScreen(isFullScreen) {
if (isFullScreen) {
this.videoDOM.parentNode.classList.add("video-full-screen");
} else {
this.videoDOM.parentNode.classList.remove("video-full-screen");
}
}
}
videoControl.setVideoDOM(video, width, height);
let playBtn = document.createElement("div");
function createPlayBtn(video) {
// Play button
playBtn.classList.add("btn", "play-btn", "pause");
playBtn.addEventListener("click", function () {
if (videoControl.paused) {
// Video status pauses playing
console.log("paused");
videoControl.play(this);
} else {
console.log("play");
videoControl.pause(this);
}
})
return playBtn;
}
const current = document.createElement("span"); // Current playback time
const total = document.createElement("span"); // Total time
function updateTime() {
const totalTime = parseTime(video.duration);
const currentTime = parseTime(video.currentTime);
current.innerText = currentTime;
total.innerText = totalTime;
timeFrameId = requestAnimationFrame(updateTime);
}
function createTimeDisplay(video) {
// 01:00 / 5:20
const timeDisplayWrapper = document.createElement("div");
timeDisplayWrapper.classList.add("time-wrapper")
timeDisplayWrapper.appendChild(current);
timeDisplayWrapper.appendChild(total);
video.addEventListener("canplaythrough", function () {
// After the video loading is completed, update the latest playback time
const totalTime = parseTime(video.duration);
const currentTime = parseTime(video.currentTime);
current.innerText = currentTime;
total.innerText = totalTime;
})
return timeDisplayWrapper
}
function exitFullscreen() {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
}
}
function createFullScreen() {
const fullScreenWrapper = document.createElement("div");
fullScreenWrapper.classList.add("full-screen-wrapper");
const arr = [" Full screen ", " Small screen "];
fullScreenWrapper.innerText = arr[0];
let status = "normal"; // A state of the browser full normal
document.addEventListener("fullscreenchange", function () {
console.log(document.fullscreenElement);
if (document.fullscreenElement !== null) {
// Enter full screen mode
status = "full";
} else {
status = 'normal';
exitFullscreen();
videoControl.setFullScreen(false);
fullScreenWrapper.innerText = arr[0];
}
});
fullScreenWrapper.addEventListener("click", function () {
if (status === 'normal') {
document.documentElement.requestFullscreen();
videoControl.setFullScreen(true);
this.innerText = arr[1];
}
if (status === 'full') {
exitFullscreen();
videoControl.setFullScreen(false);
this.innerText = arr[0];
}
})
return fullScreenWrapper;
}
function createVolumeWrapper(video) {
const volumeWrapper = document.createElement('div');
const volumeIco = document.createElement("div");
const volumeBarWrapper = document.createElement('div');
volumeWrapper.classList.add("volume-wrapper");
volumeIco.classList.add("volume-ico");
volumeBarWrapper.classList.add("volume-bar-wrapper");
const bgBar = document.createElement("div");
bgBar.classList.add("volume-bg-bar");
const innerBar = document.createElement("div");
innerBar.classList.add("volume-inner-bar");
const circle = document.createElement("span");
circle.classList.add("volume-circle");
volumeBarWrapper.appendChild(bgBar);
bgBar.appendChild(innerBar);
bgBar.appendChild(circle);
volumeWrapper.appendChild(volumeIco);
volumeWrapper.appendChild(volumeBarWrapper);
let clicked = false;
let clientY, clickY;
let barHeight = 0;
circle.addEventListener("mousedown", function (e) {
barHeight = bgBar.clientHeight; // Maximum drag range
// In parent element display:none, Inaccurate dimensions
clicked = true; // Delegates can drag and drop
clickY = e.pageY
clientY = innerBar.clientHeight;
})
volumeWrapper.addEventListener("mousemove", function (e) {
if (!clicked) {
return; // Click to drag
}
const moveY = clickY - e.pageY; // This formula should pay attention to
// Because compared with the progress bar dragging, it is a one-way animation , Just calculate the current volume level
let h = clientY + moveY;
h = h < 0 ? 0 : h; // Boundary treatment
h = h > barHeight ? barHeight : h;
innerBar.style.height = h + "px";
circle.style.bottom = h + "px";
const v = h / barHeight; // The volume
// For readability , I try not to write on one line , This is a person's professional quality
videoControl.setVolume(v);
})
const stopDragVolumeBar = function () {
if (clicked) {
// It's dragging
clicked = false; // Cancel the drag status
}
}
document.addEventListener("mouseup", stopDragVolumeBar)
volumeWrapper.addEventListener("mouseleave", stopDragVolumeBar);
return volumeWrapper;
}
function createDragBar(video, dragSvg) {
// Play progress bar
const barWrapper = document.createElement("div");
barWrapper.classList.add("bar-wrapper");
const innerBar = document.createElement("div");
innerBar.classList.add("inner-bar");
barWrapper.appendChild(innerBar);
const circle = document.createElement("span");
circle.classList.add("circle");
if (dragSvg) {
// Customize svg Drag and drop the icon
circle.innerHTML = dragSvg;
circle.classList.add("svg-circle")
} else {
circle.classList.add("normal");
}
window.circle = circle;
barWrapper.appendChild(circle);
let frameId = null; // You need to cancel the animation when dragging
// Drag and drop functionality
// I need to know the total length of the progress bar
// You also need to know the drag distance
// Drag distance / Total progress bar length = currentTime / totalTime
let totalWidth = 0;
let totalTime = 0;
video.addEventListener("canplaythrough", function () {
// Loading of video resources is completed
totalTime = this.duration;
let clicked = false;
let clientX, clickX;
circle.addEventListener("mousedown", function (e) {
// If the element attribute is obtained from the beginning , Then the full screen zoom will appear BUG
totalWidth = barWrapper.offsetWidth; // To accommodate the latest size of the element
// Pause play
// Remember the position at the moment of clicking
cancelAnimationFrame(frameId); // Cancel animation playback Optimize performance to reduce unnecessary trouble
// Otherwise you can't control the elements
videoControl.pause(playBtn);
clientX = this.offsetLeft;
clickX = e.pageX;
clicked = true; // Enter the drag state
})
document.addEventListener("mousemove", function (e) {
if (!clicked) {
return; // Non drag status
}
cancelAnimationFrame(frameId);
let moveX = e.pageX - clickX;
let per = (clientX + moveX) / totalWidth;
per = per < 0 ? 0 : per; // Do boundary treatment
per = per > 1 ? 1 : per;
per = per * 100 + "%";
circle.style.left = per;
innerBar.style.width = per;
})
document.addEventListener("mouseup", function (e) {
if (clicked) {
clicked = false;
let moveX = e.pageX - clickX;
let per = (clientX + moveX) / totalWidth;
video.currentTime = getCurrentTime(video, per);
per = per > 1 ? 1 : per;
per = per < 0 ? 0 : per;
per = per * 100 + "%";
circle.style.left = per;
innerBar.style.width = per;
videoControl.play(playBtn);
barAnimate();
}
})
})
function barAnimate() {
const per = getPercentage(video) * 100 + "%";
circle.style.left = per;
innerBar.style.width = per;
frameId = requestAnimationFrame(barAnimate);
}
barAnimate();
return barWrapper;
}
function createPlayRate(video) {
// Speed up
const rateWrapper = document.createElement("div");
rateWrapper.classList.add("rate-wrapper");
const currentRateWrapper = document.createElement('div');
currentRateWrapper.innerText = "1X";
const ul = document.createElement("ul");
ul.classList.add("rateSelectorWrapper");
ul.innerHTML = ` <li>2X</li> <li>1.5X</li> <li>1X</li> <li>.5X</li> `
ul.addEventListener("click", function (e) {
if (e.target.tagName === "LI") {
currentRateWrapper.innerText = e.target.innerText;
const rate = parseFloat(e.target.innerText);
video.playbackRate = rate;
}
})
rateWrapper.appendChild(currentRateWrapper);
rateWrapper.appendChild(ul);
return rateWrapper;
}
function initBar() {
const bar = document.createElement("div");
bar.classList.add("own-video-control-bar");
return bar;
}
const bar = initBar();
const timeDisplayWrapper = createTimeDisplay(video);
const dragBar = createDragBar(video, dragSvg);
const rateWrapper = createPlayRate(video);
// In order to gather the buttons on the right , I think it would look better
const container = document.createElement("div");
container.classList.add("video-btn-container");
container.appendChild(rateWrapper);
container.appendChild(createVolumeWrapper(video));
container.appendChild(createFullScreen());
bar.appendChild(createPlayBtn(video));
bar.appendChild(timeDisplayWrapper);
bar.appendChild(dragBar);
bar.appendChild(container);
videoWrapperDOM.appendChild(bar);
return videoWrapperDOM;
}
边栏推荐
- Introduction to the hardest core PWN in the whole network_ Graphic analysis
- Compatible with Internet Explorer
- Laravel's little knowledge
- 固态硬盘开盘数据恢复的方法
- There is 404 in the laravel visit, except the home page is redirected; Index php
- Summary of SQL injection (I)
- At the age of 30, I began to learn programming by myself. Is it still time for me to have difficulties at home?
- Page electronic clock (use js to dynamically obtain time display)
- DMA double buffer mode of stm32
- Kotlin compose perfect todo project surface rendering background and shadow
猜你喜欢

buuctf(pwn)

In depth understanding of line height and vertical align

How do the defi protocols perform under this round of stress test?

电脑的dwg文件怎么打开

Difference between asemi high power FET and triode

Student achievement management system based on SSH

Penetration test - directory traversal vulnerability

IronOCR 2022.1 Crack

2021-03-23

What if win11 Bluetooth fails to connect? Solution of win11 Bluetooth unable to connect
随机推荐
OOP vector addition and subtraction (friend + copy construction)
Mysql interactive_ Timeout and wait_ Timeout differences
In depth understanding of line height and vertical align
Click to jump out and drag the pop-up window
How to install the blue lake plug-in to support Photoshop CC 2017
How to download and use Xiaobai one click reload on the official website
【FLink】access closed classloader classloader. check-leaked-classloader
Native JS high risk reminder pop-up code snippet, "are you sure you want to do this?" and "it cannot be recovered after deletion. Do you want to continue“
固態硬盤開盤數據恢複的方法
Five simple data types of JS
Google Earth Engine(GEE)——全球JRC/GSW1_1/YearlyHistory数据集的批量下载(中国区域)
绝了!自动点赞,我用 PyAutoGUI!
How micro engine uploads remote attachments
A brief talk on media inquiry
Opensea PHP development kit
Huawei Hongmeng development lesson 4
2021-03-23
TeeChart Pro ActiveX 2022.1
CTFHub-rce
February 19 CTF exercise