[刘阳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 ...
随机推荐
- 工作流中的数据持久化详解!Activiti框架中JPA的使用分析
Activiti中JPA简介 可以使用JPA实体作为流程变量, 并进行操作: 基于流程变量更新已有的JPA实体,可以在用户任务的表单中填写或者由服务任务生成 重用已有的领域模型,不需要编写显示的服务获 ...
- 鱼眼摄像头SLAM
鱼眼摄像头SLAM 在机器人技术.摄影测量学和计算机视觉等领域,鲁棒相机位姿估计是许多视觉应用的核心.近年来,在复杂.大规模的室内外环境中,人们越来越关注相机位姿估计方法的实时性.通用性和可操作性.其 ...
- Charles下载及安装破解-自己编辑
Charles下载地址 地址:https://www.charlesproxy.com/latest-release/download.do 2. Charles破解 破解地址:https://www ...
- postman环境变量配置的详细过程(步骤加截图)
环境变量的配置 实战:https://www.baidu.com/s?wd=博客园 使用cmd命令模式输入代码:Nslookup www.baidu.com 模拟环境:线上环境14.215.177.3 ...
- Floyd最短路及路径输出
引例 下图表示城市之间的交通路网,线段上的数字表示费用.如图,求$V_{1}$→$V_{n}$最短路径长度及路径 样例数据 输入 10 0 2 5 1 0 0 0 0 0 0 0 0 0 0 12 1 ...
- WebRTC 传输安全机制第二话:深入显出 SRTP 协议
通过 DTLS 协商后,RTC 通信的双方完成 MasterKey 和 MasterSalt 的协商.接下来,我们继续分析在 WebRTC 中,如何使用交换的密钥,来对 RTP 和 RTCP 进行加密 ...
- pytest初始化与清除(一)
一.初始化函数 1.测试用例级别:def setup() 2.套件级别(在模块文件中定义):def setup_module() 3.套件级别(在类中定义): @classmethod def set ...
- Waymo object detect 2D解决方案论文拓展
FixMatch 半监督中的基础论文,自监督和模型一致性的代表作. Consistency regularization: 无监督学习的方式,数据\(A\)和经过数据增强的\(A\)计做\(A'\) ...
- Java IO学习笔记八:Netty入门
作者:Grey 原文地址:Java IO学习笔记八:Netty入门 多路复用多线程方式还是有点麻烦,Netty帮我们做了封装,大大简化了编码的复杂度,接下来熟悉一下netty的基本使用. Netty+ ...
- Golang学习(用代码来学习) - 第三篇
type Books struct { title string author string subject string id int } /** 结构体的学习 */ func struct_tes ...