此文章是接着上次写的《酷炫视频播放器制作_界面篇》将其完善,我们主要给大家介绍一下如何利用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篇的更多相关文章

  1. [刘阳Java]_酷炫视频播放器制作_界面篇

    今天开始分享一篇酷炫播放器制作,包括界面+JS.整个案例非常类似腾讯视频,优酷视频,爱奇艺视频.我们先看一下效果图,然后这篇文章主要界面篇 是不是效果比较酷炫,那么我接着来给大家说一下这个界面设计思路 ...

  2. [刘阳Java]_纯CSS代码实现内容过滤效果

    继续我们技术专题课,我们今天给大家带来的是一个比较酷炫的"纯CSS代码实现内容过滤效果",没有加入任何JS的效果.全部都是应用CSS3的新增选择器来实现的.先看效果截图 实现思路 ...

  3. [刘阳Java]_快速搭建MyBatis环境_第2讲

    1.MyBatis的环境配置 导入MyBatis包, mybatis-3.2.8.jar 导入MySQL驱动包, mysql-connector-java-5.1.24-bin.jar 创建表的实体类 ...

  4. [刘阳Java]_什么是MyBatis_第1讲

    1.什么MyBatis,我们先通过百度百科先进行一个简单的了解 MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation ...

  5. [刘阳Java]_斗胆介绍一下Eclipse快捷键大全[超详细]_第6讲

    斗胆让我在这里介绍一下Eclipse快捷键有哪些 ctrl+shirt+r 打开资源 这组快捷键可以让你开打Eclipse工作区中任何一个文件,你只需要输入你想查找的文件名字即可,而且绝对支持模糊检索 ...

  6. [刘阳Java]_避开环境配置快速的使用Java的开发工具_第5讲

    我们一般学习Java都应该遵循通过系统的命令工具来编译Java程序,然后对编译好Java程序进行运行,这个是非常好的习惯.但是随着后期学习Java技术的深入我们也得像Java的IDE工具屈服.所以,可 ...

  7. [刘阳Java]_为什么要前后端分离

    前后端分离已成为互联网项目开发的业界标准使用方式,通过nginx+tomcat的方式(也可以中间加一个nodejs)有效的进行解耦,并且前后端分离会为以后的大型分布式架构.弹性计算架构.微服务架构.多 ...

  8. [刘阳Java]_程序员Java编程进阶的5个注意点,别编程两三年还是增删改查

    此文章也是关注网上好几篇技术文章后,今天分享出来.因为,总有在程序学习路上的小伙伴会感到迷茫.而迷茫存在的情况如下 第一种:在大学学习中出现的迷茫,不知道Java到底要学什么.学习Java的标准是什么 ...

  9. [刘阳Java]_第一个Java程序_第7讲

    1. 其实第一个Java程序是很简单,但是当自己编写第一个Java程序时候需要注意如下几个内容: 理解Java程序的运行环境 校验你的Java环境变量是否能够运行你所写的第一个Java程序 理解Jav ...

随机推荐

  1. 手把手带你快速入门jQuery(视频|资料,建议收藏!)

    jQuery是什么? jQuery是一个快速.简洁的JavaScript框架,是继Prototype之后又一个优秀的JavaScript代码库(或JavaScript框架). jQuery设计的宗旨是 ...

  2. CVPR2019目标检测论文看点:并域上的广义交

    CVPR2019目标检测论文看点:并域上的广义交 Generalized Intersection over Union Generalized Intersection over Union: A ...

  3. thymeleaf+Springboot实现自定义标签

    在项目开发中,有一些组件不能满足我们快速开发的要求,我们需要封装一些组件来更加的便利我们.比如,我们可以封装一个下拉框组件,只要开发人员只有引用这个组件的标签,就能出现效果,而不用再去请求url,渲染 ...

  4. 开发掉坑(二)前端静态资源 Uncaught SyntaxError: Unexpected token <

    某天,有同学反馈后台管理系统出现静态资源无法加载的问题. 复现如下: 进入首页. 点击侧边栏某个子功能,静态资源可正常访问到. 等待10分钟左右,点击侧边栏其他子功能,无法访问到静态资源. 查看控制台 ...

  5. SpringBoot2 参数管理实践,入参出参与校验

    一.参数管理 在编程系统中,为了能写出良好的代码,会根据是各种设计模式.原则.约束等去规范代码,从而提高代码的可读性.复用性.可修改,实际上个人觉得,如果写出的代码很好,即别人修改也无法破坏原作者的思 ...

  6. 五、自定义Zabbix监控项目

    要求: 沿用练习三,使用Zabbix实现自定义监控,实现以下目标:监控Linux服务器系统账户的数量. 方案: 需要使用Zabbix自定义key的方式实现自定义监控,参考如下操作步骤:1.创建自定义k ...

  7. 「是时候升级Java11了」 JDK11优势和JDK选择

    Java8 商用收费 从2019年1月份开始,Oracle JDK 开始对 Java SE 8 之后的版本开始进行商用收费,确切的说是 8u201/202 之后的版本.如果你用 Java 开发的功能如 ...

  8. Vue(5)计算属性computed

    前言 一般情况下属性都是放到data中的,但是有些属性可能是需要经过一些逻辑计算后才能得出来,那么我们可以把这类属性变成计算属性.比如以下: <div id="example" ...

  9. 35、mysql数据库(ddl)

    35.1.数据库之库操作: 1.创建数据库(在磁盘上创建一个对应的文件夹): create database [if not exists] db_name [character set xxx]; ...

  10. Docker与k8s的恩怨情仇(四)-云原生时代的闭源落幕

    转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 在本系列前几篇文章中,我们介绍了从Cloud Foundry到Docker等PaaS平台的发展迭代过程.今天 ...