TypeScript封装video播放器组件

TypeScript 封装 video 播放器组件

通过之前对 TypeScript 的学习,今天我们用它封装一个播放器组件,希望大家喜欢,最后我会放上 GitHub 地址,需要的话可以下载下来学习。

Popup 弹层组件开发

主要是 Popup 弹层组件框架搭建、模块化、弹层布局结构及样式、遮罩层布局及样式、弹层交互及弹层容器回调实现。

// import './popup.css'; // 全局 css 操作
let styles = require('./popup.css');
// import styles from './popup.css'

interface Ipopup {
    width? : string;
    height? : string;
    title? : string;
    pos? : string;
    mask? : boolean;
    content? : (content : HTMLElement) => void;
}

interface Icomponent {
    tempContainer : HTMLElement;
    init : () => void;
    template : () => void;
    handle : () => void;
}

function popup(options : Ipopup) {
    return new Popup(options);
}

class Popup implements Icomponent{
    tempContainer;
    mask;
    constructor(private settings : Ipopup) {
        this.settings = Object.assign({
            width: '100%',
            height: '100%',
            title: '',
            pos : 'center', // 弹窗位置 left right center
            mask: true, // 是否显示遮罩
            content: function(){}
        },this.settings);
        this.init();
    }
    // 初始化
    init(){
        this.template();
        this.settings.mask && this.createMask();
        this.handle();
        this.contentCallback();
    }
    // 创建模板'
    template(){
        this.tempContainer = document.createElement('div');
        this.tempContainer.style.width = this.settings.width;
        this.tempContainer.style.height = this.settings.height;
        this.tempContainer.className = styles.popup;
        this.tempContainer.innerHTML = `
            <div class="${styles['popup-title']}">
                <h3>${ this.settings.title }</h3>
                <i class="iconfont icon-baseline-close-px"></i>
            </div>
            <div class="${styles['popup-content']}"></div>
        `;
        document.body.appendChild(this.tempContainer);
        if (this.settings.pos === 'left') {
            this.tempContainer.style.left = 0;
            this.tempContainer.style.top = (window.innerHeight - this.tempContainer.offsetHeight) + 'px';
        } else if (this.settings.pos === 'right') {
            this.tempContainer.style.right = 0;
            this.tempContainer.style.top = (window.innerHeight - this.tempContainer.offsetHeight)/2 + 'px';
        } else {
            this.tempContainer.style.left = (window.innerWidth - this.tempContainer.offsetWidth)/2 + 'px';
            this.tempContainer.style.top = (window.innerHeight - this.tempContainer.offsetHeight)/2 + 'px';
        }
    }
    // 事件操作
    handle(){
        let popupClose = this.tempContainer.querySelector(`.${styles['popup-title']} i`);
        popupClose.addEventListener('click',() => {
            document.body.removeChild(this.tempContainer);
            this.settings.mask && document.body.removeChild(this.mask);
        });
    }
    createMask () {
        this.mask = document.createElement('div');
        this.mask.className = styles.mask;
        this.mask.style.width = '100%';
        this.mask.style.height = document.body.offsetHeight + 'px';
        document.body.appendChild(this.mask);
    }
    contentCallback () {
        let popupContent = this.tempContainer.querySelector(`.${styles['popup-content']}`);
        this.settings.content(popupContent);
    }
}

export default popup;

弹出层中的 Video 播放器组件开发

主要包含组件框架搭建、播放器布局结构、播放与暂停的实现、当前时间与总时间计算、全屏功能、播放进度条、拖拽播放进度条与音量进度条、配置自动播放等功能的实现。

let styles = require('./video.css');

interface Ivideo {
    url : string;
    elem : string | HTMLElement;
    width? : string;
    height? : string;
    autoplay? : boolean;
}

interface Icomponent {
    tempContainer : HTMLElement;
    init : () => void;
    template : () => void;
    handle : () => void;
}

function video(options: Ivideo) {
    return new Video(options);
}

class Video implements Icomponent {
    tempContainer
    constructor(private settings : Ivideo){
        this.settings = Object.assign({
            width: '100%',
            height : '100%',
            autoplay : false
        },this.settings);
        this.init();
    }
    init () {
        this.template();
        this.handle();
    }
    template () {
        this.tempContainer = document.createElement('div');
        this.tempContainer.className = styles.video;
        this.tempContainer.style.width = this.settings.width;
        this.tempContainer.style.height = this.settings.height;
        this.tempContainer.innerHTML =`
            <video class="${styles['video-content']}" src="${this.settings.url}"></video>
            <div class="${styles['video-controls']}">
                <div class="${styles['video-progress']}">
                    <div class="${styles['video-progress-now']}"></div>
                    <div class="${styles['video-progress-suc']}"></div>
                    <div class="${styles['video-progress-bar']}"></div>
                </div>
                <div class="${styles['video-play']}">
                    <i class="iconfont icon-icon_play"></i>
                </div>
                <div class="${styles['video-time']}">
                    <span>00:00</span> / <span>00:00</span>
                </div>
                <div class="${styles['video-full']}">
                    <i class="iconfont icon-full-screen"></i>
                </div>
                <div class="${styles['video-volume']}">
                    <i class="iconfont icon-yinliang"></i>
                    <div class="${styles['video-volprogress']}">
                        <div class="${styles['video-volprogress-now']}"></div>
                        <div class="${styles['video-volprogress-bar']}"></div>
                    </div>
                </div>
            </div>
        `;
        if(typeof this.settings.elem === 'object') {
            this.settings.elem.appendChild(this.tempContainer);
        }else {
            document.querySelector(`${this.settings.elem}`).appendChild(this.tempContainer);
        }
    }
    handle () {
        let videoContent:HTMLVideoElement = this.tempContainer.querySelector(`.${styles['video-content']}`);
        let videoControls = this.tempContainer.querySelector(`.${styles['video-controls']}`);
        let videoPlay = this.tempContainer.querySelector(`.${styles['video-controls']} i`);
        let videoTimes = this.tempContainer.querySelectorAll(`.${styles['video-time']} span`);
        let videoFull = this.tempContainer.querySelector(`.${styles['video-full']} i`);
        let videoProgress = this.tempContainer.querySelectorAll(`.${styles['video-progress']} div`);
        let videoVolProgress = this.tempContainer.querySelectorAll(`.${styles['video-volprogress']} div`);
        let timer;

        videoContent.volume = 0.5;
        if(this.settings.autoplay){ // 是否进行自动播放处理
            timer = setInterval(playing,1000);
            videoContent.play();
        }

        this.tempContainer.addEventListener('mouseenter',function(){
            videoControls.style.bottom = 0;
        });
        this.tempContainer.addEventListener('mouseleave',function(){
            videoControls.style.bottom = '-50px';
        })
        // 视频是否加载完毕
        videoContent.addEventListener('canplay',() => {
            // console.log(videoTimes[1]);
            videoTimes[1].innerHTML = formatTime(videoContent.duration);
        });
        // 视频播放事件
        videoContent.addEventListener('play',() => {
            videoPlay.className = 'iconfont icon-ziyuan';
            timer = setInterval(playing,1000);
        });
        // 视频暂停事件
        videoContent.addEventListener('pause',() => {
            videoPlay.className = 'iconfont icon-icon_play'
            clearInterval(timer);
        });
        // 播放暂停
        videoPlay.addEventListener('click',()=>{
            if(videoContent.paused){
                videoContent.play();
            }else{
                videoContent.pause();
            }
        });
        // 全屏
        videoFull.addEventListener('click',()=>{
            videoContent.requestFullscreen();
        });
        // 视频进度条拖拽事件
        videoProgress[2].addEventListener('mousedown',function(ev:MouseEvent){
            let downX = ev.pageX;
            let downL = this.offsetLeft;
            document.onmousemove = (ev:MouseEvent) => {
                let scale = (ev.pageX - downX + downL + 8) / this.parentNode.offsetWidth;
                if (scale < 0){
                    scale = 0;
                } else if (scale > 1) {
                    scale = 1;
                }
                videoProgress[0].style.width = scale * 100 + '%';
                videoProgress[1].style.width = scale * 100 + '%';
                this.style.left = scale * 100 + '%';
                videoContent.currentTime = scale * videoContent.duration;
            };
            document.onmouseup = () => {
                document.onmousemove = document.onmouseup = null;
            };
            ev.preventDefault();
        })
        // 音量控制
        videoVolProgress[1].addEventListener('mousedown',function(ev:MouseEvent){
            let downX = ev.pageX;
            let downL = this.offsetLeft;
            document.onmousemove = (ev:MouseEvent) => {
                let scale = (ev.pageX - downX + downL + 8) / this.parentNode.offsetWidth;
                if (scale < 0){
                    scale = 0;
                } else if (scale > 1) {
                    scale = 1;
                }
                videoVolProgress[0].style.width = scale * 100 + '%';
                this.style.left = scale * 100 + '%';
                videoContent.volume = scale;
            };
            document.onmouseup = () => {
                document.onmousemove = document.onmouseup = null;
            };
            ev.preventDefault();
        })

        function playing() { // 正在播放中
            let scale = videoContent.currentTime / videoContent.duration;
            let scaleSuc = videoContent.buffered.end(0) / videoContent.duration;
            videoTimes[0].innerHTML = formatTime(videoContent.currentTime);
            videoProgress[0].style.width = scale * 100 + '%';
            videoProgress[1].style.width = scaleSuc * 100 + '%';
            videoProgress[2].style.left = scale * 100 + '%';
        }
        // 格式化时间 时分秒
        function formatTime(number:number):string {
            number = Math.round(number);
            let min = Math.floor(number/60);
            let sec = number%60;
            return setZero(min) + ':' + setZero(sec);
        }
        // 当时间出现出现个位时,补 0 操作
        function setZero(number:number):string{
            if(number<10){
                return '0' + number;
            }else{
                return '' + number;
            }
        }
    }
}

export default video;

源码下载GitHub

「点点赞赏,手留余香」

0

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
码云笔记 » TypeScript封装video播放器组件

发表回复