[刘阳Java]_酷炫视频播放器制作_JS篇
此文章是接着上次写的《酷炫视频播放器制作_界面篇》将其完善,我们主要给大家介绍一下如何利用JS脚本来控制视频的播放。为了让大家能够保持对要完成的功能有直接的了解,我们还是将效果图附到文章里面
完成本篇文章的代码编写,你能GET到200+代码量,且能够掌握很多有关video标签的属性,函数,事件的应用。当然希望大家也多多鼓励我写出更多更实际的文章来帮助大家学习的提升

第一步:我们先简单实现播放与暂停的效果,为了整个界面的DOM操作简单一点,我们就用jQuery来配合界面的操作
$(function() {
var playVideo = $("video"); // 获取播放视频对象
var playPause = $(".playPause"); // 获取播放与暂停
var currentTime = $(".timebar .currentTime"); // 当前时间
var duration = $(".timebar .duration"); // 总时间
var progress = $(".timebar .progress-bar"); // 进度条
var volumebar = $(".volumeBar .volumewrap").find(".progress-bar"); // 音量控制进度条
playVideo[0].volume = 0.4; // 初始化音量
// 播放按钮点击事件,目的控制视频播放与暂停
playPause.on("click", function() {
playControl();
});
// 屏幕点击事件,目的控制视频播放与暂定
$(".playContent").on("click", function() {
playControl();
});
/**
* 控制播放的函数
*/
function playControl() {
// 切换播放按钮的样式
playPause.toggleClass('playIcon');
if(playVideo[0].paused) {
playVideo[0].play();
} else {
playVideo[0].pause();
}
}
});
第二步:计算视频时长,时长的显示标准:小时:分钟:妙。这里我们会H5中video标签的duration属性,此属性返回视频的时长,时长计量单位秒
/**
* 将视频时长转化为时间:小时,分钟,秒
* @param {Object} value
*/
function formatSeconds(value) {
value = parseInt(value);
var time; // 存储转化好的时间格式
if(value > -1) {
hour = Math.floor(value / 3600); // 1小时=3600秒
min = Math.floor(value / 60) % 60; // 1分钟=60秒
sec = value % 60;
day = parseInt(hour / 24);
if(day > 0) {
hour = hour - 24 * day;
time = day + "day " + hour + ":";
} else {
time = hour + ":";
}
if (min < 0) {
time += "0"
}
time += min + ":";
if (sec < 0) {
time += "0";
}
time += sec;
}
return time;
}
第三步:设置视频加载后将视频时长显示到页面上。这里会用到video标签的onloadedmetadata事件
/**
* 视频加载结束后触发loadedmetadata事件
* onloadedmetadata 事件在指定视频/音频(audio/video)的元数据加载后触发
* 视频/音频(audio/video)的元数据包含: 时长,尺寸大小(视频),文本轨道
*/
playVideo.on("loadedmetadata", function() {
duration.text(formatSeconds(playVideo[0].duration));
});
第四步:视频进度条更新,完成视频播放时候进度条不断加载播放进度。这里会用到video标签的timeupdate事件
/**
* ontimeupdate 事件在视频/音频(audio/video)当前的播放位置发送改变时触发
* 该事件通常与 Video 对象的 currentTime 属性一起使用, 该属性返回视频/音频(audio/video)的当前播放位置
*/
playVideo.on("timeupdate", function() {
currentTime.text(formatSeconds(playVideo[0].currentTime));
progress.css("width", 100 * playVideo[0].currentTime / playVideo[0].duration + "%");
});
第五步:视频播放完成需要完成的更新操作。这里会用到video标签的ended事件
/**
* ended 事件在音频/视频(audio/video)播放完成后触发
*/
playVideo.on('ended', function() {
playPause.toggleClass('playIcon');
});
第六步:视频全屏播放,这里考虑兼容不同浏览器的内核(webkit,moz,ie)。同时还会用到video标签的requestFullscreen属性来判断全屏模式,document元素的exitFullScreen来退出全屏等功能设置
/**
* 视频全屏播放
* 这里尽量做到IE,Chrome,moz的内核的浏览器全屏播放的兼容性
*/
$('.fullScreen').on('click', function() {
if ($(this).hasClass('cancleScreen')) {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.mozExitFullScreen) {
document.mozExitFullScreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
}
$(this).removeClass('cancleScreen');
$('#willesPlay .playControll').css({
'bottom': -48
}).removeClass('fullControll');
} else {
if (playVideo[0].requestFullscreen) {
playVideo[0].requestFullscreen();
} else if (playVideo[0].mozRequestFullScreen) {
playVideo[0].mozRequestFullScreen();
} else if (playVideo[0].webkitRequestFullscreen) {
playVideo[0].webkitRequestFullscreen();
} else if (playVideo[0].msRequestFullscreen) {
playVideo[0].msRequestFullscreen();
}
$(this).addClass('cancleScreen');
$('#willesPlay .playControll').css({
'left': 0,
'bottom': 0
}).addClass('fullControll');
}
return false;
});
第七步:调整播放进度代码实现,思路如下
- 通过offset().left获取进度条的坐标位置
- 通过鼠标点击进度条坐标-进度条初始坐标位置=拉动进度条的偏移量(真实拉动距离)
- 最后计算进度条的百分比,然后再转化为视频拉动的时间
/**
* 拉动时间轴,调整播放的进度
*/
$(".timebar .progress").mousedown(function(e) {
e = e || window.event;
updatebar(e.pageX);
}); /**
* 调整播放进度代码实现
* 通过offset().left获取进度条的坐标位置
* 通过鼠标点击进度条坐标-进度条初始坐标位置=拉动进度条的偏移量(真实拉动距离)
* 最后计算进度条的百分比,然后再转化为视频拉动的时间
*/
var updatebar = function(x) {
var maxduration = playVideo[0].duration; // 总时长
var positions = x - progress.offset().left; // 拉动进度条的偏移量
var percentage = 100 * positions / $(".timebar .progress").width();
if(percentage > 100) {
percentage = 100;
}
if (percentage < 0) {
percentage = 0;
}
progress.css("width", percentage + "%");
playVideo[0].currentTime = maxduration * percentage / 100;
}
第八步:音量调整与控制
/**
* 音量控制弹出窗
*/
$(".volume").on("click", function(e) {
e = e || window.event;
$(".volumeBar").toggle();
e.stopPropagation();
}); /**
* 音量控制事件监听
* 多事件绑定:点击,鼠标滚轮等等方式来操作音量控制
*/
$(".volumeBar").on('click mousewhell DOMMouseScroll', function(e){
e = e || window.event;
volumeControl(e); // 控制音量调整的核心代码
e.stopPropagation();
return false;
}); /**
* 控制音量调整的核心代码
* @param {Object} e
*/
function volumeControl(e) {
e = e || window.event;
var eventype = e.type;
var delta = (e.originalEvent.wheelDelta && (e.originalEvent.wheelDelta > 0 ? 1 : -1)) || (e.originalEvent.detail && (e.originalEvent.detail > 0 ? -1 : 1));
var positions = 0;
var percentage = 0;
if (eventype == "click") {
positions = volumebar.offset().top - e.pageY;
percentage = 100 * (positions + volumebar.height()) / $('.volumeBar .volumewrap').height();
} else if (eventype == "mousewheel" || eventype == "DOMMouseScroll") {
percentage = 100 * (volumebar.height() + delta) / $('.volumeBar .volumewrap').height();
}
if (percentage < 0) {
percentage = 0;
$('.otherControl .volume').attr('class', 'volume glyphicon glyphicon-volume-off');
}
if (percentage > 50) {
$('.otherControl .volume').attr('class', 'volume glyphicon glyphicon-volume-up');
}
if (percentage > 0 && percentage <= 50) {
$('.otherControl .volume').attr('class', 'volume glyphicon glyphicon-volume-down');
}
if (percentage >= 100) {
percentage = 100;
}
$('.volumewrap .progress-bar').css('height', percentage + '%');
playVideo[0].volume = percentage / 100;
e.stopPropagation();
e.preventDefault();
}
最后还是温馨给出完整代码,供大家分享与预览,甚至拷贝都可以哈,杠杠得。。。
$(function() {
var playVideo = $("video"); // 获取播放视频对象
var playPause = $(".playPause"); // 获取播放与暂停
var currentTime = $(".timebar .currentTime"); // 当前时间
var duration = $(".timebar .duration"); // 总时间
var progress = $(".timebar .progress-bar"); // 进度条
var volumebar = $(".volumeBar .volumewrap").find(".progress-bar"); // 音量控制进度条
playVideo[0].volume = 0.4; // 初始化音量
// 播放按钮点击事件,目的控制视频播放与暂停
playPause.on("click", function() {
playControl();
});
// 屏幕点击事件,目的控制视频播放与暂定
$(".playContent").on("click", function() {
playControl();
formatSeconds(playVideo[0].duration);
});
/**
* 控制播放的函数
*/
function playControl() {
// 切换播放按钮的样式
playPause.toggleClass('playIcon');
if(playVideo[0].paused) {
playVideo[0].play();
} else {
playVideo[0].pause();
}
}
/**
* 点击网页任何地方让音量调节窗口关闭
*/
$(document).click(function() {
$(".volumeBar").hide();
});
/**
* 视频加载结束后触发loadedmetadata事件
* onloadedmetadata 事件在指定视频/音频(audio/video)的元数据加载后触发
* 视频/音频(audio/video)的元数据包含: 时长,尺寸大小(视频),文本轨道
*/
playVideo.on("loadedmetadata", function() {
duration.text(formatSeconds(playVideo[0].duration));
});
/**
* ontimeupdate 事件在视频/音频(audio/video)当前的播放位置发送改变时触发
* 该事件通常与 Video 对象的 currentTime 属性一起使用, 该属性返回视频/音频(audio/video)的当前播放位置
*/
playVideo.on("timeupdate", function() {
currentTime.text(formatSeconds(playVideo[0].currentTime));
progress.css("width", 100 * playVideo[0].currentTime / playVideo[0].duration + "%");
});
/**
* ended 事件在音频/视频(audio/video)播放完成后触发
*/
playVideo.on('ended', function() {
playPause.toggleClass('playIcon');
});
/**
* 视频全屏播放
* 这里尽量做到IE,Chrome,moz的内核的浏览器全屏播放的兼容性
*/
$('.fullScreen').on('click', function() {
if ($(this).hasClass('cancleScreen')) {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.mozExitFullScreen) {
document.mozExitFullScreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
}
$(this).removeClass('cancleScreen');
$('#willesPlay .playControll').css({
'bottom': -48
}).removeClass('fullControll');
} else {
if (playVideo[0].requestFullscreen) {
playVideo[0].requestFullscreen();
} else if (playVideo[0].mozRequestFullScreen) {
playVideo[0].mozRequestFullScreen();
} else if (playVideo[0].webkitRequestFullscreen) {
playVideo[0].webkitRequestFullscreen();
} else if (playVideo[0].msRequestFullscreen) {
playVideo[0].msRequestFullscreen();
}
$(this).addClass('cancleScreen');
$('#willesPlay .playControll').css({
'left': 0,
'bottom': 0
}).addClass('fullControll');
}
return false;
});
/**
* 拉动时间轴,调整播放的进度
*/
$(".timebar .progress").mousedown(function(e) {
e = e || window.event;
updatebar(e.pageX);
});
/**
* 调整播放进度代码实现
* 通过offset().left获取进度条的坐标位置
* 通过鼠标点击进度条坐标-进度条初始坐标位置=拉动进度条的偏移量(真实拉动距离)
* 最后计算进度条的百分比,然后再转化为视频拉动的时间
*/
var updatebar = function(x) {
var maxduration = playVideo[0].duration; // 总时长
var positions = x - progress.offset().left; // 拉动进度条的偏移量
var percentage = 100 * positions / $(".timebar .progress").width();
if(percentage > 100) {
percentage = 100;
}
if (percentage < 0) {
percentage = 0;
}
progress.css("width", percentage + "%");
playVideo[0].currentTime = maxduration * percentage / 100;
}
/**
* 音量控制弹出窗
*/
$(".volume").on("click", function(e) {
e = e || window.event;
$(".volumeBar").toggle();
e.stopPropagation();
});
/**
* 音量控制事件监听
* 多事件绑定:点击,鼠标滚轮等等方式来操作音量控制
*/
$(".volumeBar").on('click mousewhell DOMMouseScroll', function(e){
e = e || window.event;
volumeControl(e); // 控制音量调整的核心代码
e.stopPropagation();
return false;
});
/**
* 控制音量调整的核心代码
* @param {Object} e
*/
function volumeControl(e) {
e = e || window.event;
var eventype = e.type;
var delta = (e.originalEvent.wheelDelta && (e.originalEvent.wheelDelta > 0 ? 1 : -1)) || (e.originalEvent.detail && (e.originalEvent.detail > 0 ? -1 : 1));
var positions = 0;
var percentage = 0;
if (eventype == "click") {
positions = volumebar.offset().top - e.pageY;
percentage = 100 * (positions + volumebar.height()) / $('.volumeBar .volumewrap').height();
} else if (eventype == "mousewheel" || eventype == "DOMMouseScroll") {
percentage = 100 * (volumebar.height() + delta) / $('.volumeBar .volumewrap').height();
}
if (percentage < 0) {
percentage = 0;
$('.otherControl .volume').attr('class', 'volume glyphicon glyphicon-volume-off');
}
if (percentage > 50) {
$('.otherControl .volume').attr('class', 'volume glyphicon glyphicon-volume-up');
}
if (percentage > 0 && percentage <= 50) {
$('.otherControl .volume').attr('class', 'volume glyphicon glyphicon-volume-down');
}
if (percentage >= 100) {
percentage = 100;
}
$('.volumewrap .progress-bar').css('height', percentage + '%');
playVideo[0].volume = percentage / 100;
e.stopPropagation();
e.preventDefault();
}
});
/**
* 将视频时长转化为时间:小时,分钟,秒
* @param {Object} value
*/
function formatSeconds(value) {
value = parseInt(value);
var time; // 存储转化好的时间格式
if(value > -1) {
hour = Math.floor(value / 3600); // 1小时=3600秒
min = Math.floor(value / 60) % 60; // 1分钟=60秒
sec = value % 60;
day = parseInt(hour / 24);
if(day > 0) {
hour = hour - 24 * day;
time = day + "day " + hour + ":";
} else {
time = hour + ":";
}
if (min < 0) {
time += "0"
}
time += min + ":";
if (sec < 0) {
time += "0";
}
time += sec;
}
return time;
}
[刘阳Java]_酷炫视频播放器制作_JS篇的更多相关文章
- [刘阳Java]_酷炫视频播放器制作_界面篇
今天开始分享一篇酷炫播放器制作,包括界面+JS.整个案例非常类似腾讯视频,优酷视频,爱奇艺视频.我们先看一下效果图,然后这篇文章主要界面篇 是不是效果比较酷炫,那么我接着来给大家说一下这个界面设计思路 ...
- [刘阳Java]_纯CSS代码实现内容过滤效果
继续我们技术专题课,我们今天给大家带来的是一个比较酷炫的"纯CSS代码实现内容过滤效果",没有加入任何JS的效果.全部都是应用CSS3的新增选择器来实现的.先看效果截图 实现思路 ...
- [刘阳Java]_快速搭建MyBatis环境_第2讲
1.MyBatis的环境配置 导入MyBatis包, mybatis-3.2.8.jar 导入MySQL驱动包, mysql-connector-java-5.1.24-bin.jar 创建表的实体类 ...
- [刘阳Java]_什么是MyBatis_第1讲
1.什么MyBatis,我们先通过百度百科先进行一个简单的了解 MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation ...
- [刘阳Java]_斗胆介绍一下Eclipse快捷键大全[超详细]_第6讲
斗胆让我在这里介绍一下Eclipse快捷键有哪些 ctrl+shirt+r 打开资源 这组快捷键可以让你开打Eclipse工作区中任何一个文件,你只需要输入你想查找的文件名字即可,而且绝对支持模糊检索 ...
- [刘阳Java]_避开环境配置快速的使用Java的开发工具_第5讲
我们一般学习Java都应该遵循通过系统的命令工具来编译Java程序,然后对编译好Java程序进行运行,这个是非常好的习惯.但是随着后期学习Java技术的深入我们也得像Java的IDE工具屈服.所以,可 ...
- [刘阳Java]_为什么要前后端分离
前后端分离已成为互联网项目开发的业界标准使用方式,通过nginx+tomcat的方式(也可以中间加一个nodejs)有效的进行解耦,并且前后端分离会为以后的大型分布式架构.弹性计算架构.微服务架构.多 ...
- [刘阳Java]_程序员Java编程进阶的5个注意点,别编程两三年还是增删改查
此文章也是关注网上好几篇技术文章后,今天分享出来.因为,总有在程序学习路上的小伙伴会感到迷茫.而迷茫存在的情况如下 第一种:在大学学习中出现的迷茫,不知道Java到底要学什么.学习Java的标准是什么 ...
- [刘阳Java]_第一个Java程序_第7讲
1. 其实第一个Java程序是很简单,但是当自己编写第一个Java程序时候需要注意如下几个内容: 理解Java程序的运行环境 校验你的Java环境变量是否能够运行你所写的第一个Java程序 理解Jav ...
随机推荐
- 腾讯 angel 3.0:高效处理模型
腾讯 angel 3.0:高效处理模型 紧跟华为宣布新的 AI 框架开源的消息,腾讯又带来了全新的全栈机器学习平台 angel3.0.新版本功能特性覆盖了机器学习的各个阶段,包括:特征工程.模型训练. ...
- 智能驾驶L2发展策略
智能驾驶L2发展策略 智能驾驶L2,以们通俗的定义是,以高级辅助驾驶的产品为主的各种巡航产品,包括定速巡航,自适应巡航ACC,预见性巡航,智能巡航等等. 车辆驾驶是集注意力高度集中,手把控方向盘和换挡 ...
- Covid经济型自主汽车
Covid经济型自主汽车 Autonomous Vehicles in Covid Economy Covid经济已经对汽车行业产生了负面影响,更多的变化正在进行中,同时也带来了大量的不确定性.我们可 ...
- 实战SpringBoot Admin
长话短说哦,直接查看下文吧 目录 声明 先锋 前提 SpringBoot Admin 介绍 服务端的搭建 客户端的搭建 参数的指南 尾声 声明 见名知意,实战SpringBoot Admin,实战!实 ...
- .NET平台系列26:在 Windows 上安装 .NET Core/.NET5/.NET6
系列目录 [已更新最新开发文章,点击查看详细] 本文介绍如何在 Windows 上安装 .NET. .NET 由运行时和 SDK 组成. 运行时用于运行 .NET 应用,应用可能包含也可能不包 ...
- 三、Tomcat配置文件的介绍
*允许直接复制另外多份完整的tomcat数据,修改配置保证不冲突,起多个tomcat,优点:其中一个tomcat挂了不影响其他网页 tomcat配置文件server.xml介绍 <Server& ...
- ffmpeg实战-音视频合成案例
转发自白狼栈:查看原文 很多小伙伴私下里留言说,之前没接触过音视频,对于ffmpeg可以做什么还是有些懵. 今天我们一起看下我们究竟可以用 ffmpeg 做什么? 很多小伙伴应该都玩过抖音,你在&qu ...
- python10-网络编程
1,七层网络协议 应表会传网数物: 应用层.表示层.会话层 (这三层又可以合并为应用层,这样就是五层网络协议[osi五层协议]) python '你好'.encoding('utf-8') 传输层. ...
- 配置IPv6公网地址DDNS并开放外网访问端口
目前使用三大运营商宽带服务都会下发公网IPv6地址,这样我们想要在外网访问家里的路由.NAS等设备就可以直接通过IPv6地址来访问了.但是每次重新拨号后IPv6地址都会改变,而且IPv6的地址很长,这 ...
- npm 操作代码
npm cache clean -force //强制清除缓,比如安装echarts失败后,清除,在安装