可拖动对话弹框的模块化实现
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对象所占用的,按钮的点击只负责弹框的样式及显示。