You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Drupal 7中D3.js(v3/v4)树折叠后点击事件丢失问题求助

解决Drupal 7中D3.js树折叠/展开后点击事件丢失的问题

看起来你遇到的核心问题是D3树展开/折叠时会重新生成DOM元素,而你原有的Drupal行为只在页面初始加载时绑定了一次事件,新生成的.ajax_button元素没被处理。下面给你两个靠谱的解决方案,按优先级推荐:

方案一:使用事件委托(最稳定高效)

事件委托的思路是把点击事件绑定到树的父容器上,而不是每个.ajax_button元素。这样不管D3怎么删除、重建子元素,只要元素符合选择器,事件就能触发。

修改后的Drupal行为代码

(function($) {
Drupal.behaviors.listload = {
    attach: function(context, settings) {
        // 替换#tree-container为你D3树实际的父容器选择器
        $('#tree-container', context)
            .once('listload-event-delegate') // 确保只绑定一次委托
            .on('click', '.ajax_button', function(e) {
                e.preventDefault();
                e.stopPropagation();
                
                var the_id = $(this).attr('href');
                var noSlashes = the_id.replace(/\//g, '');
                
                $.ajax({
                    url: Drupal.settings.basePath + 'views/ajax',
                    type: 'post',
                    data: {
                        view_name: 'candidate_list_er',
                        view_display_id: 'candidate_list_block',
                        view_args: noSlashes,
                    },
                    dataType: 'json',
                    success: function(response) {
                        if (response[1] !== undefined) {
                            var viewHtml = response[1].data;
                            $('#ajax-target .content').html(viewHtml);
                            // 加载新视图后,别忘了处理新内容里的Drupal行为
                            Drupal.attachBehaviors('#ajax-target .content');
                        }
                    },
                    error: function(data) {
                        alert('An error occurred!');
                    }
                });
            });
    },
    detach: function(context, settings, trigger) {
        $('#tree-container', context).off('click', '.ajax_button');
    }
};
})(jQuery);

关键修改点

  1. 移除了context == document的限制,让行为能处理局部上下文
  2. 用事件委托替代直接绑定元素,避免D3更新DOM后事件丢失
  3. 使用once确保委托事件只绑定一次,不会重复触发

配合D3的操作

在你的D3树折叠/展开函数末尾,添加一行代码通知Drupal处理更新后的DOM:

// 假设你的D3树容器是#tree-container,替换成实际选择器
Drupal.attachBehaviors(document.getElementById('tree-container'));

方案二:直接绑定元素(适合简单场景)

如果不想用事件委托,可以修改行为逻辑,让每次D3更新DOM后,都能重新给新元素绑定事件:

修改后的Drupal行为代码

(function($) {
Drupal.behaviors.listload = {
    attach: function(context, settings) {
        // 去掉全局上下文限制,处理所有传入的局部元素
        $('.ajax_button', context)
            .off('click.listload') // 先解绑命名空间事件,避免重复绑定
            .on('click.listload', function(e) {
                e.preventDefault();
                e.stopPropagation();
                
                var the_id = $(this).attr('href');
                var noSlashes = the_id.replace(/\//g, '');
                
                $.ajax({
                    url: Drupal.settings.basePath + 'views/ajax',
                    type: 'post',
                    data: {
                        view_name: 'candidate_list_er',
                        view_display_id: 'candidate_list_block',
                        view_args: noSlashes,
                    },
                    dataType: 'json',
                    success: function(response) {
                        if (response[1] !== undefined) {
                            var viewHtml = response[1].data;
                            $('#ajax-target .content').html(viewHtml);
                            Drupal.attachBehaviors('#ajax-target .content');
                        }
                    },
                    error: function(data) {
                        alert('An error occurred!');
                    }
                });
            });
    },
    detach: function(context, settings, trigger) {
        $('.ajax_button', context).off('click.listload');
    }
};
})(jQuery);

配合D3的操作

和方案一一样,在D3折叠/展开函数末尾调用:

Drupal.attachBehaviors(document.getElementById('tree-container'));

关键修改点

  1. 移除context == document限制,支持局部DOM更新
  2. 使用命名空间事件(click.listload),避免和其他事件冲突,同时确保每次绑定前先解绑,防止重复触发

为什么原来的代码会失效?

  1. context == document:限制了行为只在页面初始加载时执行,D3更新DOM后的局部元素不会被处理
  2. .once():只会给初始的DOM元素绑定一次事件,D3重新生成的新元素不会触发绑定逻辑
  3. D3树折叠/展开时会删除旧元素、创建新元素,原来绑定的事件会随着旧元素被销毁而丢失

内容的提问来源于stack exchange,提问作者kiranking

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:22:45