[刘阳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 ...
随机推荐
- Jmeter——元件扩展,使其功能更全面
工具扩展 在之前的博文中,有介绍自定义函数.Java请求扩展,博文如下: Jmeter二次开发--基于Java请求 Jmeter二次开发--自定义函数 上述内容,是按自己的需要来进行针对性扩展,从而实 ...
- TensorFlow分布式详解
每次 TensorFlow 运算都被描述成计算图的形式,允许结构和运算操作配置所具备的自由度能够被分配到各个分布式节点上.计算图可以分成多个子图,分配给服务器集群中的不同节点. 强烈推荐读者阅读论文& ...
- 使用CUDA Warp-Level级原语
使用CUDA Warp-Level级原语 NVIDIA GPU以SIMT(单指令,多线程)的方式执行称为warps 的线程组.许多CUDA程序通过利用warp执行来实现高性能.本文将展示如何使用cud ...
- 【逆向&编程实战】Metasploit中的安卓载荷凭什么吊打SpyNote成为安卓端最强远控
文章作者:MG1937 QQ:3496925334 CNBLOG:ALDYS4 未经许可,禁止转载 前言 说起SpyNote大家自然不陌生,这款恶意远控软件被利用在各种攻击场景中 甚至是最近也捕获到了 ...
- 【NX二次开发】Block UI 对象颜色选择器
属性说明 常规 类型 描述 BlockID String 控件ID Enable Logical 是否可操作 Group Logical ...
- 【NX二次开发】按层查找工作部件中的对象 UF_LAYER_cycle_by_layer
第一次调用 :返回第一个启用层中的第一个对象. 第二次调用 :返回下一个已启用层中的下一个对象. 最后一次调用:当所有对象都被耗尽时,将返回object_tag = NULL_TAG. 在循环数据库时 ...
- 【VBA】显示所有隐藏的名称管理器中的名称
Excel提示这个 代码: Sub DisplayNames() Dim Na As Name For Each Na In ThisWorkbook.Names Na.Visible = True ...
- 强烈推荐!15 个Github 顶级Java教程类开源项目
大家好,我是 Guide 哥!今天给大家推荐 15 个新手也能看懂的 Java 教程方向的开源项目.这些项目无论是对于你学习 Java 还是准备 Java 方向的面试都非常有帮助. 正如我第一个要推荐 ...
- 在 raspberry pi pico 上体验 MicroPython
raspberry pi pico 官方提供 2 种开发方式,其中一种是使用 python3 开发,树莓派提供了 MicroPython 固件,把这个固件烧录进去,就可以 在 pico 上跑 pyth ...
- 扩展ADO.net实现对象化CRUD(.net core/framework)
扩展ADO.net实现对象化CRUD(.net core/framework) 安装nuget包:CRL using CRL; 实现数据操作 获取数据访问连接IDbConnection dbConne ...