video.js 사용과 DOM 조작, CSS 설정 정리글

soo's·2023년 8월 16일
2

TIL

목록 보기
49/53

1. Video.js

video.js는 HTML5 기반의 웹 비디오 플레이어를 생성 및 사용할 수 있게 하는 라이브러리이다.

1-1. video player 생성 과정

HTML 요소 생성

<video ref={videoRef} className="video-js" playsInline>
	<track label={"자막"} kind={"captions"} srcLang={"kr"} src={subtitle} default />
</video>

Player 초기화 및 생성

const player = (playerRef.current = videojs(videoElement as HTMLVideoElement, options, () => {
        onReady && onReady(player);
				// player 실행시 동작시킬 부분
}));
  1. videojs()를 사용하여 player를 초기화 및 생성할 수 있다. 함수의 첫 번째 인자로 video ****element를, 두 번째 인자로 해당 **video player의 **option 객체를, 마지막 인자로 해당 player가 준비되었을 때 호출할 callback 함수를 작성한다.

  2. 위 코드는 변수 playerplayer.current 에 video player를 할당하여, player 변수로 직접video player를 조작하거나 player.current로 다른 곳에서도 동일한 player 인스턴스에 접근하기 위해 chained assignment 를 사용했다.

  3. 두번째 인자인 option 객체는 아래와 같은 형태로 커스텀 하여 사용할 수 있다.

    • option custom 예시 코드
      {
          autoplay: true,                    // 자동 재생 설정
          controls: true,                    // 플레이어 컨트롤 표시 설정
          crossOrigin: "anonymous",          // 교차 출처 리소스 공유 설정
          responsive: true,                  // 반응형 플레이어 설정
          fluid: true,                       // 컨테이너 크기에 맞게 플레이어 크기 조절
          playbackRates: [2, 1.5, 1.25, 1, 0.75, 0.5],  // 사용 가능한 재생 속도 옵션
          touchEnabled: true,                // 터치 이벤트 활성화 설정
          controlBar: {                      // 컨트롤 바 설정
            playToggle: true,                // 재생/일시정지 토글 버튼 활성화
            remainingTimeDisplay: true,      // 남은 시간 표시 활성화
            progressControl: true,           // 진행률 컨트롤 활성화
            pictureInPictureToggle: true,    // 화면 내 화면(PiP) 토글 버튼 활성화
            currentTimeDisplay: true,        // 현재 재생 시간 표시 활성화
            fullscreenToggle: !isIOS,        // 전체화면 토글 버튼 활성화 (iOS가 아닐 경우)
            qualitySelector: true,           // 화질 선택 컨트롤 활성화
          },
          plugins: {                         // 사용할 플러그인 설정
            // ...
          },
          poster: thumbnailUrl,              // 비디오 썸네일 URL
          sources: [{ src: videoUrl }],      // 비디오 소스 URL
      };
      
      **// 구체적인 옵션은 https://videojs.com/guides/options/ 에서 확인 가능 🔎**

메서드와 이벤트 리스너 사용

player를 초기화 및 생성한 후에는 메서드를 통해 player를 조작할 수 있다.

player.play(); // 재생
player.puase(); // 정지

혹은 이벤트 리스너를 연결하여 player를 조작할 수 있다.

player.on('play', function() {
  console.log('플레이어가 재생됨~');
});
// on 메서드를 사용하여 이벤트 리스너를 연결하여 'play' 이벤트 발생시 callback 실행


2. DOM 조작

비디오 플레이어의 옵션을 변경해야 하는 경우 (ex: 컨트롤 바 요소 생성 및 추가, 삭제 등의 작업)

DOM을 조작하여 player를 custom 할 수 있다.

DOM을 조작하는 방법은 다양하지만 크게 두 가지 방법으로 정리하겠다.

❶  querySelector로 element 선택 → element의 method 이용

// 예시 - insertAdjacentHTML 메서드로 새로운 element 추가

const somebtn = player.el().querySelector(".somebtn");
const qualityWrapHTML = `
	<div class="qulity-Wrap">
		<button>
			화질 버튼
		</button>
	</div>
	`
somebtn.insertAdjacentHTML("beforeend", qualityWrapHTML);

위 코드는 특정 버튼 element를 querySelector를 사용하여 변수에 할당하고
html 태그를 문자열로 만들어서 insertAdjacentHTML 메서드를 사용하여 텍스트를 HTML 파싱하여 DOM에 추가한다.

player의 instance 선택 → instance의 method 이용

// 예시 - player의 controlBar 인스턴스에 접근하고 해당 인스턴스의 addChild 메서드로 element 추가

if (!player.controlBar.getChild("iosFullscreenCustomButton")) {
  player.controlBar.addChild("button", {
    name: "iosFullscreenCustomButton",
    text: "전체 화면",
    className: "vjs-custom-button-IOS",
  });
}			
	
let iosFullscreenCustomButton: any = player.el().querySelector(".vjs-custom-button-IOS");						
iosFullscreenCustomButton?.addEventListener("touchstart", function () {
	setIsFullscreenValue((prev) => !prev);
});

위 코드는 player의 contorlBar 인스턴스에 접근하여 `getChild` 메서드를 사용해서 "iosFullscreenCustomButton" 컴포넌트가 있는지 확인한다.
해당 컴포넌트가 없다면 `addChild` 메서드를 사용하여 새로운 element를 생성한다.
해당 element를 가지고 1번의 방법(querySelector와 element의 메서드 사용)을 이용해서 이벤트를 연결한다.

아래는 DOM을 조작하여 control-bar를 custom하는 추가적인 예시이다.

  • 예시 코드
// 1️⃣ **control bar의 배속 옵션의 텍스트 '1x'에서 '1배'로 수정**

// 1) querySelector로 조작할 element를 선택하여 할당한다.
const rateMenuButton = player.el().querySelector(".vjs-playback-rate .vjs-menu");

// 2) element의 innerText를 변경한다.
if (rateMenuButton) {
  var menuContentEl = rateMenuButton.querySelectorAll(".vjs-menu-item");
  menuContentEl.forEach(function (menuItem: any) {
    var textEl = menuItem.querySelector(".vjs-menu-item-text");
    if (textEl) {
      textEl.innerText = textEl.innerText.replace("x", "배");
    }
  });
}
    

// 2️⃣ **control bar의 ios용 전체 화면 커스텀 버튼 생성**

// 1) player의 fullscreenToggle 인스턴스의 el() 메서드로 element를 할당하여 dispaly를 조작한다. 
if (isIOS) {
  // ios일 때 전체 화면 토글 버튼 숨김
  if (player.controlBar && (player.controlBar as any).fullscreenToggle) {
    const fullscreenButton = (player.controlBar as any).fullscreenToggle.el();
    fullscreenButton.style.display = "none";
  }

// 2) player의 controlbar 인스턴스의 getChild() 메서드로 컴포넌트 확인 -> addChild() 메서드로 새로운 컴포넌트 생성 + 연결된 DOM element 생성
  // ios용 전체 화면 커스텀 버튼 생성
  if (!player.controlBar.getChild("iosFullscreenCustomButton")) {
    player.controlBar.addChild("button", {
      name: "iosFullscreenCustomButton",
      text: "전체 화면",
      className: "vjs-custom-button-IOS",
    });
  }
}

🔎 player의 controlBar 인스턴스 사용에 대한 보충 설명

video.js에서 videojs() 함수를 사용해서 player 인스턴스를 생성한다.

video.js는 component-based architecture를 가지기 때문에 컴포넌트 클래스를 이용해서 컴포넌트 인스턴스를 생성하는 것이다. 즉, controlBar와 같은 하위 컴포넌트(video.js가 생성하는 컴포넌트)들이 모여서 video player를 만드는 것이고 각각의 하위 컴포넌트들은 결과적으로 컴포넌트 클래스의 인스턴스(클래스로 만들어낸 객체)이기 때문에 점 표기법을 ****통해 하위 컴포넌트로 접근할 수 있게 된다.

예를 들어, player 인스턴스가 controlBar 라는 하위 컴포넌트로 구성되어 있고 controlBar 컴포넌트가 fullscreenToggle 이라는 하위 컴포넌트로 구성되었다면player.controlBar.fullscreenToggle 과 같이 해당 하위 컴포넌트에 접근할 수 있는 것이다.

예시 코드 2️⃣ control bar의 ios용 전체 화면 커스텀 버튼 생성 을 보면, 위와 같은 이유로 인해 player.controlBar.fullscreenToggle에 접근하고 해당 인스턴스의 el() 메서드를 사용해서 특정 element에 접근하여 커스텀 할 수 있는 것이다.



3. CSS 설정

video.js는 player에 대한 default style을 제공한다.

video.js/dist/video-js.css를 import 하여 default style 적용이 가능하다.

하지만 default style이 아닌 custom style 적용이 필요한 경우가 생길 수 있다.

따라서 video.js의 player를 스타일링하는 방법을 크게 두 가지로 정리하겠다.

❶ video.js가 제공하는 element의 classname 이용

video.js를 사용해서 player를 생성하면, 특정 classname을 가진 element들이 player 인스턴스를 이루게 된다. 커스텀 할 element의 특정 classname을 이용해서 새로운 스타일을 overriding 하면 된다.

.vjs-control-bar {
    background-color: #333;
}

이 코드는 video.js player의 `.vjs-control-bar`라는 클래스를 가진 요소의
배경색을 지정하여 기존 스타일(video.js/dist/video-js.css)을 overriding 하여 스타일을 적용한다.

이 방법은 기존 스타일 시트와 통합하여 사용 가능하기 때문에 간편하다.


❷ DOM 조작을 통한 style property 이용

player를 이루고 있는 요소 자체에 접근하여 style property를 이용해서 스타일링 한다.

const player = (playerRef.current = videojs(videoElement as HTMLVideoElement, options, () => {
	onReady && onReady(player);
	
	// style property 사용
	let volumeButton = player.el().querySelector(".vjs-volume-button");
	volumeButton.style.order = "999";
	volumeButton.style.background = "url('/mobile_assets/settingbtn.svg') no-repeat center / contain";
};

이 코드는 querySelector를 통해 스타일링을 설정할 element를 변수에 할당하고
style property를 사용해서 동적으로 스타일링을 적용한다.

이 방법은 JS 로직과 함께 사용 가능하기 때문에 동적으로 스타일링 적용이 필요할 때 유용하다.
하지만 이 방법을 사용할 때는 잠재적인 문제 예방을 위해, 반드시 video player가 초기화 및 생성된 후에 스타일링 해야한다.


❸ 참고할 부분

두 가지 방법은 각각의 장점이 있어서 정적인 스타일링에서는 1번 방법을, 동적 혹은 js 로직이 필요한 부분에서는 2번 방법을 사용하면 된다.

하지만 player의 특정 element의 경우 1번(classname 방법)이 적용되지 않는 문제가 있다.

이 부분은 선택자 특정화(더 구체적인 선택자로 스타일 적용 점수 높임), !important 키워드 사용, overriding할 style sheet의 import 순서 고려 등 다양한 방법을 시도했지만 적용되지 않았다.

결론적으로 Video.js가 run time에 JS를 사용해서 일부 스타일을 동적으로 적용하는 과정에서 스타일시트에 정의된 스타일이 재정의되었을 확률이 높다. 따라서 이런 경우에는 2번(DOM style property 방법)을 적용시켜 해결했다.

1개의 댓글

comment-user-thumbnail
2023년 8월 16일

개발자로서 배울 점이 많은 글이었습니다. 감사합니다.

답글 달기