可点击 "positioning" 指向 A/V 的超链接(本地存储在您的网站上并“隐藏”在海报图片后面)
Clickable "positioning" hyperlinks to A/V (locally stored on your website and “hidden” behind a poster image)
Meta:这个问题是后续问题,或者是关于嵌入式 Youtube 的类似问题的变体视频:
定义:
一张"poster"图片
您点击的自定义图片,显示实际的 A/V 玩家。
本地存储
A/V 存储在您的网站上,而不是 Youtube 等流媒体服务。
可点击 "positioning" 超链接
当 HTML 文本中的某个超链接时,A/V 的预定义开始(可能结束)位置将被寻址并自动播放。
我一直在网上阅读有关 function(){something.currentTime=...;});
的内容,但我无法实现它。
演示
很抱歉延迟了,因为它与 Youtube 的不完全一样,我最缺乏的是一致性,但是 here it is。
我将此示例基于 Hozier 中的两首歌曲,一首是音频格式,一首是视频格式。 (希望没有人起诉我)
与往常一样,您以后可以修改样式以适合您的设计,我只是快速组合一些东西来演示。
下面,您将看到代码工作原理的基本示例(有关更深入的示例,请参阅 demo)。
HTML
音频
<div class="mediaAudioFacade"
id="id"
data-sources="source1.mp3,source2.wav,source3.ogg"
data-start="seconds"(optional)
data-end="seconds"(optional)>
label
</div>
<div class="mediaJumper" data-id="id" data-time="seconds">label</div>
视频
<div class="mediaVideoFacade" (..)>(..)</div>
(..)
唯一的区别是 class 属性,这是 mediaVideoFacade
而不是 mediaAudioFacade
。
JavaScript
window.addEventListener("load",function(){
setUpMediaObjects();
setUpMediaJumpers();
});
MediaObjects = [];
MediaJumpers = [];
function setUpMediaObjects() {
var allAudioFacades = document.querySelectorAll(".mediaAudioFacade");
if (allAudioFacades) {
for (var i = 0; i < allAudioFacades.length; i++) {
var facade = allAudioFacades[i];
var mo = new MediaObject(facade);
MediaObjects.push(mo);
}
}
var allVideoFacades = document.querySelectorAll(".mediaVideoFacade");
if (allVideoFacades) {
for (var i = 0; i < allVideoFacades.length; i++) {
var facade = allVideoFacades[i];
var mo = new MediaObject(facade);
MediaObjects.push(mo);
}
}
}
function setUpMediaJumpers(){
var allMediaJumpers = document.querySelectorAll(".mediaJumper");
for( var i = 0 ; i < allMediaJumpers.length ; i ++ ){
var mediaJumper = allMediaJumpers[i];
var mj = new MediaJumper(mediaJumper);
MediaJumpers.push(mj);
}
}
function MediaObject(facade) {
this.facade = facade;
this.id = this.facade.id;
this.sourcesURI = this.facade.dataset.sources.split(",");
this.sources = this.getSources();
var isAudio = this.facade.className.match(/mediaAudioFacade/);
this.type = (isAudio) ? "audio" : "video";
this.icon = new Image();
this.icon.src = (isAudio) ? "http://i.imgur.com/HKktAoE.png" : "http://findicons.com/icon/download/566082/video_play/33/png";
this.setUpFacade();
this.capType = this.type.substr(0,1).toUpperCase() + this.type.substr(1);
this.elem = document.createElement(this.type);
this.elem.controls = "true";
this.elem.className = "mediaType".replace(/type/i, this.capType);
this.hasStarted = false;
this.appendSources();
this.startTime = this.facade.dataset.start;
this.endTime = this.facade.dataset.end;
this.facade.addEventListener("click", this.startUp.bind(this) );
}
MediaObject.prototype.setUpFacade = function () {
var label = document.createElement("span");
label.innerHTML = this.facade.innerHTML || "Play audio.";
this.facade.innerHTML = "";
this.facade.appendChild(this.icon);
this.facade.appendChild(label);
}
MediaObject.prototype.getSources = function () {
var sources = [];
for (var i = 0; i < this.sourcesURI.length; i++) {
var sourceURI = this.sourcesURI[i];
var source = document.createElement("source");
source.src = sourceURI;
sources.push(source);
}
return sources;
}
MediaObject.prototype.appendSources = function () {
for (var i = 0; i < this.sources.length; i++) {
var source = this.sources[i];
this.elem.appendChild(source);
}
}
MediaObject.prototype.startUp = function () {
this.replaceNode(this.facade, this.elem);
this.hasStarted = true;
if( this.startTime )
this.elem.currentTime = this.startTime;
if( this.endTime )
this.elem.addEventListener("timeupdate",this.checkForVideoEnd.bind(this));
this.elem.play();
}
MediaObject.prototype.checkForVideoEnd = function(){
console.log(this.elem.currentTime);
if( Math.floor(this.elem.currentTime) == this.endTime )
this.elem.pause();
}
MediaObject.prototype.replaceNode = function(node1,node2){
var parent = node1.parentNode;
var next = node1.nextSibling;
if( next )
parent.insertBefore(node2,next);
else
parent.appendChild(node2);
parent.removeChild(node1);
}
function MediaJumper(jumper){
this.jumper = jumper;
this.id = this.jumper.dataset.id;
this.mediaObject = this.getMediaObject();
this.time = this.jumper.dataset.time;
this.jumper.addEventListener("click",this.jump.bind(this));
}
MediaJumper.prototype.getMediaObject = function(){
for( var i = 0 ; i < MediaObjects.length ; i ++ ){
var mediaObj = MediaObjects[i];
if( mediaObj.id == this.id )
return mediaObj;
}
return null;
}
MediaJumper.prototype.jump = function(){
if( this.mediaObject ){
if( !this.mediaObject.hasStarted )
this.mediaObject.startUp();
this.mediaObject.elem.currentTime = this.time;
this.mediaObject.elem.play();
}
}
随时询问有关代码的任何问题,或报告任何不工作的地方,祝您好运,希望对您有所帮助! :)
更新
添加了data-start
和data-end
,注意data-end
只会在指定的时间与视频的当前时间匹配时停止视频。技术上:
if( Math.Floor(MediaCurrentTime) == DataEndTime ) 停止();
这意味着如果跳线被调用,它将继续正常播放,直到它再次击中那个数字,如果跳线调用超过数据结束的时间,那么视频将正常播放。
Meta:这个问题是后续问题,或者是关于嵌入式 Youtube 的类似问题的变体视频:
定义:
一张"poster"图片
您点击的自定义图片,显示实际的 A/V 玩家。
本地存储
A/V 存储在您的网站上,而不是 Youtube 等流媒体服务。
可点击 "positioning" 超链接
当 HTML 文本中的某个超链接时,A/V 的预定义开始(可能结束)位置将被寻址并自动播放。
我一直在网上阅读有关 function(){something.currentTime=...;});
的内容,但我无法实现它。
演示
很抱歉延迟了,因为它与 Youtube 的不完全一样,我最缺乏的是一致性,但是 here it is。
我将此示例基于 Hozier 中的两首歌曲,一首是音频格式,一首是视频格式。 (希望没有人起诉我)
与往常一样,您以后可以修改样式以适合您的设计,我只是快速组合一些东西来演示。
下面,您将看到代码工作原理的基本示例(有关更深入的示例,请参阅 demo)。
HTML
音频
<div class="mediaAudioFacade"
id="id"
data-sources="source1.mp3,source2.wav,source3.ogg"
data-start="seconds"(optional)
data-end="seconds"(optional)>
label
</div>
<div class="mediaJumper" data-id="id" data-time="seconds">label</div>
视频
<div class="mediaVideoFacade" (..)>(..)</div>
(..)
唯一的区别是 class 属性,这是 mediaVideoFacade
而不是 mediaAudioFacade
。
JavaScript
window.addEventListener("load",function(){
setUpMediaObjects();
setUpMediaJumpers();
});
MediaObjects = [];
MediaJumpers = [];
function setUpMediaObjects() {
var allAudioFacades = document.querySelectorAll(".mediaAudioFacade");
if (allAudioFacades) {
for (var i = 0; i < allAudioFacades.length; i++) {
var facade = allAudioFacades[i];
var mo = new MediaObject(facade);
MediaObjects.push(mo);
}
}
var allVideoFacades = document.querySelectorAll(".mediaVideoFacade");
if (allVideoFacades) {
for (var i = 0; i < allVideoFacades.length; i++) {
var facade = allVideoFacades[i];
var mo = new MediaObject(facade);
MediaObjects.push(mo);
}
}
}
function setUpMediaJumpers(){
var allMediaJumpers = document.querySelectorAll(".mediaJumper");
for( var i = 0 ; i < allMediaJumpers.length ; i ++ ){
var mediaJumper = allMediaJumpers[i];
var mj = new MediaJumper(mediaJumper);
MediaJumpers.push(mj);
}
}
function MediaObject(facade) {
this.facade = facade;
this.id = this.facade.id;
this.sourcesURI = this.facade.dataset.sources.split(",");
this.sources = this.getSources();
var isAudio = this.facade.className.match(/mediaAudioFacade/);
this.type = (isAudio) ? "audio" : "video";
this.icon = new Image();
this.icon.src = (isAudio) ? "http://i.imgur.com/HKktAoE.png" : "http://findicons.com/icon/download/566082/video_play/33/png";
this.setUpFacade();
this.capType = this.type.substr(0,1).toUpperCase() + this.type.substr(1);
this.elem = document.createElement(this.type);
this.elem.controls = "true";
this.elem.className = "mediaType".replace(/type/i, this.capType);
this.hasStarted = false;
this.appendSources();
this.startTime = this.facade.dataset.start;
this.endTime = this.facade.dataset.end;
this.facade.addEventListener("click", this.startUp.bind(this) );
}
MediaObject.prototype.setUpFacade = function () {
var label = document.createElement("span");
label.innerHTML = this.facade.innerHTML || "Play audio.";
this.facade.innerHTML = "";
this.facade.appendChild(this.icon);
this.facade.appendChild(label);
}
MediaObject.prototype.getSources = function () {
var sources = [];
for (var i = 0; i < this.sourcesURI.length; i++) {
var sourceURI = this.sourcesURI[i];
var source = document.createElement("source");
source.src = sourceURI;
sources.push(source);
}
return sources;
}
MediaObject.prototype.appendSources = function () {
for (var i = 0; i < this.sources.length; i++) {
var source = this.sources[i];
this.elem.appendChild(source);
}
}
MediaObject.prototype.startUp = function () {
this.replaceNode(this.facade, this.elem);
this.hasStarted = true;
if( this.startTime )
this.elem.currentTime = this.startTime;
if( this.endTime )
this.elem.addEventListener("timeupdate",this.checkForVideoEnd.bind(this));
this.elem.play();
}
MediaObject.prototype.checkForVideoEnd = function(){
console.log(this.elem.currentTime);
if( Math.floor(this.elem.currentTime) == this.endTime )
this.elem.pause();
}
MediaObject.prototype.replaceNode = function(node1,node2){
var parent = node1.parentNode;
var next = node1.nextSibling;
if( next )
parent.insertBefore(node2,next);
else
parent.appendChild(node2);
parent.removeChild(node1);
}
function MediaJumper(jumper){
this.jumper = jumper;
this.id = this.jumper.dataset.id;
this.mediaObject = this.getMediaObject();
this.time = this.jumper.dataset.time;
this.jumper.addEventListener("click",this.jump.bind(this));
}
MediaJumper.prototype.getMediaObject = function(){
for( var i = 0 ; i < MediaObjects.length ; i ++ ){
var mediaObj = MediaObjects[i];
if( mediaObj.id == this.id )
return mediaObj;
}
return null;
}
MediaJumper.prototype.jump = function(){
if( this.mediaObject ){
if( !this.mediaObject.hasStarted )
this.mediaObject.startUp();
this.mediaObject.elem.currentTime = this.time;
this.mediaObject.elem.play();
}
}
随时询问有关代码的任何问题,或报告任何不工作的地方,祝您好运,希望对您有所帮助! :)
更新
添加了
data-start
和data-end
,注意data-end
只会在指定的时间与视频的当前时间匹配时停止视频。技术上:if( Math.Floor(MediaCurrentTime) == DataEndTime ) 停止();
这意味着如果跳线被调用,它将继续正常播放,直到它再次击中那个数字,如果跳线调用超过数据结束的时间,那么视频将正常播放。