overlay.js 3.09 KB
/**
 * Modal 覆盖层组件
 *
 * @author: Aiden Xu<aiden.xu@yoho.cn>
 * @date: 2016/07/18
 */

'use strict';

const $ = require('yoho-jquery');

const ANIMATIONS = {
    none: {
        in: 'overlay-in',
        out: 'overlay-out'
    },
    fade: {
        in: 'overlay-fade-in',
        out: 'overlay-fade-out'
    }
};

class Overlay {
    constructor(opts) {
        this.isVisible = false;

        // 默认参数
        this.defaults = {
            className: 'overlay',
            clickToClose: true, // 点击关闭
            onClose: $.noop,    // 关闭回调函数
            animation: 'fade',   // 动画效果
            disableScrolling: true // 是否禁止
        };

        // 初始化参数
        this.settings = Object.assign({}, this.defaults, opts);

        this.settings.animationClasses = {
            in: ANIMATIONS[this.settings.animation].in,
            out: ANIMATIONS[this.settings.animation].out
        };

        this.elem = $('<div/>', {
            class: this.settings.className
        });

        // 点击关闭
        this.elem.click(()=> {
            if (this.settings.clickToClose) {
                this.hide();
            }
        });

        if (this.settings.disableScrolling) {
            // 覆盖层出现时阻止滚动
            $(window).on('touchmove', (e)=> {
                if (this.isVisible) {
                    e.preventDefault();
                }
            });
        }
    }

    _clearStylesClasses() {
        this.elem
            .removeClass(this.settings.animationClasses.in)
            .removeClass(this.settings.animationClasses.out);
    }

    _cleanupListener() {
        this.elem.css({
            visibility: 'hidden'
        });
        this._clearStylesClasses();
        this.isVisible = false;
        this.elem.detach();

        // 一次性监听,动画完成事件触发后删除监听器
        this.elem[0].removeEventListener('webkitTransitionEnd', this._cleanupListener);
    }

    /**
     * 显示覆盖层
     */
    show() {
        if (this.elem.parent().length === 0 && !this.isVisible) {
            this.elem.appendTo('body');


            this._clearStylesClasses();
            this.elem.css({
                visibility: 'visible'
            }).show().addClass(this.settings.animationClasses.in);

            if (this.settings.disableScrolling) {
                $('body').css({
                    overflow: 'hidden'
                });
            }

            this.isVisible = true;
        }
    }

    /**
     * 关闭覆盖层
     */
    hide() {
        if (this.isVisible) {
            this._clearStylesClasses();

            this.elem[0].addEventListener('webkitTransitionEnd', this._cleanupListener.bind(this));
            this.elem.addClass(this.settings.animationClasses.out);

            if (this.settings.disableScrolling) {
                $('body').css({
                    overflow: 'auto'
                });
            }

            setTimeout(()=> {
                this._cleanupListener();
            }, 100);

            this.settings.onClose();
        }
    }
}

module.exports = Overlay;