可点击 "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-startdata-end,注意data-end只会在指定的时间与视频的当前时间匹配时停止视频。技术上:

    if( Math.Floor(MediaCurrentTime) == DataEndTime ) 停止();

这意味着如果跳线被调用,它将继续正常播放,直到它再次击中那个数字,如果跳线调用超过数据结束的时间,那么视频将正常播放。