javascript - 关于jq .on方法的问题。
问题描述
arr中保存的是div的位置,div可以移动删除,现在的问题是如果删除div,他的位置也会加到arr中并且会重复,请问是执行顺序的问题吗?
var arr=[];
function add(){
var addDiv=$("<div><span>DM54</span></div>");
addDiv.addClass("draggable");
addDiv.draggable();
$(".box").append(addDiv);
}
$('.box')
.on('click', '#close', function(){
$("#popup").hide("slow");
})
.on('dblclick', '.draggable', function(){
$("#popup").show("slow");
var that=$(this);
$('#delete').click(function(){
that.remove();
})
})
.on('mouseup', '.draggable', function(){
var cache = $(this).css(['top','left']);
var location={
id: $(this).index()+1,
X: cache.top,
Y: cache.left
};
arr.push(location);
})
代码地址http://runjs.cn/detail/y2qtieiq (位置值是undefined可能是我粘代码问题可以忽略)
看了你在 http://runjs.cn/detail/y2qtieiq 的代码,发现一些问题
[1] - 取位置用 .css(["top", "left"])
这一点是 jQuery 1.9 添加的新语法,我孤陋寡闻了,多谢 @熊猫桑
如果我没记错的话,jQuery 应该不支持这种方式获取多个CSS属性的值,你可以分成两句话来写
var cache = {
top: $(this).css("top"),
left: $(this).css("left")
};
或者,直接用 .position()
var cache = $(this).position();
// 注意 position() 取出来的位置只有值,没有单位,这与 css 取出来的不同
cache.top = cache.top + "px";
cache.left = cache.left + "px";
[2] - arr.push(location)
这里每次 mouseup
事件都会 push
一个 location
对象到 arr
中去,然而实际上如果是对同一个对象多次操作,arr
里会保存很多个同一对象的位置
解决办法
在 location 有 ID 的情况下,可以使用 map(即 js 对象) 来解决
var all = {}; // 代替 arr (不要求顺序的情况下)
// ...
// 然后在 push 那里改为
all[location.id] = location;
// 之后需要取出来的时候
var data = Object
.keys(all)
.map(function(key) { return all[key]; });
[3] - $("#delete").click(...)
这里每境框一次都会绑定一个事件,所以多次弹框之后每次点删除按钮都会触发很多次事件。这里建议你做个初始化绑定,只绑定一次事件。如果你担心每次,或某次弹出来的删除按钮已经不是原来那个了,可以给它加个 .data(...)
值用来标记。
另外,这个事件里用到了 that.remove()
这是没有问题的,问题在于,从 DOM 树里删除了对象,arr
中却仍然存在——其实整个代码中我都没看到哪里有从 arr
里删除对象的代码,所以 arr
的项其实是只增不减的。
解决办法:
var $del = $("#delete");
if (!$del.data("inited")) {
$del.click(...);
$del.data("inited", true);
}
然后在 that.remove()
之前(之后好像也可以)
var id = that.data(id);
delete all[id];
不过这样之后,由于 dblclick
事件有可能是不同的 .draggable
触发的,而 $del.click
事件中的 that
是在定义这个事件处理函数的那个 .draggable
,所以这里还需要在 .dblclick
中告诉 $del
要删除的是哪一个,然后在 $del
中去删除这一个。(这里有点绕,我一开始没想到,所以是后来补充的这一段)
.on("dblclick", ".draggable", function() {
$("#popup").show("slow");
var that = $(this);
var $del = $("#delete");
// ① 把触发 dblclick 这个目标给记录下来,备②用
$del.data("target", that);
if (!$del.data("inited")) {
$del.click(function() {
// ② 从 $del.data 中把目标取出来,要删除的就是这个 $target,
// 也就是弹框之前双击的那个 .draggable
var $target = $del.data("target");
var id = $target.data("id");
delete all[id];
$target.remove();
});
$del.data("inited", true);
}
})
[4] - id: $(this).index() + 1
这里单独来看并没有什么问题,但是,这个 index()
是计算是这个元素在当前父元素中是第几个子元素,那么,在 that.remove()
之后,这个 that
后面的所有兄弟元素的 index()
都会发生变化,所以拿它(index()
)来作为 id
显然是不合适的。同样,建议你通过 .data(...)
来赋予 ID,至于 ID 的取值,你只需要能保证唯一就行了。你甚至可以不要 ID,直接保存对应的 DOM 元素或相应的 jQuery 对象。
解决办法,生成唯一 ID
var nextId = (function() {
var id = 1;
return function() {
return id++;
};
})();
// .....
var $this = $(this);
var id = $this.data("id");
if (!id) {
id = nextId();
$this.data("id", id);
}
[5] - $("#save").click(...)
这里的 data
中是用的不能唯一对应 DOM 对象的 ID (push(location)
之前在 location
中定义的,上一条已经说明了它的不稳定性)。这还不是仅存的问题,问题是你还要把这个 id 送给服务器,服务器怎么会知道你到底送的是个啥(比如对应的名称是啥)?
解决办法
假设要传递给服务器的是名称。这样的话,需要在生成 location
的时候多加一个属性
location.name = $this.text();
然后在 save 的时候直接序列化前面从 all
中得到的 data 即可。
暂时就发现这些问题,请先思考一下逻辑。写任何程序,代码只是最后的呈现,关键是你要逻辑要经得起推敲!
这篇关于javascript - 关于jq .on方法的问题。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!