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);
关键修改点
- 移除了
context == document的限制,让行为能处理局部上下文 - 用事件委托替代直接绑定元素,避免D3更新DOM后事件丢失
- 使用
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'));
关键修改点
- 移除
context == document限制,支持局部DOM更新 - 使用命名空间事件(
click.listload),避免和其他事件冲突,同时确保每次绑定前先解绑,防止重复触发
为什么原来的代码会失效?
context == document:限制了行为只在页面初始加载时执行,D3更新DOM后的局部元素不会被处理.once():只会给初始的DOM元素绑定一次事件,D3重新生成的新元素不会触发绑定逻辑- D3树折叠/展开时会删除旧元素、创建新元素,原来绑定的事件会随着旧元素被销毁而丢失
内容的提问来源于stack exchange,提问作者kiranking
相关产品推荐
相关产品推荐

