问题描述
参考文献
我正在为元素列表 click-outside senario编写自定义指令。
I am writing a custom directive for 'click-outside senario' for a list of elements.
基本上,在列表中的项目上单击按钮时,它将进入选定模式。现在,如果在其他任何地方都发生单击,则需要取消选择模式。
为此,我需要检测外部点击。
我从
中找出了指令,为此,我想到了
Basically when a button is clicked on a item in the list it goes into selected mode . Now if a click occurs anywhere else I need to cancel selection mode .For that I need to detect click outside .I figured out the directive for it fromFor that I have come up with
const clickOutside = {
bind: function (el, binding, vnode) {
console.log('bind called')
document.body.addEventListener('click', (event) => {
// check that click was outside the el and his childrens
if (!(el == event.target || el.contains(event.target))) {
// and if it did, call handle method provided in attribute value
console.log('directive working')
vnode.context[binding.expression](event);
}
})
},
unbind: function (el) {
document.body.removeEventListener('click', el.event)
console.log('unbind called')
}
}
export {
clickOutside
}
来自上面引用中的
现在,我只希望每个列表项在选定的菜单项中都在监听该外部点击de。
Now I only want each list item to listen for outside clicks when that item is in selected mode .
所以我需要完成类似
<div id="list-item" v-on-click-outside="outSideClickHandler" //trigger only when selected>
</div>
<script>
export default{
data:{
selectedState:false;
},
methods:{
outSideClickHandler:{//......}
}
</script>
推荐答案
为什么不在内部进行选定的检查点击外部处理程序?您还需要一种将单击的项目传递给处理程序的方法。
Why don't you just do the selected check inside the click outside handler? You'll also need a way of passing the clicked item to the handler.
<div id="list-item" v-on-click-outside="outSideClickHandler(item)"></div>
outSideClickHandler(item) {
return event => {
if (item.selected) {
// Handle the click outside
}
};
}
在指令中调用处理程序,如下所示:
Call the handler in the directive like this:
binding.value(event);
您不会像使用<$一样获得自定义指令的自动表达式/语句绑定c $ c> v-on 这就是为什么当您想向处理函数传递额外的参数时需要使用该函数。
You do not get the automatic "expression/statement" binding for custom directives like do you with v-on
which is why you need to curry the handler function when you want to pass extra arguments to it.
我的意思是传递给 v-on
的参数可以是表达式或语句,例如:
By this I mean the argument passed to v-on
can be an expression or a statement, such as:
@click="handler" - handler is an expression (the function itself)
@click="handler(item)" - handler(item) is a statement
但是使用自定义指令,您只能传递表达式;除非 handler()
返回另一个函数,否则上面的第二行是不可能的。
But with custom directives you can only pass expressions; the second line above is not possible unless handler()
returns another function.
我认为有些混乱,因为您似乎想拥有一个自定义指令,该指令仅在此特定情况下与您的列表项一起使用,但是我上面的解决方案更多是关于编写通用的外部单击指令
I think there is some confusion because it seems what you want is to have a custom directive which is used only in this specific situation with your list items, but my solution above is more about writing a general "click outside" directive which you can use in any situation.
我还认为,如果未选择列表项,出于性能原因,您不希望指令注册任何事件侦听器。 。在这种情况下,您可以使用事件委派。
Also I think you do not want the directive to register any event listeners if the list item is not selected (for performance reasons?). If that's the case, then you can use event delegation instead.
无法有条件地启用/禁用指令,您必须执行类似,两者都有些混乱。
There is no way to conditionally enable/disable a directive, you would have to do something like Morty's answer, both of which is kind of messy.
您反对编写DOM吗?指令之外的操作代码? Angular 1拥有这种理念。除非您想在不同的情况下重用该指令,否则为这种情况编写一个指令以免 DOM操作代码不会污染我的组件可能是过大的选择。如果我要写一条指令,那么我希望它尽可能通用,以便我可以在许多不同的情况下使用它。
Are you against writing DOM manipulation code outside of directives? Angular 1 had this philosophy. Unless you want to reuse the directive in different situations then it may be overkill to write a directive for this situation just so that "DOM manipulation code does not pollute my component". If I'm going to write a directive, then I would want it to be as general as possible so that I can use it in many different situations.
然后,我不确定为什么您要将此作为指令来实现,而这很少需要。您只需在已安装
钩子中注册正文单击事件,然后在 destroyed
钩子中将其删除。所有的外部点击逻辑都可以包含在组件本身内。
Then I'm not sure why you'd want to implement this as a directive, which is rarely needed anyway. You can just register the body click event in the mounted
hook and remove it in the destroyed
hook. All of the click-outside logic can be contained within the component itself.
如果您不必担心注册每个列表项的主体单击事件侦听器,您可以执行以下操作:
If your main concern is not having to register a body click event listener for each list item, you can do something like this:
const handlers = new Map();
document.addEventListener('click', e => {
for (const handler of handlers.values()) {
handler(e);
}
});
Vue.directive('click-outside', {
bind(el, binding) {
const handler = e => {
if (el !== e.target && !el.contains(e.target)) {
binding.value(e);
}
};
handlers.set(el, handler);
},
unbind(el) {
handlers.delete(el);
},
});
您可以再走一步,只要自动添加主体单击事件侦听器handlers
是非空的,并在 handlers
为空时删除侦听器。由您决定。
You can go one step further and automatically add the body click event listener whenever handlers
is nonempty and remove the listener when handlers
is empty. It's up to you.
这篇关于有条件地绑定vue js中的自定义指令以“在元素事件之外单击”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!