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

2018-07-12  本文已影响0人  upup_dayday

先上效果图


演示.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对象所占用的,按钮的点击只负责弹框的样式及显示。

源码
演示

上一篇下一篇

猜你喜欢

热点阅读