实现跨页音乐播放

注:其实媒体文件的播放都可以采用本文的方法,这里仅以音乐为例。

很多喜欢音乐的朋友都喜欢在自己的站点中分享自己喜欢的音乐。通常除了直接给出音乐文件下载地址,还可以在文章内容中嵌入播放器,使读者可以在阅读内容的时候很方便地播放。可以使用Flash或者JavaScript的播放器。Yahoo! Media PlayerJW FLV Media Player 都是不错的选择。但是在播放一首曲目的时候,如果用户想切换到别的页面浏览别的内容,播放就会终止。那如何做到在用户切换页面的时候,使音乐继续播放呢?

其实只要遵循一个原则就可以做到——播放器所在的页面不进行跳转。也就是说,要么将其他内容与播放器分离,要么整个站点的内容都在一个页面内,采用动态加载。

播放器与内容分离

有两种方法:弹出新窗口进行播放和使用框架。

弹出新窗口

这个很容易理解,谷歌音乐就是采取的这个方式。这个方式使得播放器完全分离在另一个窗口,感觉上和使用本地播放器进行播放效果类似,比较之下其优势在于可以在播放窗口安排更多的个性化功能。但是这个方法要多开一个浏览器窗口,总让人感觉不那么自然。

使用框架

这个方法和上一个其实没有本质的区别,最大的不同就是将独立的窗口放在一个frame中,这样就可以在同一个视图中进行播放器的控制和站点其他内容的浏览了。上一次的测试文章就是使用的这个方法。

稍微介绍一下我使用的这个方法。将frameset分为上下两个frame,上面的主窗口就放站点原来的页面,在下面的frame中嵌入包含JW Player的player.html。包含frameset的网页代码大致如下:

HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<html>
<head>
<title>My Website</title>
</head>
<!-- 下面rows="*, 20px"表示,页面上部自适应高度,下部固定20px高,可自己调整 -->
<frameset id="f" rows="*, 20px" border="0">
    <!-- 下面这个frame指向你的网站路径 -->
    <frame src="http://www.my-website.com" frameborder="0" noresize="true" />
    <!-- 下面这个frame指向播放器路径 -->
    <frame src="player.html" frameborder="0" scrolling="no" noresize="true" />
</frameset>
<noframes>
    <body>
        <!-- 如果浏览器不支持框架,显示如下内容 -->
        Sorry, your browser does not support frameset.
    </body>
</noframes>
</html>

下载JW Player后将其包含的播放器Flash文件及swfobject.js均解压到站点相应目录。可以去JW Player的官网使用其设置向导进行代码生成,直接copy到player.html中。生成的代码包含这样一句:

JavaScript
var so = new SWFObject('player-viral.swf','mpl','100%','19','9');

其中的'mpl'是生成的播放器对象的id和name,之后还会用上。当然也可以自己起别的名字。

现在播放器只能播放初始化时预设的那个曲目,已经可以实现跨页播放,不过还需要进一步的改进。我们可能在站点内多处提供了音乐资源,希望用户可以根据喜好选择播放器内播放的曲目。接下来可以使用JS来控制播放器播放的曲目。由于这些功能在不使用frameset时不需要,我们可以在页面初始化时,通过检查是否存在frameset来判断是否需要动态加载实现这些功能的JS代码。我使用的是jQuery的动态加载方法,如果顶层窗口内存在2个frame,就进行加载:

JavaScript
if(top.frames[1]) {
    $.getScript('http://lync.in/frame.js');
}

首先,我们希望在音乐文件的链接后给出一个播放按钮。在发布需要支持跨页播放的音乐链接时,我们可以给相应的<a>标签添加class="play",然后使用jQuery来完成按钮的添加:

JavaScript
$('a.play[href]').each(function () {
    $(this).after('<span>[<a class="play_button" href="javascript:playAudio(\'' + $(this).attr('href') + '\');">Play</a>]</span>');
});

接下来就是完成playAudio这个函数的功能。首先,在player.html的JS代码中添加:

JavaScript
1
2
3
4
5
6
7
8
function thePlayer() {
    if(navigator.appName.indexOf("Microsoft") != -1) {
        return window['mpl'];
    } else {
        return document['mpl'];
    }
}
var player = thePlayer();

这就取得了播放器的JS对象,在主页面中可以使用top.frames[1].player对其进行引用。注意上面'mpl'需要和在SWFObject对象初始化时设定的id相同。然后只要在点击Play按钮时给播放器发送相应事件就可以更新其播放的内容:

JavaScript
1
2
3
4
5
function playAudio(src) {
    player.sendEvent('STOP');
    player.sendEvent('LOAD', src);
    player.sendEvent('PLAY');
}

这样,整个站点内class="play"的音乐链接都会动态加上Play按钮,并可以在站内实现跨页面播放了。

还有几个小细节需要完善。在带框架的页面内再点击导航向框架页面会导致框架嵌套,可以使用JS处理页面内所有链接,在遇到导航向框架页的链接时,在顶层窗口进行跳转。在这里我带框架的页面地址为http://lync.in/go.php

JavaScript
$('a[href^="http://lync.in/go.php"]').click(function() {
    top.window.location.href = $(this).attr('href');
});

除此之外,当点击站外链接时,也应该在顶层窗口进行跳转。在使用框架时,点击某个frame中的链接并不会改变顶层窗口的title和地址栏链接。

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$('a').click(function() {
    top.document.title = 'Loading...'; //点击链接时先将title设为"loading..."
}).filter(function() {
    var href = $(this).attr('href');
    if(href) {
        //经过滤选出站外链接
        return !(href.indexOf('http://') == -1 || href.indexOf('http://lync.in/') == 0);
    }
    return true;
}).click(function() {
    top.window.location.href = $(this).attr('href');
    return false;
});
top.document.title = document.title; //让顶层窗口的title和主窗口title相同

用上面的方法,可在新页面加载的时候用JS将title更新。而对地址栏的链接就没有什么完美的方法了,可以采取Billboard的解决方案,后面会说。

全站动态加载

整个站点都不刷页,点击链接都以AJAX的方式进行加载,或者直接全站Flash/Flex。

这个方法有一个很好的例子是Billboard。它所有的音乐都使用页面左侧的JS播放器进行播放,并有调整播放列表等功能,而页面的跳转全部都使用JS来处理。而地址栏URL它采用了页内链接的方式,点击后不刷页,但是可以更新地址栏URL。这样,用JS将普通的链接在点击时转换为页内链接,就可以不刷新页面而且更新地址栏了。如果我们应用到框架方法中,那就可以在点击站内链接时,先将顶层窗口定向到相应页内链接,然后return true就行了。同时,如果用户使用带有'#'的链接进行直接访问,也应该在服务器端做相应处理,给出相应的frame源地址。但Wordpress站点一般都含有带页内锚点的链接,比如http://lync.in/how-to-play-music-across-pages/#comments,这样处理起来就比较麻烦了。

个人不太喜欢全站Flash/Flex的站点,虽然效果够炫,但是这样屏蔽了浏览器的不少功能,可能会与用户长期养成的使用习惯发生冲突。比如在访问Flash站点时,就无法使用浏览器的返回按钮进行回退了,更别说鼠标手势等等功能了。

就这点体会了,如果大家有更好的方法来实现这个效果,希望不吝赐教。

Comments (21)

  1. 20:00, 2009-09-17任平生  / Reply

    这个真折腾。。。

  2. 20:19, 2009-09-17Justice  / Reply

    @任平生
    大家都爱折腾...

  3. 20:40, 2009-09-17任平生  / Reply

    @Justice
    是哈~

  4. 13:57, 2009-09-21DeepBlue  / Reply

    一直想实现这功能,一直没成功!

  5. 14:43, 2009-09-21Justice  / Reply

    @DeepBlue
    这个实现起来还是挺麻烦的~

  6. 11:55, 2010-04-17kristam  / Reply

    下载JW Player后将其包含的播放器Flash文件及swfobject.js均解压到站点相应目录。可以去JW Player的官网使用其设置向导进行代码生成,直接copy到player.html中

    博主您好,参照你的文章搞了很久没有结果,请教下这个“相应目录”是指什么地方呢,,?

  7. 12:10, 2010-04-17Justice  / Reply

    @kristam
    放在你的 player.html 同一目录下就可以。

  8. 12:17, 2010-04-17kristam  / Reply

    是放在同一目录下的,再请教您下,应该是放到空间根目录下,还是要放到WP主题的根目录下,

  9. 13:35, 2010-04-17Justice  / Reply

    @kristam
    应该只要是任何可以远程访问到的目录都可以。你需要在你站点目录新建一个 HTML 页面,我之前文章中没给出代码,现在更新了一下。你把你网站的路径写在第一个 framesrc 中,然后远程访问你新建的这个页面,应该就可以了。

  10. 19:44, 2010-04-17kristam  / Reply

    非常感谢,您看是不是这样,
    1.空间根目录下新建一个名为player.html页面,里面是您今天补上的那个代码,
    2.把play.swf和swfobject.js放到站点目录下
    3.把JW Player官网设置向导生成的代码copy到player.html里,

  11. 20:56, 2010-04-17Justice  / Reply

    @kristam
    不是。你需要新建的页面是包含两个 frame 的页面(也就是我后来加的那个),名字随意。两个 frame 一个指向你网站的内容,另一个指向 player.html。在 player.html 中要包含向导生成的代码,这样就可以简单地实现跨页播放指定的曲目。如果要让自己网站里的音乐文件都能调用这个播放器来播放,就比较复杂了,整个过程很复杂,我没有完全写出来,只是贴了主要的代码。如果你对 JavaScript 不太熟的话建议能跨页播放指定曲目就可以了。

  12. 18:09, 2010-04-18kristam  / Reply

    Test
    非常感谢博主,过来交作业,呵,再复杂的也没敢想了,对代码完全不熟,有时间照着你的教程一步步摸看看,

  13. 22:30, 2010-04-30guest  / Reply

    您好
    我按照您提供的方法的修改, 但是卻發生一個問題
    每當按下一個連結就會多跑出一個jw player
    而且按下連結後還是轉址到原來的網址
    想請教文中提到"还有几个小细节需要完善。...." 的那段程式碼是要放到什麼地方呢?
    懇請賜教

  14. 22:51, 2010-04-30Justice  / Reply

    @guest
    你可能是框架相互嵌套了,你说的那几段代码是放在你原来的网站内容的 JS 代码里的。你的网址是什么呀,我帮你看一下吧~

  15. 08:38, 2010-05-09kristam  / Reply

    那个让自己网站里的音乐文件都能调用这个播放器来播放,始终不行,崩溃了,,
    给您发了邮件,您有空的时候帮我看下好吗,,,

  16. 12:45, 2010-05-09Justice  / Reply

    @kristam
    我没有收到邮件啊。我上面写的不是全部的代码,只是一些关键的代码。这不是一个教程,只是一些实现手段的讨论啦。

  17. 13:08, 2010-05-09kristam  / Reply

    邮件被系统拒收了,我自己肯定是没戏啦,哎,,,您可以帮我搞一下吗,如果可以的话,我把我FTP和站点后台账号密码给您,,,

  18. 13:38, 2010-05-09Justice  / Reply

    @kristam
    厄...这段时间应该是没啥时间了...

  19. 12:51, 2010-05-10kristam  / Reply

    额,还以为搞下很快呢,如果很麻烦的话那不敢打扰了,呵,,,

  20. 09:06, 2010-10-09逝水流痕  / Reply

    @guest
    哎,本来还弄着的,弄来弄去都不成功,就没弄了。有点复杂哎!不过还是谢谢博主。准备过段时间再弄它。

  21. 14:43, 2011-07-30kingfon  / Reply

    您好,请问有没有下载包?不会弄啊!。。。

Leave a Reply

Allowed Tags - You may use these HTML tags and attributes in your comment.

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">

Pingbacks (1)