原生js实现简单的视频播放控件

这篇具有很好参考价值的文章主要介绍了原生js实现简单的视频播放控件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

HTML 5 视频/音频参考手册https://www.w3school.com.cn/html5/html5_ref_audio_video_dom.asp本文主要依靠HTML 5 api ,所有用的HTML 5 api 的使用和各项信息请参考以上链接!

如果你打算参考本文,这里所用的视频什么的请自行准备。这里仅建议初学者参考。

因为主要依靠HTML 5的api,所有也没什么好说的,关于api的使用方法在上面的链接里讲的已经非常清楚了(视频相关事件在上面的链接里有讲)

进度条什么的主要用到mousedown、mousemove和mouseup事件,offsetWidth、offsetLeft等属性,HTML结构就是几个块级元素嵌套在一起。

下载功能的话,这里是通过创建a元素并设置download属性,然后触发a元素进行下载。

效果图

原生js实现简单的视频播放控件

视频封面图片:编写者播放器.jpeg(bianxiezhe.com里面没有播放器,仅为美观而添加bianxiezhe.com字样)

原生js实现简单的视频播放控件

 css文件:player.css

* {
	margin: 0px;
	padding: 0px;
}

body {
	width: 100vw;
	height: 100vh;
	color: #555555;
	display: flex;/* 弹性布局 */
	align-items: center;/* 垂直居中 */
	justify-content: center;/* 水平居中 */
	background-color: #333333;
}

main {
	min-width: 900px;
	/* 溢出裁剪 */
	overflow: hidden;
}

.main {
	width: 900px;
	height: 507px;
	position: relative;
	border: 2px solid rgb(29, 29, 29);
}

.mainPro {
	width: 100vw;
	height: 100vh;
	position: fixed;
}

.Loading {
	width: 100%;
	height: 100%;
	position: absolute;
	text-align: center;
	line-height: 506px;
	font-size: 56px;
	font-weight: bold;
	background-color: rgb(169, 169, 169);
}

video {
	width: 100%;
	height: 100%;
}

.control {
	width: 100%;
	height: 43px;
	padding-top: 6px;
	background-color: rgba(29, 29, 29, 0.95);
	position: absolute;
	top: calc(100% - 49px);
}

.controlPro,
.controlHover {
	width: 100%;
	height: 43px;
	padding-top: 6px;
	background-color: rgba(29, 29, 29, 0.95);
	position: absolute;
	/* 设置动画时间 */
	transition: 0.3s;
	top: 100%;
}

main:hover .controlHover {
	top: calc(100% - 49px);
}

.LoadingBarDiv {
	width: calc(100% + 7.5px);
	height: 12px;
	display: flex;
	align-items: center;
	position: relative;
	background-color: rgb(169, 169, 169);
}

.obtain {
	height: 100%;
	width: 0px;
	/* 设置穿透节点 */
	pointer-events: none;
	/* 设置动画时间 */
	transition: width 0.5s;
	position: absolute;
	background-color: rgb(219, 219, 219);
}

.LoadingBar {
	width: 0px;
	max-width: 100%;
	/* 设置穿透节点 */
	pointer-events: none;
	height: 12px;
	background-color: rgb(99, 99, 99);
}

.spot {
	width: 15px;
	height: 15px;
	/* 设置渐变背景 */
	background-image: linear-gradient(to right, rgb(169, 169, 169), rgb(99, 99, 99));
	margin-left: -7.5px;
	border-radius: 50%;
	display: none;
}

.spotPro {
	width: 15px;
	height: 15px;
	background-image: linear-gradient(to right, rgb(169, 169, 169), rgb(99, 99, 99));
	margin-left: -7.5px;
	border-radius: 50%;
}

.LoadingBar,
.spot,
.spotPro {
	position: relative;
	z-index: 1;
}

.LoadingBarDiv:hover .spot {
	display: block;
}

.time {
	width: 56px;
	height: 24px;
	position: absolute;
	margin-top: -44px;
	background-color: rgb(169, 169, 169);
	color: rgb(32, 32, 32);
	border-bottom: 2px solid rgb(32, 32, 32);
	text-align: center;
	font-weight: bold;
	line-height: 24px;
	display: none;
}

.timePro {
	width: 56px;
	height: 24px;
	position: absolute;
	margin-top: -44px;
	background-color: rgb(169, 169, 169);
	color: rgb(32, 32, 32);
	border-bottom: 2px solid rgb(32, 32, 32);
	text-align: center;
	font-weight: bold;
	line-height: 24px;
}

.LoadingBarDiv:hover~.time {
	display: block;
}

.ul {
	height: 24px;
	width: 406px;
	margin: 3px;
}

.ul>li {
	background-color: rgb(169, 169, 169);
	color: rgb(32, 32, 32);
	float: left;
	list-style-type: none;
	height: 100%;
	width: 24px;
	font-weight: bold;
	line-height: 24px;
	text-align: center;
	cursor: default;
	user-select: none;
}

.ul>li+li {
	margin-left: 4px;
}

.ul>li:hover {
	background-color: rgb(219, 219, 219);
}

#timeTextId {
	width: 108px;
}

#speedId {
	width: 70px;
}

#timeTextId,
#speedId,
#volumeId {
	background-color: rgb(169, 169, 169);
}

.SpeedOption {
	width: 70px;
	height: 24px;
	position: absolute;
	margin-top: -149px;
	display: none;
	z-index: 1;
}

#speedId:hover .SpeedOption {
	display: block;
}

.SpeedOption>li {
	width: 100%;
	height: 100%;
	background-color: rgb(169, 169, 169);
	list-style-type: none;
	text-align: center;
	font-weight: bold;
	border-bottom: 1px solid rgb(32, 32, 32);
}

.SpeedOption>li:hover {
	background-color: rgb(219, 219, 219);
}

.volumeTwo {
	width: 6px;
	height: 126px;
	padding: 12px 9px;
	background-color: rgb(169, 169, 169);
	border-bottom: 1px solid rgb(32, 32, 32);
	top: -130px;
	position: absolute;
	display: none;
	z-index: 1;
}

.volumeTwoPro {
	width: 6px;
	height: 126px;
	padding: 12px 9px;
	background-color: rgb(169, 169, 169);
	border-bottom: 1px solid rgb(32, 32, 32);
	top: -130px;
	position: absolute;
	z-index: 1;
}

.volume:hover .volumeTwo {
	display: block;
}

.volumeTwoPro>.volumeThree,
.volumeTwo>.volumeThree {
	width: 6px;
	height: 130px;
	background-color: rgb(32, 32, 32);
	position: absolute;
}

.volumeThree>.VolumeValue {
	width: 6px;
	height: 0px;
	background-color: #dddddd;
}

.volumeThree>.VolumeSpot {
	width: 12px;
	height: 12px;
	margin-top: -4.5px;
	margin-left: -2.5px;
	border-radius: 50%;
	background-image: radial-gradient(#dddddd, rgb(32, 32, 32));
}

.VolumeText {
	width: 100px;
	height: 24px;
	line-height: 23px;
	margin-left: 15px;
	margin-top: -9px;
	position: absolute;
	background-color: rgb(169, 169, 169);
	border-left: 1px solid rgb(32, 32, 32);
	text-align: center;
	font-weight: bold;
}

input {
	width: 100%;
	height: 100%;
	border: none;
	border-radius: 0px;
	display: none;
}

label {
	width: 100%;
	height: 100%;
	display: block;
	line-height: 24px;
	text-align: center;
	font-weight: bold;
}

.proposalORreport {
	width: 100px;
	height: 24px;
	line-height: 23px;
	border-radius: 3px;
	position: absolute;
	color: #dddddd;
	top: 0px;
	background-color: rgb(29, 29, 29);
	text-align: center;
	font-weight: bold;
	display: none;
	cursor: default;
	user-select: none;
}

html文件:player.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<link rel="stylesheet" href="icomoon/demo-files/demo.css">
		<link rel="stylesheet" href="icomoon/style.css">
		<link rel="stylesheet" href="./css/player.css">
		<title>播放器</title>
	</head>
	<body>
		<main class="main">
			<div class="Loading" id="LoadingId">加载中</div>
			<video src="#" id="media" poster="编写者播放器.jpeg" data-custom></video>
			<div class="control" id="controlId">
				<div class="LoadingBarDiv" id="LoadingBarDivId">
					<div class="obtain" id="obtainId"></div>
					<div class="LoadingBar"></div>
					<div class="spot"></div>
				</div>
				<div class="time" id="timeId">00:00</div>
				<ul class="ul" id="ulId">
					<li class="icon-stop2 Reset" id="ResetId"></li>
					<li class="icon-play3 playORsuspend" id="playORsuspendId"></li>
					<li class="icon-last next" id="nextId"></li>
					<li class="timeText" id="timeTextId">00:00/00:00</li>
					<li class="speed" id="speedId">
						<span id="SpeedValueId">1.00倍</span>
						<ul class="SpeedOption">
							<li>0.50倍</li>
							<li>0.75倍</li>
							<li>1.00倍</li>
							<li>1.25倍</li>
							<li>1.50倍</li>
						</ul>
					</li>
					<li class="icon-volume-high volume" id="volumeId" data-custom>
						<div class="volumeTwo" id="volumeTwoId">
							<div class="volumeThree" id="volumeThreeId">
								<div class="VolumeValue" id="VolumeValueId"></div>
								<div class="VolumeSpot" id="VolumeSpotId"></div>
							</div>
							<div class="VolumeText" id="VolumeTextId">音量:100%</div>
						</div>
					</li>
					<li class="icon-box-add download" id="downloadId"></li>
					<li class="icon-enlarge2 WebFullScreen" id="WebFullScreenId" data-custom></li>
					<li class="icon-enlarge FullScreen" id="FullScreenId" data-custom></li>
					<li class="dropORstay" id="dropORstayId">
						<label for="choice">降</label>
						<input type="checkbox" id="choice" />
					</li>
				</ul>
			</div>
			<div class="proposalORreport" id="proposalORreportId">建议或举报</div>
		</main>
		<script src="./javascript/player.js"></script>
	</body>
</html>

js文件:player.js文章来源地址https://www.toymoban.com/news/detail-433078.html

(function() {
	//获取所需操作节点,这里用到的变量名均与id名、标签名、类名其中一个相同
	const LoadingId = document.getElementById("LoadingId"),
		controlId = document.getElementById("controlId"),
		LoadingBarDivId = document.getElementById("LoadingBarDivId"),
		obtainId = document.getElementById("obtainId"),
		timeId = document.getElementById("timeId"),
		ResetId = document.getElementById("ResetId"),
		playORsuspendId = document.getElementById("playORsuspendId"),
		volumeId = document.getElementById("volumeId"),
		nextId = document.getElementById("nextId"),
		timeTextId = document.getElementById("timeTextId"),
		SpeedValueId = document.getElementById("SpeedValueId"),
		VolumeValueId = document.getElementById("VolumeValueId"),
		VolumeSpotId = document.getElementById("VolumeSpotId"),
		VolumeTextId = document.getElementById("VolumeTextId"),
		downloadId = document.getElementById("downloadId"),
		WebFullScreenId = document.getElementById("WebFullScreenId"),
		FullScreenId = document.getElementById("FullScreenId"),
		proposalORreportId = document.getElementById("proposalORreportId"),
		input = document.getElementById('choice'),
		volumeTwoId = document.getElementById('volumeTwoId'),
		body = document.querySelector("body"),
		main = document.querySelector('main'),
		video = document.querySelector('video'),
		LoadingBar = document.querySelector('.LoadingBar'),
		SpeedOption = document.querySelector('.SpeedOption'),
		spot = document.querySelector('.spot'),
		label = document.querySelector('label');

	// 播放名单
	const VideoUrl = {
		media1: '10-12-1.mp4',
		media2: '10-12-3.mp4',
		media3: 'trailer_test.mp4',
		media4: '配乐音量.mp4'
	}
	// 设置video节点的src值,这里采用协议、域名(ip)、端口自适应
	video.src = './Video/' + VideoUrl['media' + Math.floor(Math.random() * (5 - 1) + 1)];

	function enhanceVideoSeek() {
		let minute = 0,
			second = 0,
			VideoMinute = 0,
			VideoSecond = 0;
		// toFixed(1)会四舍五入,parseInt不会
		// 已播放的分钟
		minute = parseInt(video.currentTime % 3600 / 60);
		// 三目运算:小于10则在前面添加0
		minute = minute < 10 ? '0' + minute : minute;
		// 已播放的秒钟
		second = parseInt(video.currentTime % 3600 % 60);
		// 三目运算:小于10则在前面添加0
		second = second < 10 ? '0' + second : second;
		// 总时长的分钟
		VideoMinute = parseInt(video.duration % 3600 / 60);
		// 三目运算:小于10则在前面添加0
		VideoMinute = VideoMinute < 10 ? '0' + VideoMinute : VideoMinute;
		// 总时长的秒钟
		VideoSecond = parseInt(video.duration % 3600 % 60);
		// 三目运算:小于10则在前面添加0
		VideoSecond = VideoSecond < 10 ? '0' + VideoSecond : VideoSecond;
		// 设置对应节点的文本节点
		timeTextId.innerText = minute + ":" + second + "/" + VideoMinute + ":" + VideoSecond;
	}

	// 遍历“倍速”节点,给它的所有字节的设置单击事件
	for (let itme of SpeedOption.children) {
		itme.addEventListener('click', function() {
			// 获取itme文本后截取数字部分转为浮点型并设置视频播放速率
			video.playbackRate = parseFloat(itme.innerText.substring(0, 4));
			// 设置对应节点的文本节点
			SpeedValueId.innerText = itme.innerText;
		});
	}

	function setClassName(ele, removeClass, addClas) {
		// 删除类名
		ele.classList.remove(removeClass);
		// 添加类名
		ele.classList.add(addClas);
	}

	function playPause() {
		// 捕获异常
		try {
			// 如果处于暂停状态则播放,否则暂停
			if (video.paused) {
				video.play(); //播放
				// 设置自定义属性,方便后续操作
				video.setAttribute('data-custom', 'play');
				// 设置“暂停/播放”按键的class属性值,变更其文字图案表现
				// 调用setClassName方法
				setClassName(playORsuspendId, 'icon-play3', 'icon-pause2');
			} else {
				video.pause(); //暂停
				// 设置自定义属性,方便后续操作
				video.setAttribute('data-custom', 'pause');
				// 设置“暂停/播放”按键的class属性值,变更其文字图案表现
				// 调用setClassName方法
				setClassName(playORsuspendId, 'icon-pause2', 'icon-play3');
			}
		} catch (e) {
			console.log('%c出错啦!暂停/播放状态请勿切换过快!!!',
				'background-color:#be191c;color:#f3f3f3;border-radius: 1px;padding:2px 8px;text-align: center;font-weight: bold;'
			);
		}
	}

	function timeFun(e) {
		let minute = 0,
			second = 0;
		// toFixed(1)会四舍五入,parseInt不会
		// 鼠标所指之处的分钟
		minute = parseInt(((e.clientX - main.offsetLeft) / (LoadingBarDivId.offsetWidth - spot.offsetWidth / 2)) *
			video.duration % 3600 / 60);
		// 三目运算:小于10则在前面添加0
		minute = minute < 10 ? '0' + minute : minute;
		// 鼠标所指之处的秒钟
		second = parseInt(((e.clientX - main.offsetLeft) / (LoadingBarDivId.offsetWidth - spot.offsetWidth / 2)) *
			video.duration % 3600 % 60);
		// 三目运算:小于10则在前面添加0
		second = second < 10 ? '0' + second : second;
		// 设置对应节点的文本节点
		timeId.innerText = minute + ":" + second;
		// 计算id名为timeId的节点应该具有的左边距的距离
		let marginLeft = ((e.clientX - main.offsetLeft) - (timeId.offsetWidth / 2));
		if (marginLeft < 0) { // 判断marginLeft的值是否小于0
			// 设置id名为timeId的节点的左边距
			timeId.style.marginLeft = '0px';
		} else if (marginLeft > ((LoadingBarDivId.offsetWidth - spot.offsetWidth / 2) - timeId
				.offsetWidth)) { // 判断marginLeft的值加上id名为timeId的节点的宽度是否大于于进度条容器的宽度
			// 设置id名为timeId的节点的左边距
			timeId.style.marginLeft = (LoadingBarDivId.offsetWidth - spot.offsetWidth / 2) - timeId
				.offsetWidth + 'px';
		} else {
			// 设置id名为timeId的节点的左边距
			timeId.style.marginLeft = marginLeft + 'px';
		}
	}

	function show_coords(e, parameter) {
		// 判断进度条宽度是否超过其容器的宽度
		if (parameter <= controlId.offsetWidth && parameter >= 0) {
			// 设置进度条宽度
			LoadingBar.style.width = parameter + 'px';
			if (e) {
				// 调用timeFun方法
				timeFun(e);
			}
			// 计算进度条宽度与其容器宽度的比例
			let percent = LoadingBar.offsetWidth / (LoadingBarDivId.offsetWidth - spot.offsetWidth / 2);
			// 设置视频播放时间(即播放到哪里了)
			video.currentTime = percent * video.duration;
		}
	}

	function LoadingBarWidthFun(e) {
		// 被单击的如果是进度条上的圆点,则结束这个方法;否则调用show_coords方法
		if (e.target.className === "spot" || e.target.className === "spotPro") return null;
		show_coords(null, e.offsetX);
	};

	// 加载完视频“元数据”后触发loadedmetadata事件
	video.addEventListener("loadedmetadata", function() {
		LoadingBar.style.width = '0px';
		// 调用enhanceVideoSeek方法
		enhanceVideoSeek();
		// 双击video节点时触发事件
		video.addEventListener("dblclick", function() {
			// 调用playPause方法
			playPause();
		});
		// 键盘按下某一个键时触发事件
		document.addEventListener("keydown", function(e) {
			// 如果按下的是空格键
			if (e.keyCode === 32) {
				// 调用playPause方法
				playPause();
			}
		});

		// 隐藏“加载中”提示节点
		LoadingId.style.display = 'none';

		// 单击id名为ResetId的节点时触发事件
		ResetId.addEventListener("click", function() {
			// 设置(归零)视频播放时间(即播放到哪里了)
			video.currentTime = 0;
			obtainId.style.width='0px';
		});

		// 单击id名为playORsuspendId的节点时触发事件
		playORsuspendId.addEventListener("click", playPause);

		// 单击id名为LoadingBarDivId的节点时触发事件
		LoadingBarDivId.addEventListener("click", LoadingBarWidthFun);

		// 单击id名为downloadId的节点时触发事件
		downloadId.addEventListener('click', function() {
			// 通过协议判断是不是只是打开了html文件,而不是在网站上打开页面
			if (!window.location.protocol || window.location.protocol === 'file:') { // 如果是
				return alert('你的文件为本地文件,不能下载');
			} else { // 如果不是
				// 创建a节点
				let a = document.createElement("a"),
					// 获取视频文件名“.”前面的部分
					FileName = window.decodeURIComponent(video.src.substring(video.src.lastIndexOf(
						"/") + 1, video.src.lastIndexOf(".")));
				// 将video节点的src属性值赋值给a节点的href属性
				a.href = video.src;
				// 设置a节点的download属性,该属性值就是下载到本地时的文件名,该属性仅在网站上可用
				a.download = FileName + new Date().getTime() + a.href.substr(a.href.lastIndexOf(
					"."));
				// 添加节点到body节点
				body.appendChild(a);
				// 设置定时器,定时(0.1秒后)删除a节点
				let aSet = setTimeout(function() {
					// 删除a节点
					body.removeChild(a);
					// 移除定时器
					clearTimeout(aSet);
				}, 100);
				// 触发a节点的单击事件
				a.click();
			}
		});

		// 进度条圆点按下时
		spot.addEventListener('mousedown', function(e) {
			video.pause(); // 暂停播放

			// 修改相应节点类名,达到样式需求效果
			spot.className = "spotPro";
			timeId.className = "timePro";

			// 计算鼠标按下时,鼠标相对于进度条圆点的位置,以免抖动
			let xPro = (e.clientX - main.offsetLeft) - (spot.offsetLeft + spot.offsetWidth / 2);

			// 鼠标移动时触发
			document.onmousemove = function(e) {
				// 移除进度条容器的单击事件
				LoadingBarDivId.removeEventListener("click", LoadingBarWidthFun);

				// 计算进度条长度
				let x = (e.clientX - main.offsetLeft) - xPro;
				// 调用show_coords方法
				show_coords(e, x);

				// 鼠标按下开始拖动,时触发事件;没啥用,只是样式需要而已
				document.ondragstart = function(ev) {
					// 阻止默认事件
					ev.preventDefault();
				};

				// 鼠标结束拖动并松开,时触发事件;没啥用,只是样式需要而已
				document.ondragend = function(ev) {
					// 阻止默认事件
					ev.preventDefault();
				};
			}

			// 鼠标松开时触发事件
			document.onmouseup = function(e) {
				// 移除相应事件
				document.onmousemove = null;
				document.onmouseup = null;
				// 给进度条容器绑定单击事件
				LoadingBarDivId.addEventListener("click", LoadingBarWidthFun);
				// 修改相应节点类名,达到样式需求效果
				spot.className = "spot";
				timeId.className = "time";
				// 通过自定义属性判断拖动进度条前的播放状态,决定播放还是暂停
				if (video.getAttribute('data-custom') === "play") {
					video.play(); //播放
				} else if (video.getAttribute('data-custom') === "pause") {
					video.pause(); //暂停
				}
			};
		});

		// 鼠标进入在进度条时触发事件
		LoadingBarDivId.addEventListener('mousemove', function(e) {
			// 如果节点的id名为不为timeId
			if (e.target.id != 'timeId') {
				// 调用timeFun方法
				timeFun(e);
			}
		});
	});

	// 视频播放时间变化时触发事件
	video.addEventListener("timeupdate", function(e) {
		// 计算已播放时间和总时长的比例
		let ratio = video.currentTime / video.duration;
		// 计算并设置进度条长度
		LoadingBar.style.width = (LoadingBarDivId.offsetWidth - 7.5) * ratio + 'px';
		// 调用enhanceVideoSeek方法
		enhanceVideoSeek();
		// 判断已缓冲数据长度是否大于零
		if (video.buffered.length > 0) {
			// 计算已缓冲视频提示条长度
			let obtainWidth = (video.buffered.end(video.buffered.length - 1) / video.duration) *
				LoadingBarDivId.offsetWidth;
			// 设置已缓冲视频提示条长度
			obtainId.style.width = obtainWidth + "px";
		}
	});

	// 单击id名为nextId的节点时触发事件
	nextId.addEventListener('click', function() {
		// 获取视频路径,这里采用协议、域名(ip)、端口自适应
		let src = './Video/' + VideoUrl['media' + Math.floor(Math.random() * (5 - 1) + 1)];
		// 获取video节点src属性相对应部分(中文有需要window.decodeURIComponent解码)
		VideoName = window.decodeURIComponent(video.src.substr(video.src.lastIndexOf("/") + 1));
		if (src !== './Video/' + VideoName) { // 如果不同
			try {
				video.removeAttribute('src');
				obtainId.style.width='0px';
				// 设置video节点的src值
				video.src = src;
				// 通过自定义属性判断拖动进度条前的播放状态,决定播放还是暂停
				video.playbackRate = parseFloat(SpeedValueId.innerText.substring(0, 4));
				if (video.getAttribute('data-custom') === "play") {
					video.play(); // 播放
				} else if (video.getAttribute('data-custom') === "pause") {
					video.pause(); // 暂停
				}
			} catch (e) {
				console.log(e)
			}
		} else { // 如果相同
			// 触发id名为nextId的节点的单击事件
			nextId.click();
		}
	});

	// 单击id名为volumeId的节点时触发事件
	volumeId.addEventListener('click', function(e) {
		// 阻止事件冒泡
		e.stopPropagation();
		// 如果节点的id名为为volumeId
		if (e.srcElement.id === 'volumeId') {
			// 如果自定义属性值不存在或为空
			if (!volumeId.getAttribute('data-custom')) {
				// 调用setClassName方法
				setClassName(volumeId, 'icon-volume-high', 'icon-volume-mute2');
				// 设置自定义属性值
				volumeId.setAttribute('data-custom', 'Mute');
				// 设置视频音量为0
				video.volume = 0;
				// 修改音量提示块的文本信息
				VolumeTextId.innerText = '音量:静音';
			} else if (volumeId.getAttribute('data-custom') !== "change") {
				// 调用setClassName方法
				setClassName(volumeId, 'icon-volume-mute2', 'icon-volume-high');
				// 设置自定义属性值
				volumeId.setAttribute('data-custom', '');
				// 计算并设置视频音量
				video.volume = (124 - VolumeValueId.offsetHeight) / 124;
				// 修改音量提示块的文本信息
				VolumeTextId.innerText = '音量:' + ((124 - VolumeValueId.offsetHeight) / 124 * 100)
					.toFixed(0) + '%';
			} else {
				// 设置自定义属性值
				volumeId.setAttribute('data-custom', '');
			}
		}
	});

	function volumeFun(e) {
		// 判断e是否为空,如果为空就设置它
		e = e || document;
		// 计算y的值
		let y = e.clientY - controlId.offsetTop - (VolumeSpotId.offsetHeight / 2);
		// 判断y的值是否符合要求并设置id名为VolumeValueId的节点的高度
		if (y >= 0 && y <= 124) {
			VolumeValueId.style.height = y + 'px';
		} else if (y > 124) {
			VolumeValueId.style.height = '124px';
		} else {
			VolumeValueId.style.height = '0px';
		}
		// 设置id名为VolumeTextId的节点的上边距
		VolumeTextId.style.marginTop = (VolumeValueId.offsetHeight - 9) + 'px';
		// 计算并设置视频音量
		video.volume = (124 - VolumeValueId.offsetHeight) / 124;
		// 判断是否处于静音状态,如果不是
		if (!volumeId.getAttribute('data-custom') || volumeId.getAttribute('data-custom') === "change") {
			// 修改音量提示块的文本信息
			VolumeTextId.innerText = '音量:' + ((124 - VolumeValueId.offsetHeight) / 124 * 100).toFixed(0) + '%';
		}
	}

	// 单击id名为volumeThreeId的节点时触发事件
	volumeThreeId.addEventListener('click', volumeFun);

	// 音量圆点按下时
	VolumeSpotId.addEventListener('mousedown', function(e) {
		// 修改相应节点类名,达到样式需求效果
		volumeTwoId.className = "volumeTwoPro";
		// 鼠标移动时触发
		document.onmousemove = function(e) {
			// 设置自定义属性值
			volumeId.setAttribute('data-custom', 'change');
			// 调用volumeFun方法
			volumeFun(e);
			// 鼠标按下开始拖动,时触发事件;没啥用,只是样式需要而已
			document.ondragstart = function(ev) {
				// 阻止默认事件
				ev.preventDefault();
			};
			// 鼠标结束拖动并松开,时触发事件;没啥用,只是样式需要而已
			document.ondragend = function(ev) {
				// 阻止默认事件
				ev.preventDefault();
			};
		}

		// 鼠标松开时触发事件
		document.onmouseup = function(e) {
			// 修改相应节点类名,达到样式需求效果
			volumeTwoId.className = "volumeTwo";
			// 移除相应事件
			document.onmousemove = null;
			document.onmouseup = null;
			// 如果节点的id名为不为volumeId
			if (e.srcElement.id !== 'volumeId') {
				// 设置自定义属性值
				volumeId.setAttribute('data-custom', '');
			}
		};
	});

	function isFullscreenForNoScroll(e) {
		// 如果节点的id名为为FullScreenId
		if (e.srcElement.id === "FullScreenId") {
			// 如果自定义属性值不存在或为空
			if (!e.srcElement.getAttribute('data-custom')) {
				// 设置main节点全屏
				main.webkitRequestFullscreen();
				// 调用setClassName方法
				setClassName(e.srcElement, 'icon-enlarge', 'icon-shrink');
				// 设置自定义属性值
				e.srcElement.setAttribute('data-custom', 'FullScreenId');
				// 移除main节点的相应事件
				main.onmousemove = null;
				// 给main节点的mousemove事件
				main.onmousemove = function() {
					// 修改鼠标样式
					video.style.cursor = "auto";
					// 判断多选框是否被选中
					if (input.checked === true) { // 被选中
						// 修改相应节点类名,达到样式需求效果
						controlId.className = 'controlHover';
					} else { // 不被选中
						// 修改相应节点类名,达到样式需求效果
						controlId.className = 'control';
					}
					// 设置定时器
					let timer = setTimeout(function() {
						// 如果自定义属性值存在且不为空
						if (FullScreenId.getAttribute('data-custom')) {
							// 判断多选框是否被选中
							if (input.checked === true) { // 被选中
								// 修改相应节点类名,达到样式需求效果
								controlId.className = 'controlPro';
							}
							// 修改鼠标样式
							video.style.cursor = "none";
							// 移除定时器
							clearTimeout(timer);
							timer = null;
						}
					}, 10000);
				}
			} else {
				// 退出全屏
				document.exitFullscreen();
				// 调用setClassName方法
				setClassName(e.srcElement, 'icon-shrink', 'icon-enlarge');
				// 设置自定义属性值
				e.srcElement.setAttribute('data-custom', '');
			}
		} else {
			if (FullScreenId.getAttribute('data-custom')) {
				// 退出全屏
				document.exitFullscreen();
				// 调用setClassName方法
				setClassName(FullScreenId, 'icon-shrink', 'icon-enlarge');
				// 设置自定义属性值
				FullScreenId.setAttribute('data-custom', '');
			}
			if (!e.srcElement.getAttribute('data-custom')) {
				// 修改相应节点类名,达到样式需求效果
				main.className = "mainPro";
				// 调用setClassName方法
				setClassName(e.srcElement, 'icon-enlarge2', 'icon-shrink2');
				// 设置自定义属性值
				e.srcElement.setAttribute('data-custom', 'WebFullScreenId');
			} else {
				// 修改相应节点类名,达到样式需求效果
				main.className = "main";
				// 调用setClassName方法
				setClassName(e.srcElement, 'icon-shrink2', 'icon-enlarge2');
				// 设置自定义属性值
				e.srcElement.setAttribute('data-custom', '');
			}
		}
	}

	// 单击id名为WebFullScreenId的节点时触发事件
	WebFullScreenId.addEventListener('click', isFullscreenForNoScroll);

	// 单击id名为FullScreenId的节点时触发事件
	FullScreenId.addEventListener('click', isFullscreenForNoScroll);

	// 多选框的值发生变化时触发事件
	input.addEventListener('change', function() {
		// 判断多选框是否被选中
		if (input.checked === true) { // 被选中
			// 修改对应节点的文本信息
			label.innerText = '留';
			// 修改相应节点类名,达到样式需求效果
			controlId.className = 'controlHover';
		} else { // 不被选中
			// 修改对应节点的文本信息
			label.innerText = '降';
			// 修改相应节点类名,达到样式需求效果
			controlId.className = 'control';
		}
	});

	// 右击时触发该事件
	document.addEventListener('contextmenu', function(e) {
		// 判断被右击的元素的id是否符合要求
		if (e.target.id === 'media' || e.target.id === 'proposalORreportId') {
			// 阻止默认事件
			e.preventDefault();
			// 判断被右击的元素的id是否为media同时是否处于非全屏状态
			if (e.target.id === 'media' && !FullScreenId.getAttribute('data-custom')) {
				// 计算x的值
				let x = e.target.offsetWidth - proposalORreportId.offsetWidth;
				// 判断鼠标的x坐标是否小于等于x
				if (e.offsetX <= x) { //如果小于等于x
					// 赋值x等于e.offsetX
					x = e.offsetX;
				}
				// 计算y的值
				let y = e.target.offsetHeight - controlId.offsetHeight - proposalORreportId.offsetHeight;
				// 判断鼠标的y坐标是否小于等于y
				if (e.offsetY <= y) { // 如果小于等于y
					// 赋值y等于e.offsetY
					y = e.offsetY;
				}
				// 设置id为proposalORreportId的节点的样式
				proposalORreportId.style.cssText = 'display:block;top:' + y + 'px;left:' + x + 'px';
			}
		}
	});

	document.addEventListener('click', function(e) {
		if (e.target.id === 'proposalORreportId') {
			alert('我们一概不接受建议和举报!!!');
		} else {
			proposalORreportId.style.display = 'none';
		}
	});

	video.addEventListener("ended", function() { // 当视频由于结束而停止
		// 设置自定义属性值
		video.setAttribute('data-custom', '');
		// 调用setClassName方法
		setClassName(playORsuspendId, 'icon-pause2', 'icon-play3');
	});

	// video.addEventListener("seeking", function() {// 当用户开始移动/跳跃到音频/视频中的新位置时
	// 	LoadingId.style.display = 'block';
	// });

	// video.addEventListener("seeked", function() {// 当用户已移动/跳跃到音频/视频中的新位置时
	// 	LoadingId.style.display = 'none';
	// });

	video.addEventListener("waiting", function() { // 当视频由于需要缓冲下一帧而停止
		LoadingId.style.display = 'block';
	});

	video.addEventListener("playing", function() { // 当音频/视频在已因缓冲而暂停或停止后已就绪时
		LoadingId.style.display = 'none';
	});

})();

到了这里,关于原生js实现简单的视频播放控件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python实现本地视频/音频播放器

    在Python中,有几个库可以用于视频播放,但是没有一个库是完美的,因为它们可能依赖于外部软件或有一些限制。 先看介绍用Python实现本地视频播放器,再介绍用Python实现本地音乐播放器。 Python 实现本地视频播放器 与HTML5+JavaScript实现本地视频播放器相比,使用Python实现比

    2024年04月26日
    浏览(28)
  • Flutter的AspectRatio控件实现视频播放、图片播放按照长宽比缩放

    AspectRatio小部件用于调整其子级小部件的宽高比。它将其子级小部件的宽度调整为给定的宽度,并根据宽度计算出相应的高度,以保持指定的宽高比。 调整容器的宽高比: 当您希望在布局中使用容器或小部件时,以特定的宽高比显示内容时,可以使用AspectRatio。 例如,您可能

    2024年02月13日
    浏览(46)
  • uni-app小程序实现音频播放,uniapp播放录音,uniapp简单实现播放录音

    复制到.vue文件即可预览效果 问题 :开发者工具中.onTimeUpdate方法可能会失效! 官方参考:https://uniapp.dcloud.net.cn/api/media/audio-context.html# 其他博客参考:https://blog.csdn.net/weixin_45328705/article/details/114091301 录音实现参考 :https://blog.csdn.net/weixin_43992507/article/details/129857780

    2024年02月12日
    浏览(39)
  • vue3项目引入本地js文件,实现一个音频播放按钮

    目前有一个需求就是在网页上放置一个音乐控制按钮,并且是在vue3项目里面。于是小白的我遇到了2个问题,第一个问题是如何实现没有进度条的播放按钮,这个网上有现成的代码,可以通过js代码切换不同的图片或者是别的样式,并不算难;第二个问题是如何在vue3项目中引

    2024年02月19日
    浏览(32)
  • html+css+js本地音乐播放器,实现可视化音频频谱

    html+css+js本地音乐播放器,实现可视化音频频谱 之前用swing写了个本地音乐播放器(如下图),但是效果一言难尽,界面丑,功能bug也多,唉 所以后面又重新用html写了个,界面样式和功能方面,比swing写的好看、完善多了。 导入音乐(已完成) 展示列表(已完成) 列表双击

    2024年02月09日
    浏览(34)
  • 【html本地工具】html+css+js本地音乐播放器,实现可视化音频频谱

    html+css+js本地音乐播放器,实现可视化音频频谱 之前用swing写了个本地音乐播放器(如下图),但是效果一言难尽,界面丑,功能bug也多,唉 所以后面又重新用html写了个,界面样式和功能方面,比swing写的好看、完善多了。 导入音乐(已完成) 展示列表(已完成) 列表双击

    2024年02月14日
    浏览(28)
  • 原生JS实现视频截图

    要用原生js实现视频截图,可以利用 canvas 的绘图功能 ctx.drawImage ,只需要获取到视频标签,就可以通过 drawImage 把视频当前帧图像绘制在canvas画布上。 接下来,需要把画布转化为图片,canvas提供了两个2D转换为图片的方法: canvas.toDataURL() 和 canvas.toBlob() canvas.toDataURL(mimeType,

    2024年02月05日
    浏览(33)
  • vue+flv.js实现视频播放

    代码如下(示例): npm install --save flv.js  下载flv依赖 1.获取视频流地址并使用 2.有一个问题就是同时只能播放6个视频,超出6个视频会加载不出来,需要摧毁上一个视频,关闭视频的时候调用这个方法就好 3.还有一个就是,flv视频在谷歌浏览器播放,如果你离开页面他会暂

    2024年02月14日
    浏览(28)
  • qt实现简单的视频播放器

    2024年02月11日
    浏览(41)
  • 原生 JS 实现一个简单轮播图

    在动手实现轮播图之前,我们先来明确一下要实现的效果。 默认自动轮播,每隔4秒切换一张图片 鼠标点击任一个小圆点即可切换到对应的图片 鼠标移入轮播区域时,两侧出现切换图片的按钮,点击按钮分别切换到上(下)一张图片 因此,轮播图可以分为三个主要部分,首

    2024年02月09日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包