在jstree委托中创建意外的多个实例

时间:2012-06-26 09:36:24

标签: javascript jquery delegates jstree

var json_string=$.parseJSON(document.getElementById("json_db").innerHTML);
$(function () 
{
    $("#folder_tree").jstree({ 
        contextmenu: {items: customMenu},
        "json_data" : {data:json_string},
        "plugins" : [ "themes", "json_data", "ui", "contextmenu" ],

    });
});
function customMenu(node)
{
    var items = { };
}



$('#folder_tree').delegate('a', 'contextmenu', function (e)
{

        idn = $(this).parent().attr("id");
        if(idn) pool_control(idn,e); //sendMsg(idn)

});

嗨,我在jsTree中得到了一些非常奇怪的东西。 上面的代码显示了树创建和委派右键单击事件。 sendMsg(idn)将AJAX请求发送到另一个页面。 pool_control(idn,e)使用该事件显示单击节点旁边的表单。表单填写后,调用sendMsg。

当我在委托事件处理程序(而不是pool_control)中直接调用sendMsg时,脚本运行正常。但是,当我通过pool_control调用它时,会发生这种情况: 每个pool_control都被调用,no。发送的Ajax请求增加一个。请求的内容看起来是一样的,但我不知道为什么没有。 ajax请求增加。当我直接调用sendMsg时,这不会发生。

发生了什么事?我该如何解决这个问题?

pool_control和sendMsg:

function pool_control(id,ev)
{

    $("#pool_count").css("left",ev.pageX);
    $("#pool_count").css("top",ev.pageY);
    $("#pool_count").css("visibility","visible");
    $("#poolbutton").click(function()
    {
        $('#pool_count').css('visibility','hidden');    
        sendMsg(id);
    });
    $("#poolcancel").click(function()
    {
        $('#pool_count').css('visibility','hidden');
    }); 
}

function sendMsg(a,ev)
{

    $('#pool_count').css('visibility','hidden');    
    var factid = $("#factid").val();
    var floor = $("#floor").val();
    var ceiling = $("#ceiling").val();
    var pool_count = $('#poolsize').val();
    var userid = document.getElementById("userid").innerHTML;
    $.ajax(
    {
        type: "POST",
        url: "generator.php",
        data: {what:a,name:factid,author:userid,floor:floor,ceiling:ceiling,pool_count:pool_count},
        async: false,
        cache: false,
        timeout:50000,
    }); 
}

这是一个长轮询网页。 sendMsg在树中发送用户自定义的更改,并不关心响应。 另一个函数waitForMsg是长轮询ajax请求。当它看到由于sendMsg导致的db更改时,它再次调用jstree()函数来重新生成树。 当我在树中进行更改时,sendMsg首次发送1个请求,2个请求秒时间,3个第三次请求,依此类推。 我很确定这个函数没什么问题,但是在这里,以防万一

function waitForMsg()
{
    var lastupdate = document.getElementById("lastupdate").innerHTML;
    var msg;
    $.ajax({
        type: "POST",
        url: "oracle.php",
        data: {lastupdate:lastupdate},
        async: true,
        cache: false,
        timeout:20000,

        success: function(data)
        { 
            msg = data.split("@");
            document.getElementById("lastupdate").innerHTML=msg[0];
            document.getElementById("json_db").innerHTML=msg[1];
            initPage(); //a <body onready> function which creates the tree again                
            setTimeout('waitForMsg()', 200 );
        },
        error: function(XMLHttpRequest, textStatus, errorThrown){
                            setTimeout('waitForMsg()', 1000);

        }
    });
}

1 个答案:

答案 0 :(得分:0)

由于事件在jQuery中的工作方式,每次使用.click()等函数附加事件时,事件都会“堆叠”到列表中,而不是替换。

通俗地说,以下代码:

    $("#poolbutton").click(function()
    {
        $('#pool_count').css('visibility','hidden');    
        sendMsg(id);
    });

不会告诉jQuery 在点击发生时运行,而是将此添加到触发点击时应该运行的事物列表

也就是说,如果您多次附加事件,例如以下列方式:

    $("#poolbutton").click(function()
    {
        $('#pool_count').css('visibility','hidden');    
        sendMsg(id);
    });

    $("#poolbutton").click(function()
    {
        $('#pool_count').css('visibility','hidden');    
        sendMsg(id);
    });

    $("#poolbutton").click(function()
    {
        $('#pool_count').css('visibility','hidden');    
        sendMsg(id);
    });

结果将是(您猜对了)sendMsg()每次点击被调用3次,因为附加的每个事件都是独立处理的。

由于每次调用pool_control时都会附加新的单击事件,因此结果是sendMsg()调用的数量,因此ajax请求的每个pool_control()调用都会增加一个。

修复?在pool_control()中再次绑定它们之前取消绑定单击事件:

function pool_control(id,ev)
{

    $("#pool_count").css("left",ev.pageX);
    $("#pool_count").css("top",ev.pageY);
    $("#pool_count").css("visibility","visible");
    $("#poolbutton").unbind('click').click(function()
    {
        $('#pool_count').css('visibility','hidden');    
        sendMsg(id);
    });
    $("#poolcancel").unbind('click').click(function()
    {
        $('#pool_count').css('visibility','hidden');
    }); 
}

OR,我个人宁愿推荐这种方式,因为除了其他方面它的开销较少,在初始化代码中只附加一次事件。你可以随时附加事件,在你的示例中在pool_control()之外的contextmenu上调用委托之前附加它们是完全正常的:

var json_string=$.parseJSON(document.getElementById("json_db").innerHTML);
$(function () 
{
    $("#folder_tree").jstree({ 
        contextmenu: {items: customMenu},
        "json_data" : {data:json_string},
        "plugins" : [ "themes", "json_data", "ui", "contextmenu" ],

    });
});
function customMenu(node)
{
    var items = { };
}

$("#poolbutton").click(function()
{
    $('#pool_count').css('visibility','hidden');    
    sendMsg(id);
});
$("#poolcancel").click(function()
{
    $('#pool_count').css('visibility','hidden');
}); 

$('#folder_tree').delegate('a', 'contextmenu', function (e)
{

        idn = $(this).parent().attr("id");
        if(idn) pool_control(idn,e); //sendMsg(idn)

});

function pool_control(id,ev)
{
    $("#pool_count").css("left",ev.pageX);
    $("#pool_count").css("top",ev.pageY);
    $("#pool_count").css("visibility","visible");
}

此方法确保事件仅附加一次,并且只要您不销毁#pool_count即可,只要发生单击而不必在pool_control()中关注它,就会触发事件。