美文网首页
可拖动对话弹框的模块化实现

可拖动对话弹框的模块化实现

作者: upup_dayday | 来源:发表于2018-07-12 04:53 被阅读0次

    先上效果图


    演示.gif

    利用面向对象的方法做了一个弹框,点击不同按钮可创建不同样式的弹框,弹框出现后,对应的按钮不可用,需处理弹框后,才恢复。
    说下实现细节吧

    对话框样式设置

    构造函数里设置了对话框的模板和默认的样式,弹框默认是不显示的

     DialogCtor.prototype = {
                defaultOpt: {
                    titile: "",
                    message: "",
                    isShowCloseBtn: true,
                    isShowConfirmBtn: false,
                    onClose: function() {},
                    onConfirm: function() {}
                },
    
    ....
     createDialog: function() {
                    let tmp = '<div class="dialog" style="display:none">' +
                        '<div class="dialog-box">' +
                        '<div class="dialog-header"><h3></h3><span class="btn-close">x</span></div>' +
                        '<div class="dialog-content">' +
                        '</div>' +
                        '<div class="dialog-footer">' +
                        '  <a href="#" class="btn btn-close">取消</a>' +
                        '  <a href="#" class="btn btn-confirm">确定</a>' +
                        '</div>' +
                        '</div>' +
                        '</div>';
                    this.$diag = $(tmp);
                    $('body').append(this.$diag);
                },
    

    同时,也提供了接口,接收传入的选项参数,修改弹框的样式

    setOpt: function(opt) {
                    if (typeof opt === 'string') {
                        this.opt = $.extend({}, this.defaultOpt, {
                            message: opt
                        });
                    } else if (typeof opt === 'object') {
                        this.opt = $.extend({}, this.defaultOpt, opt);
                    }
                },
    
                setDialog: function() {
                    let $diag = this.$diag;
                    if (!this.opt.title) {
                        $diag.find('.dialog-header').hide();
                    } else {
                        $diag.find('.dialog-header').show();
                    }
    
                    if (!this.opt.isShowCloseBtn) {
                        $diag.find('.dialog-footer .btn-close').hide();
                    } else {
                        $diag.find('.dialog-footer .btn-close').show();
                    }
    
                    if (!this.opt.isShowConfirmBtn) {
                        $diag.find('.btn-confirm').hide();
                    } else {
                        $diag.find('.btn-confirm').show();
                    }
    
                    $diag.find('.dialog-header h3').text(this.opt.title);
                    $diag.find('.dialog-content').html(this.opt.message);
                },
    

    拖动效果实现

    _this.$diag.on('mousedown', function(e) {
                        /*e.pageX:事件在页面上的绝对位置*/
                        /*$dialog.offset() dialog在页面的绝对位置*/
                        let $curDialog = $(this),
                            evtX = e.pageX - $curDialog.offset().left, //evtX 计算事件的触发点在 dialog内部到 dialog 的左边缘的距离
                            evtY = e.pageY - $curDialog.offset().top;
    
                        $curDialog.addClass('draggable').data('evtPos', {
                            x: evtX,
                            y: evtY
                        })
                    });
    

    检测鼠标在弹框上按下后,记录事件触发点在弹框内部的位置,给弹框增加draggable的class,并存储记录在弹框的标签中

    $('body').on('mousemove', function(e) {
                        if ($('.draggable').length && $('.draggable').offset()) {
                            $('.draggable').offset({
                                left: e.pageX - $('.draggable').data('evtPos').x, // 当用户鼠标移动时,根据鼠标的位置和前面保存的距离,计算 dialog 的绝对位置
                                top: e.pageY - $('.draggable').data('evtPos').y
                            })
                        }
                    });
    

    监测鼠标移动的事件,如果draggable这个class存在,说明处于鼠标按下后的拖动过程中,重新获取事件发生点在页面的绝对位置,并根据上一次记录的弹框的位置数据,计算得出css设置left和top的偏移量

    $('body').on('mouseup', function() {
                        $('.draggable').length && $('.draggable').removeClass('draggable').removeData('evtPos');
                    })
    

    检测鼠标抬起事件,删除对弹框添加的class和data

    内存及变量回收的一点思考

    开始的实现思路是点击按钮的时候,在按钮绑定的事件回调函数里创建弹框对象,这样创建的就是局部变量

            $('#open1').on('click', function() {
                console.log(tt)
                var Diag1 = new DialogCtor();
                Diag1.open('hello, world');
            });
    

    按照之前对变量的理解,回调函数执行完之后,创建的这个局部的对象Diag1应该就被回收了,但是拖动的效果还可以实现,说明浏览器并没有把Diag1回收。可能也是因为在页面上添加了DOM元素,元素绑定了Diag1中的函数,所以导致Diag1没有被回收。

    但这种创建对象的方法,没有对按钮的限制,可以无限次创建,这样显然不好,所以进行了优化。

            var Diag1 = new DialogCtor();
            $('#open1').on('click', function() {
                Diag1.open('hello, world');
                $(this).attr('disabled', 'disabled');
                Diag1.$button = $(this);
            });
    

    创建全局的Diag对象,按钮的点击用来设置弹框的样式及显示弹框。创建之后就禁止按钮,等弹框关闭后,再移除按钮的disable。这样一来使用的内存就只有确定的5个diag对象所占用的,按钮的点击只负责弹框的样式及显示。

    源码
    演示

    相关文章

      网友评论

          本文标题:可拖动对话弹框的模块化实现

          本文链接:https://www.haomeiwen.com/subject/bmxlpftx.html