Marionette ItemView事件处理与Bootstrap下拉列表冲突



我有一个创建表的Composite视图,childView集合显示每一行。每行的末尾都有一个基于Bootstrap的下拉按钮。单击该行将打开一个模态(工作),但当单击按钮下拉列表时,事件仍然会被触发,因此模态显示,下拉列表显示在下面。

如何在不防止Bootstrap挂钩也被切断的情况下,防止点击按钮向下传播到行点击事件?

处理这些类型的特殊点击事件的标准方法(在我的研究和书籍阅读中),在返回的jquery事件上使用e.stopPropagation(),以防止事件进一步发展,但这会阻止Bootstrap下拉打开事件的触发。

如果我仍然在单击按钮组时调用stopPropagation(),然后使用事件对象的currentTarget对象并手动切换类,我可以在没有冲突的情况下打开下拉列表,但由于关闭按钮触发器是向下4层的,我会使用暴力&调用parent()4次来切换类,这听起来不太可持续或可移植。

如何使用Bootstrap的内置切换进行行点击操作并打开和关闭下拉列表?

项目视图

Show.Result = Marionette.ItemView.extend({
tagName:"tr",
template: "#row-template",
events:{
"click .js-delete-result": "editRow",
"click .js-edit-result": "deleteRow",
"click div.btn-group button": "openSettings"
"click": "rowClicked",
},
editRow: function(e){e.stopPropagation();alert("you trying to delete bro?!")},
deleteRow: function(e){e.stopPropagation();alert("you trying to edit bro?!")},
openSettings: function(e){
//e.stopPropagation()
//$(e.currentTarget).parent().toggleClass('open')
//e.currentTarget.button('toggle');
},
rowClicked:function(e){
e.preventDefault()
this.trigger("show:result",this)
},
}

模板

<script id="row-template">
<td class="vert-align"><%= value %></td>
<td class="vert-align"><%= notes %></td>
<td class="vert-align">
<div class="btn-group">
<button class="btn btn-xs btn-default dropdown-toggle" aria-haspopup="true"  data-toggle="dropdown" aria-expanded="false">
<span class="glyphicon glyphicon-edit"/>
</button>
<ul class="dropdown-menu" role="menu">
<li><a href="#" class="js-edit-result">Edit</a></li>
<li><a href="#" class="js-delete-result"> Delete <i class= "glyphicon glyphicon-trash"/></a></li>
</ul>
</div>
</td>
</script>

随机想法:也许我想错了这个问题,应该找到一个更好的CSS/jQuery选择器,它可以覆盖除按钮组之外的所有内容;是否有带有CSS的"not"选择器?

EDIT:我尝试将"click": "rowClicked",通用单击处理程序更改为使用'not'css选择器;"click :not(div.btn-group *)": "rowClicked",但没有任何作用;单击按钮时,它仍然会打开模型。经过更多的研究,我意识到我的not选择器没有正确格式化/使用,但这可能很奇怪,因为我试图以一种不适合的方式使用它。

编辑2:我最终阻止了传播(有点),但在这个过程中发现生成了两个单独的点击我不知道为什么这是因为事件传播从未停止,并且一直到根HTML元素,在本例中是TR.

每次单击时,更改通用单击函数以检查单击的目标是什么,以及它的祖先是否包含.btn-group类,但仅限于按钮本身;如果你只点击一行,那么它只会触发一次。

如何在正确的项目上阻止这种传播/设置事件侦听器?

rowClicked:function(e){
e.preventDefault()
console.log("I get called twice?!")
if($(e.target).parents('.btn-group').length > 0){
//do nothing
}
else{
e.stopPropagation()
this.trigger("show:result",this)
}
}, 

只是一个想法,尚未测试。你是如何在按钮的父级停止传播的?例如click div.btn-group?它不应该干扰默认的引导行为,但它可以阻止它冒泡到行本身。

试试这个;

rowClicked:function(e){
if($(e.currentTarget).is('td')){ //or e.target will also do
this.trigger("show:result",this);
}
}, 

经过大量的谷歌搜索和测试,我认为这可能是目前最好的方法。它并没有真正解决我问题的核心,但由于一个通用的点击事件处理程序在引导程序到达它之前就已经插入了它自己,所以将点击的焦点更改为更具体的东西似乎已经成功了。

感谢@Pawan@squall3d在这个方向上提供了一些指针,但我仍在寻找如何更好地传播/设置/控制事件侦听器以防止将来与其他库发生冲突的答案。

然而,为了让它现在工作,我将通用点击更改为"click td": "rowClicked"td几乎是基本层,但足够具体,不会干扰按钮事件。我不再需要按钮点击处理程序(我们希望引导程序来完成),所以它被删除了:"click div.btn-group button": "openSettings"

Show.Result = Marionette.ItemView.extend({
tagName:"tr",
template: "#row-template",
events:{
"click .js-delete-result": "editRow",
"click .js-edit-result": "deleteRow",
"click td": "rowClicked",
},
editRow: function(e){e.stopPropagation();alert("you trying to delete bro?!")},
deleteRow: function(e){e.stopPropagation();alert("you trying to edit bro?!")},
rowClicked:function(e){
e.preventDefault()
this.trigger("show:result",this)
},
}

值得注意的是,我确实向rowClicked函数添加了额外的代码,以防止在显示按钮下拉列表时打开模态,而您在单击下拉列表外部以关闭它时意外地单击了一行。我发现这是一种更好的用户体验。

rowClicked:function(e){
if($("#edit-btn").hasClass("open")){
//also do nothing - the dropdown is open
}
else{
e.stopPropagation()
e.preventDefault()
this.trigger("show:result",this)
}
}

并为jquery选择向btn组添加了一个id

<div class="btn-group" id="edit-btn">

这是因为Bootstrap添加了一个.opencss类来触发显示下拉html。

最新更新