这是一只只能在Mobile下使用的Video自定义组件。

为什么只能在Mobile下使用?。。。因为我将鼠标事件都换成了Touch事件。。。等我有空了再添加兼容手势库吧。

Talk is cheak, show you the code. 直接上代码:

JS组件代码:

/**
 * video插件Mobile版(只兼容mobile)
 * @params: options对象,属性如下:
 *     ele   {String/jQuery DOM/Javascript DOM}   video元素(可直接在该元素中定义<video>标签的原生属性,加上'data-'前缀)(必选填
 *     controls    {Boolean}    是否带controls
 *     autoplay    {Boolean}    是否自动播放
 *     src    {String}    视频资源地址
 *     preload    {String}    是否预载资源

 * @return: 
 *    1) 当options.ele仅有一个DOM时,返回new Video()对象;
 *    2) 当options.ele有多个DOM时,返回[new Video(), ...]数组。
 * 
 *    备注: new Video()对象的具体属性和方法可以查看以下代码。

 * @使用方法:
 *    JS:    Video.create(options);
 *    HTML:    <div class="video-box" data-autoplay='true' data-control='true' data-preload='auto' data-src=''></div>
 */
var Video = function(options) {
    this.videoBox = $(options.ele);
    this.options = options;
};

Video.prototype = {
    constructor: Video,
    // 构建DOM
    init: function() {
        // 设置videoBox样式
        this.videoBox.css({position: 'relative', 'overflow': 'hidden'});

        this.video.volume = 1;
        this.setSlidebarProgress('.slidebar-volume', 1);
        this.isHideControl = false;
        this.hideControlTimer = null;
        this.isPlaying = false;
        // 自动播放
        if(this.isAutoPlay === 'true' || this.hasControl == 'false') {
            this.play();
        } else {
            this.showControl();
        }
    },
    // duration change
    durationChange: function() {
        var _this = this;
        this.video.addEventListener('durationchange', function() {
            _this.setProgressTime(_this.video.currentTime, _this.video.duration);
            _this.setVideoSize();
        }, false);
    },
    // 设置video的宽高
    setVideoSize: function() {
        var videoBox = this.videoBox;
        var videoBoxWidth = videoBox.width();
        var videoHeight = this.video.videoHeight;
        var videoWidth = this.video.videoWidth;
        var videoBoxHeight = videoBoxWidth / videoWidth * videoHeight;
        videoBox.height(videoBoxHeight);
    },
    // 创建video DOM
    createVideoDom: function() {
        var _this = this;
        var videoBox = this.videoBox;
        var options = this.options;
        this.hasControl = options.controls || videoBox.attr('data-control');
        this.isAutoPlay = options.autoplay || videoBox.attr('data-autoplay');
        this.src = options.src || videoBox.attr('data-src');
        this.preload = options.preload || videoBox.attr('data-preload');
        var videoAttr = {
            src: _this.src,
            'webkit-playsinline': true,
            playsinline: true,
            preload: _this.preload
        };
        var videoDom = $('<video></video>').attr(videoAttr);
        this.videoBox.append(videoDom);

        this.video = this.videoBox.find('video')[0];
    },
    // 创建control DOM
    createControlDom: function() {
        var controlDom = '<div class="video-control">'
                            + '<div class="btn-play video-btn"></div>'
                            + '<span class="text-time"></span>'
                            + '<div class="slidebar slidebar-progress">'
                                + '<div class="btn-thumb"></div>'
                                + '<div class="line-runway"></div>'
                            + '</div>'
                            + '<div class="btn-muted video-btn"></div>'
                            + '<div class="slidebar slidebar-volume">'
                                + '<div class="btn-thumb"></div>'
                                + '<div class="line-runway"></div>'
                            + '</div>'
                            + '<div class="btn-fullpage video-btn"></div>'
                        + '</div>';

        this.videoBox.append(controlDom);
    },
    // 播放
    play: function() {
        if(this.video.paused) {
            var _this = this;
            this.video.play();
            this.isPlaying = true;
            this.videoBox.find('.btn-play').addClass('active');
        }
    },
    // 暂停
    pause: function() {
        if(!this.video.paused) {
            this.video.pause();
            this.isPlaying = false;
            this.videoBox.find('.btn-play').removeClass('active');
        }
    },
    // 显示controls
    showControl: function(isShowAlways) {
        var _this = this;
        if(this.hasControl !=='false') {
            this.isHideControl = false;
            this.videoBox.find('.video-control').addClass('active');
        }

        if(_this.hideControlTimer) {
            clearTimeout(_this.hideControlTimer);
            _this.hideControlTimer = null;
        }
        if(!isShowAlways && this.isPlaying) {
            this.hideControlTimer = setTimeout(function() {
                _this.hideControl();
            }, 2000);
        }
    },
    hideControl: function() {
        this.isHideControl = true;
        this.videoBox.find('.video-control').removeClass('active');
    },
    // video点击事件绑定
    videoClickHandler: function() {
        var _this = this;
        this.video.addEventListener('touchstart', function() {
            _this.showControl();
        }, false);

        this.videoBox.on('touchmove', '.video-control', function() {
            _this.showControl();
        });
    },
    // 播放与暂停事件切换
    playPause: function() {
        if(this.video.paused) {
            this.play();
        } else {
            this.pause();
        }
    },
    // 切换静音模式
    toggleMuted: function() {
        var _this = this;
        var video = this.video;
        this.video.muted = !video.muted;
        var ratio = 0;
        var mutedBtn = this.videoBox.find('.btn-muted');
        if(this.video.muted) {
            ratio = 0;
            mutedBtn.addClass('active');
        } else {
            var ratio = _this.video.volume || 0;
            mutedBtn.removeClass('active');
        }
        this.setSlidebarProgress('.slidebar-volume', ratio);
    },
    // 设置视频播放时间
    setProgressTime: function(currentTime, duration) {
        var textTimeDom = this.videoBox.find('.text-time');
        var duration = duration || this.video.duration;
        var currentTime = currentTime || 0;
        var timeString = this.formatTime(currentTime) + '/' + this.formatTime(duration);
        textTimeDom.html(timeString);
    },
    // 时间格式化: 00:00
    formatTime: function(second) {
        var timeString = '';
        var min = Math.floor(second / 60) || 0;
        var sec = Math.floor(second % 60) || 0;
        min = min >= 10 ? min :  '0' + min;
        sec = sec >= 10 ? sec :  '0' + sec;
        timeString = min + ':' + sec;
        return timeString;
    },
    // 正在播放的事件绑定
    playing: function() {
        var _this = this;
        this.video.addEventListener('timeupdate', function() {
            var ratio = _this.video.currentTime / _this.video.duration || 0;
            _this.setSlidebarProgress('.slidebar-progress', ratio);
            _this.setProgressTime(_this.video.currentTime);
        }, false);
    },
    // slide滑动事件绑定
    bindEventToSlide: function(slidebarClassName, callbackOpt) {
        var _this = this;
        var isTouchStart = false;
        var slidebar = this.videoBox.find(slidebarClassName);
        var slidebarThumb = slidebar.find('.btn-thumb');
        var slidebarThumbWidth = slidebarThumb.width();
        var slidebarWidth = slidebar.width();
        var slidebarOffsetLeft = slidebar.offset().left;
        var ratio;
        var touchstartCb = callbackOpt.touchstart;
        var touchmoveCb = callbackOpt.touchmove;
        var touchendCb = callbackOpt.touchend;
        var clickCb = callbackOpt.click;

        this.videoBox.on('touchstart', slidebarClassName + ' .btn-thumb', function(e) {
            e.preventDefault();
            // e.stopPropagation();
            isTouchStart = true;
            slidebarThumb.addClass('active');
            if(typeof touchstartCb == 'function') {
                touchstartCb();
            }
        }).on('touchmove', slidebarClassName + ' .btn-thumb', function(e) {
            e.preventDefault();
            // e.stopPropagation();
            if(isTouchStart) {
                var curTouchX = e.touches[0].pageX;
                ratio = (curTouchX - slidebarOffsetLeft - slidebarThumbWidth / 2) / slidebarWidth;
                if(ratio >= 1) {
                    ratio = 1;
                } else if(ratio <= 0) {
                    ratio = 0;
                }
                _this.setSlidebarProgress(slidebarClassName, ratio);

                if(typeof touchmoveCb == 'function') {
                    touchmoveCb(ratio);
                }
            }
        }).on('touchend', slidebarClassName + ' .btn-thumb', function(e) {
            e.preventDefault();
            // e.stopPropagation();
            if(isTouchStart) {
                isTouchStart = false;
                slidebarThumb.removeClass('active');

                if(typeof touchendCb == 'function') {
                    touchendCb(ratio);
                    _this.showControl();
                }
            }
        }).on('touchstart', slidebarClassName, function(e) {
            e.preventDefault();
            // e.stopPropagation();
            var curTouchX = e.touches[0].pageX;
            ratio = (curTouchX - slidebarOffsetLeft - slidebarThumbWidth / 2) / slidebarWidth;
            if(ratio >= 1) {
                ratio = 1;
            } else if(ratio <= 0) {
                ratio = 0;
            }
            _this.setSlidebarProgress(slidebarClassName, ratio);

            if(typeof clickCb == 'function') {
                clickCb(ratio);
            } else if(touchmoveCb == 'function') {
                touchmoveCb(ratio);
            }
        });
    },
    // 设置进度条显示
    setSlidebarProgress: function(slidebarClassName, ratio) {
        var slidebar = this.videoBox.find(slidebarClassName);
        var slidebarThumb = slidebar.find('.btn-thumb');
        var slidebarRunway = slidebar.find('.line-runway');
        var slidebarThumbWidth = slidebarThumb.width();
        var slidebarWidth = slidebar.width();
        var slidebarWidthRatio = (slidebarWidth - slidebarThumbWidth / 2) / slidebarWidth;

        var percent = Math.ceil(ratio * slidebarWidthRatio * 100) + '%';
        slidebarThumb.css('left', percent);
        slidebarRunway.width(percent);
    },
    // 播放进度条事件绑定
    bindEventToProgressSlidebar: function() {
        var _this = this;
        this.bindEventToSlide('.slidebar-progress', {
            touchmove: function(ratio) {
                _this.video.currentTime = _this.video.duration * ratio || 0;
                _this.pause();
            },
            touchend: function(ratio) {
                _this.play();
            },
            click: function(ratio) {
                _this.video.currentTime = _this.video.duration * ratio || 0;
                _this.play();
            }
        });
    },
    // 音量进度条事件绑定
    bindEventToVolumeSlidebar: function() {
        var _this = this;
        this.bindEventToSlide('.slidebar-volume', {
            touchmove: function(ratio) {
                _this.video.volume = ratio || 0;
            },
            click: function(ratio) {
                _this.video.volume = ratio || 0;
            }
        });
    },
    // 音量变化事件监听
    volumeChange: function() {
        var _this = this;
        var mutedBtn = this.videoBox.find('.btn-muted');
        this.video.addEventListener('volumechange', function() {
            if(_this.video.volume == 0 || _this.video.muted) {
                mutedBtn.addClass('active');
            } else {
                mutedBtn.removeClass('active');
            }
        }, false);
    },
    // 切换全屏
    toggleFullPage: function() {
        this.requestFullscreen(this.video);
    },
    requestFullscreen: function(element) {
        if(element.requestFullScreen) {  
            element.requestFullScreen();
        } else if(element.mozRequestFullScreen) {  
            element.mozRequestFullScreen();  
        } else if(element.webkitRequestFullScreen) {  
            element.webkitRequestFullScreen();  
        }
    },
    // 创建DOM
    createDom: function() {
        this.createVideoDom();
        this.createControlDom();
    },
    // 绑定事件到control
    bindEventToControl: function() {
        var _this = this;
        // 播放 / 暂停
        this.videoBox.on('touchstart', '.btn-play', function(e) {
            e.stopPropagation();
            e.preventDefault();
            _this.playPause();
            if(_this.isPlaying) {
                _this.showControl();
            } else {
                _this.showControl(true);
            }
        });

        // 静音
        this.videoBox.on('touchstart', '.btn-muted', function() {
            _this.toggleMuted();
        });

        // 全屏
        this.videoBox.on('touchstart', '.btn-fullpage', function() {
            _this.toggleFullPage();
        });

        this.durationChange(); // 总时间 change
        this.volumeChange(); // 音量 change
        this.bindEventToProgressSlidebar(); // 进度条slide change
        this.bindEventToVolumeSlidebar(); // 音量slide change
        this.videoClickHandler(); // video点击事件
        this.playing(); // 正在播放的事件监听
    },
    render: function() {
        this.createDom();
        this.init();
        this.bindEventToControl();
    }
};

// 创建Video对象
Video.create = function(options) {
    var ele = $(options.ele);
    if(ele.length == 1) {
        var video = new Video(options);
        video.render();
        return video;
    } else if (ele.length > 1) {
        // 当ele为多元素时,遍历创建多个变量
        var videoArr = [];
        ele.each(function(index, element) {
            var video = new Video(options);
            video.videoBox = $(element);
            video.render();
            videoArr.push(video);
        });
        return videoArr;
    }
};

HTML代码:

<div class="video-box" data-autoplay='true' data-control='true' data-preload='auto' data-src='https://nie.res.netease.com/r/video/20161223/56db4506-c848-452d-8168-34eed9f84f32.mp4'></div>

JS使用代码:

Video.create({
    ele: '.video-box'
});

CSS代码:

video { display: inline-block; width: 100%;}
.video-control { position: absolute; display: -webkit-flex; display: flexbox; display: flex; height: 16px; width: 100%; left: 0; bottom: -1px; padding: 7px 1px; background: rgba(240, 240, 240, 1); opacity: 0; transform: translateY(40px); transition: all .5s;}
.video-control.active {opacity: 1; transform: translateY(0);}
.video-control .text-time {width: 65px; margin: 0 5px; font-size: 12px; line-height: 18px; color: #666666;}
.video-control .video-btn { display: inline-block; width: 16px; height: 16px; background: url(sprites-video.png) no-repeat;}
.video-control .btn-play { margin-left: 10px; background-position: 0 -32px;}
.video-control .btn-play.active { background-position: 0 -16px;}
.video-control .btn-muted {margin-left: 10px; background-position: 0 -64px;}
.video-control .btn-muted.active {background-position: 0 -48px;}
.video-control .btn-fullpage {margin: 0 10px; background-position: 0 0;}
.video-control .slidebar-progress {flex: 3;}
.video-control .slidebar-volume {flex: 1;}
.video-control .slidebar {position: relative; display: inline-block; margin: 7px 10px; height: 2px; background: rgba(66, 133, 244, .5); border-radius: 1px;}
.video-control .slidebar .btn-thumb {position: absolute; width: 12px; height: 12px; top: 50%; margin-top: -6px; border-radius: 50%; background: #4285f4; z-index: 2;}
.video-control .slidebar .btn-thumb.active {transform: scale3d(1.4, 1.4, 1);}
.video-control .slidebar .line-runway {position: absolute; width: 0; height: 2px; background: #4285f4; border-radius: 1px; z-index: 1;}

效果:

本文作者:子匠_Zijor,转载请注明出处:http://www.dengzhr.com/js/1275