video標籤製作簡易版彈幕視訊

大猿猴發表於2018-08-03

認識兩個HTML5標籤,分別是video和source。

video標籤屬性

  • autoplay:表示視訊是否就緒後馬上播放,值為autoplay
  • controls:表示是否向使用者顯示控制元件,值為controls
  • height:表示視訊播放器高度
  • width:表示視訊播放器寬度
  • loop:表示當媒介檔案完成播放後是否再次開始播放,值為loop
  • preload:表示視訊是否在頁面載入時進行載入,並預備播放,若使用autoplay,則忽略該屬性,值為preload
  • poster:指定視訊載入時顯示的圖片url
  • src:指定要播放的視訊url

source標籤屬性

  • src:指定要連結的媒介資源URL
  • type:表示資源的MIME型別。比如在video標籤中支援型別有video/mp4、video/ogg和video/webm

如何製作一個簡易版彈幕視訊?

  • HTML部分

    內容分為螢幕層和彈幕層,螢幕層由視訊、輸入框和按鈕組成,比較簡單。

      <!--螢幕層-->
      <div class="screen">
          <!--視訊-->
          <video class="screen-video" autoplay loop>
              <source src="./video/happy.mp4" type="video/mp4">
              您的瀏覽器不支援 video 標籤。
          </video>
          <!--輸入框-->
          <input type="text" class="screen-input">
          <!--傳送按鈕-->
          <input type="button" value="傳送" class="screen-button" onclick="send()">
      </div>
      <!--彈幕層-->
      <div class="barrage"></div>
    複製程式碼
  • CSS部分

    佈局結合百分比佈局和REM佈局,使網頁響應式,體驗稍好。

      .screen-video {    
          width:80%;
          margin: 1rem 10%;
          border: 1px solid white; 
          
          /*填充父元素,IE和Edge不支援,真頭疼!!!*/
          object-fit: fill;      
      }
      
      .screen-input {
          position: absolute;
          left:10%;
      
          height: 1.5rem;
      
          line-height: 1.5rem;
          font-size: 1rem;
      }
      
      .screen-button {
          position: absolute;
          right: 10%;
      
          height: 1.5rem;
      
          line-height: 1.5rem;
          letter-spacing: 0.2em;
          font-size: 0.8rem;
      
          cursor: pointer;
      }
      
      .barrage {
          position: absolute;
          left:10%;
      
          width: 80%;
          
          /*x軸方向上超過則隱藏內容*/
          overflow-x: hidden;
          
          z-index: 999;
      }
    複製程式碼
  • JavaScript部分

    第一步,設定事件監聽

      //視窗載入時初始化
      window.addEventListener("load",init,false);
      //視窗大小變化時重新初始化
      window.addEventListener("resize",init,false);
      //輸入框回車時傳送彈幕文字
      content.addEventListener("keyup",function(event) {
          var e = event||window.event;
          if (e.which == "13"|| e.keyCode =="13") {
              send();
          }
      },false);
    複製程式碼

    第二步,事件處理

    • 初始化

       function init(){
       
          // 實現REM佈局需要根據視窗大小來控制根字型大小
          // 瀏覽器預設字型大小是16px,最小字型是12px
          html.style.fontSize = parseInt(doc.clientWidth /45)+"px";
          if(parseInt(html.style.fontSize)<12){
              html.style.fontSize = "12px";
          }
      
          //設定video的高度
          video.style.height =  parseInt(video.offsetWidth/16*9)+"px";
          //設定input的寬度
          content.style.width = parseInt(video.offsetWidth - btn_send.offsetWidth)+"px";
          //設定button的位置
          btn_send.style.top = (video.offsetHeight + video.offsetTop *2)+"px";
          //設定barrage的位置和高度
          barrage.style.top =video.offsetTop +"px";
          barrage.style.height = video.offsetHeight +"px"; 
      }
      複製程式碼

      以前通過獲取樣式物件進行初始化,如下,

       var sstyle = screen.currentStyle||window.getComputedStyle(screen);
       var vstyle = video.currentStyle||window.getComputedStyle(video);
      複製程式碼

      之後放棄使用這種方式,一是有相容性,比如獲取margin,在Chrome和FF正常,但是到了IE和FF則不支援了,獲取marginTop、marginLeft等則正常,雖然可以解決,但是為了這點問題,折騰半天,實在沒必要。二是JS需要關注CSS是否應用了該樣式,如果沒有,那麼獲取的是預設值,比如margin預設值是auto,但是我想獲取具體的數值,這就不好處理了。總之,涉及BOM操作的還是少用比較好。

    • 傳送彈幕內容

      function send() {
          //傳送內容
          var val = trim(content.value);
          //建立的節點
          var span;
          //偏移量
          var offset = 0;
          //幀ID
          var id;
          if (val != "") {
              //建立節點
              span = document.createElement("span");
              //設定文字
              span.innerHTML = val;
              //設定樣式
              span.className = "barrage-span";
              //新增
              barrage.appendChild(span);
              //設定初始位置,注意新增元素後寬度和高度才生效。
              span.style.top = getRandomNumber(parseInt(video.offsetHeight-span.offsetHeight)) + "px";
              span.style.left =  video.offsetWidth+"px";
              span.style.color = getRandomColor();
              //設定監聽事件
              span.addEventListener("mouseover", stop, false);
              span.addEventListener("mouseout", scroll, false);
              //預設初始文字滾動
              scroll();
          }
          content.value = "";
          
          function scroll() {
      
              offset += 2;
      
              span.style.transform = "translateX(-" + offset + "px)";
              span.style.transition = "transform 0s linear";
      
              if (offset >= parseInt(video.offsetWidth+span.offsetWidth)) {
                  stop();
                  barrage.removeChild(span);
              }else{    
                  id = window.requestAnimationFrame(scroll);
              }  
          }
      
          function stop(){
              window.cancelAnimationFrame(id);
          }
      
          //去除兩邊空格
          function trim(s) {
              return s.replace(/(^\s*)|(\s*$)/g, "");
          }
      
          //指定範圍內獲取隨機數
          function getRandomNumber(value) {
              return parseInt(Math.random() * value);
          }
      
          //獲取任意顏色
          function getRandomColor() {
              var color = "#";
              var j;
              for (var i = 0; i < 6; i++) {
                  j = getRandomNumber(16);
                  color += str.substring(j, j + 1);
              }
              return color;
          }
      }
      複製程式碼

      在處理髮送彈幕時,發現文字不時會超出彈幕層,從而出現滾動條,結果發現是下面這句程式碼出現了問題,

      span.style.top = getRandomNumber(parseInt(video.offsetHeight-span.offsetHeight)) + "px";
      複製程式碼

      span.offsetHeight列印結果總為0,後來把這句程式碼放在父元素新增span元素之後,即下面這句程式碼就可以了。這說明了要使元素的offsetWidth、offsetHeight等屬性值生效,需要注意元素是否已經渲染到瀏覽器上,單單建立一個元素物件,但是沒有新增到文件中,只是存放在記憶體,還沒有被瀏覽器渲染。先記錄下來,避免以後填坑,哈哈。

      barrage.appendChild(span);
      複製程式碼

附上原始碼:

https://github.com/muzhidong/frontend-demo/tree/master/barrage-video  
複製程式碼

相關文章