1. 程式人生 > >HTML頁面嵌入視訊和JS控制切換視訊

HTML頁面嵌入視訊和JS控制切換視訊

首先,在頁面中嵌入視訊的HTML程式碼為:

<div id="youku" class="youku">
    <object id="obx" name="obx" width="290" height="260">
    <param name="movie" value="http://www.tudou.com/v/6HJvxxkarzk/&resourceId=0_04_11_19/v.swf"></param>            
    <param name="allowFullScreen" value="true"></param>
    <param name="allowscriptaccess" value="always"></param>
    <param name="wmode" value="opaque"></param>
    <embed src="http://www.tudou.com/v/6HJvxxkarzk/&resourceId=0_04_11_19/v.swf" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" wmode="opaque" width="290" height="260"></embed>
    </object>
</div>
其中,同時使用objectembed標籤是為了相容更多的瀏覽器,但請注意保持兩種標籤下相同屬性值的一致。
PS:<object><embed>標籤及其屬性的介紹和使用方法請參考OBJECT和EMBED標籤一文。

然後,再說說如何用JS來動態改變嵌入視訊的地址從而達到播放下一個視訊的目的。
這時好多人立刻就能想到用標籤名或者DOM方式來找到上述param結點的value屬性和embed結點的src屬性,用JS動態賦值來改變地址。但是測試發現視訊地址雖然被替換了,頁面上顯示的視訊卻還是原來的沒有改變,百思不得其解。

原來,嵌入的這個object物件的所有引數是在頁面載入的時候初始化的,只有使其重新載入才能實現切換到下一個視訊進行播放,單純改變它的地址屬性值是不起作用的。就像公司的某個員工,他的地址變了(搬家了),他還是原來的那個員工而不是其他人。
我經常使用的使其重新載入的方法有兩種(以上述程式碼為例):
①用JS的obj.
innerHTML方法將object物件整體進行重置。
/*功能:動態切換視訊*/
function setvideo(url){
    var youku = document.getElementById("youku");
    var htmlstr =  "<object  id='obx' name='obx' width='290' height='260'>";
        htmlstr += "<param name='movie' value='"+url+"'></param>";
        htmlstr += "<param name='allowFullScreen' value='true'></param>";
        htmlstr += "<param name='allowscriptaccess' value='always'></param>";
        htmlstr += "<param name='wmode' value='opaque'></param>";
        htmlstr += "<embed src='"+url+"' type='application/x-shockwave-flash' allowscriptaccess='always' allowfullscreen='true' wmode='opaque' width='290' height='260'></embed>";
        htmlstr += "</object>";
    youku.innerHTML = htmlstr;
}
②在div容器內放置一個iframe,這樣可以動態重新整理iframe內的頁面而不影響當前父頁面。
具體的程式碼就不寫了,大體的思路有:
  1.採用url傳值。
  2.父頁面或子頁面弄個隱藏域動態存放地址供子頁面獲取。
  3.採用①方法重置子頁面中object物件。
  4.其他諸如window.open方法就繞遠了,不推薦。
至此,嵌入和控制視訊切換都成功實現了。但是無意間,我發現一個問題:
切換到新的視訊之後,點重新整理或按F5等任何方式的重新整理頁面,都會彈出一個“缺少物件”的指令碼錯誤。找到錯誤程式碼,發現是Flash的內部指令碼錯誤:
 function __flash__removeCallback(instance, name) {
2   instance[name] = null;
3 }

如果頁面裡使用了flash,並且flash裡使用了flash.external.ExternalInterface.addCallback 方法,重新整理網頁時就會報__flash__removeCallback的js錯誤:缺少物件(Line 53),(Jscript-scriptblock)。此函式的呼叫處為:

1 __flash__removeCallback(document.getElementById(""), "dewprev");

很顯然,這裡document.getElementById("")返回的是null,才會導致__flash__removeCallback報錯,個人認為這個flash的內建方法或許應該這麼寫:

1 function __flash__removeCallback(instance, name) {
2     if (instance != null) { instance[name] = null; }
3 }

有人測試發現,document.getElementById("")這裡是獲取flash控制元件Object物件的id/name屬性的,之所以出現這個錯誤,是因為沒給Object設定id/name屬性,設定後就不會出錯了。可事實上我的object都是帶著id/name屬性的,因此不敢苟同此原因。由此看來,這個加id/name的方法可以解決部分人的問題,引起此問題的原因並非僅此一種。

爾後,我苦苦找尋了好久,終於在一個外國網站上找到了解決的辦法,是一個叫Dave Smith的人寫的,我在他程式碼的基礎上做了點改進,減少了頁面不斷執行程式碼的壓力。他提供的程式碼如下:

<script type="text/javascript">
   (function(){
  var setRemoveCallback = function(){
     __flash__removeCallback = function(instance, name){
      if (instance){
              instance[name] =null; 
          }
      };
      window.setTimeout(setRemoveCallback, 10);
   };
   setRemoveCallback();
   })();
</script>
他的意思大體就是:重寫flash內部的這個指令碼可以解決當前的問題,但是當object物件載入後某個時間,flash內部的這個指令碼又會覆蓋你重寫的這個函式。因此不能保證播放器到時會呼叫你重寫的函式。為了達到這個目的,他將函式設為每10毫秒覆蓋一下flash內部提供的這個函式。這樣問題就解決了。同時他將這段程式碼加以簡化形成了以下兩個“版本”:
簡化版本一:稍簡
<script type="text/javascript">
  var setRemoveCallback = function() {
        __flash__removeCallback = function(instance, name) {
       if(instance) {
                instance[name] = null;
            }
        };
        window.setTimeout(setRemoveCallback, 10);
    };
    setRemoveCallback();
</script>
簡化版本二:超簡
<script type="text/javascript">(function(){var s=function(){__flash__removeCallback=function(i,n){if(i)i[n]=null;};window.setTimeout(s,10);};s();})();</script>
我想了會,理理思路:
這錯誤是在重新整理頁面時產生的,頁面重新整理的過程就是舊頁面的消亡和新頁面的過載。理論上過載新頁面不會有什麼問題,那麼錯誤就是產生在舊頁面消亡前的“善後”工作中。我只要在頁面消亡前將flash內部這個回撥函式重寫,就能達到同樣的目的,程式碼如下,測試通過。
/*解決視訊切換內部指令碼錯誤*/
<script type="text/javascript">
function endcall(){var s=function(){__flash__removeCallback=function(i,n){if(i)i[n]=null;};window.setTimeout(s,10);};s();}
window.onbeforeunload = endcall;
</script>