Javascript 检测元素外的点击
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36170425/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Detect click outside element
提问by MadisonTrash
How can I detect a click outside my element? I'm using Vue.js so it's gonna be outside my templates element. I know how to do it in Vanilla JS, but I'm not sure if there's a more proper way to do it, when I'm using Vue.js?
如何检测元素外的点击?我正在使用 Vue.js 所以它会在我的模板元素之外。我知道如何在 Vanilla JS 中做到这一点,但是当我使用 Vue.js 时,我不确定是否有更合适的方法来做到这一点?
This is the solution for Vanilla JS: Javascript Detect Click event outside of div
这是 Vanilla JS 的解决方案:Javascript Detect Click event outside of div
I guess I can use a better way to access the element?
我想我可以使用更好的方法来访问元素?
采纳答案by Linus Borg
Can be solved nicely by setting up a custom directive once:
可以通过设置一次自定义指令很好地解决:
Vue.directive('click-outside', {
bind () {
this.event = event => this.vm.$emit(this.expression, event)
this.el.addEventListener('click', this.stopProp)
document.body.addEventListener('click', this.event)
},
unbind() {
this.el.removeEventListener('click', this.stopProp)
document.body.removeEventListener('click', this.event)
},
stopProp(event) { event.stopPropagation() }
})
Usage:
用法:
<div v-click-outside="nameOfCustomEventToCall">
Some content
</div>
In the component:
在组件中:
events: {
nameOfCustomEventToCall: function (event) {
// do something - probably hide the dropdown menu / modal etc.
}
}
Working Demo on JSFiddle with additional info about caveats:
JSFiddle 上的工作演示以及有关警告的附加信息:
回答by MadisonTrash
There is the solution I used, which is based on Linus Borg answer and works fine with vue.js 2.0.
有一个我使用的解决方案,它基于 Linus Borg 的答案,并且在 vue.js 2.0 中运行良好。
Vue.directive('click-outside', {
bind: function (el, binding, vnode) {
el.clickOutsideEvent = function (event) {
// here I check that click was outside the el and his childrens
if (!(el == event.target || el.contains(event.target))) {
// and if it did, call method provided in attribute value
vnode.context[binding.expression](event);
}
};
document.body.addEventListener('click', el.clickOutsideEvent)
},
unbind: function (el) {
document.body.removeEventListener('click', el.clickOutsideEvent)
},
});
You bind to it using v-click-outside
:
你绑定到它使用v-click-outside
:
<div v-click-outside="doStuff">
You can find some more info about custom directives and what el, binding, vnodemeans in https://vuejs.org/v2/guide/custom-directive.html#Directive-Hook-Arguments
您可以在https://vuejs.org/v2/guide/custom-directive.html#Directive-Hook-Arguments 中找到有关自定义指令以及el、binding、vnode含义的更多信息
回答by G'ofur N
Add tabindex
attribute to your component so that it can be focused and do the following:
将tabindex
属性添加到您的组件,以便它可以聚焦并执行以下操作:
<template>
<div
@focus="handleFocus"
@focusout="handleFocusOut"
tabindex="0"
>
SOME CONTENT HERE
</div>
</template>
<script>
export default {
methods: {
handleFocus() {
// do something here
},
handleFocusOut() {
// do something here
}
}
}
</script>
回答by Julien Le Coupanec
There are two packages available in the community for this task (both are maintained):
社区中有两个包可用于此任务(均已维护):
回答by xiaoyu2er
export default {
bind: function (el, binding, vNode) {
// Provided expression must evaluate to a function.
if (typeof binding.value !== 'function') {
const compName = vNode.context.name
let warn = `[Vue-click-outside:] provided expression '${binding.expression}' is not a function, but has to be`
if (compName) { warn += `Found in component '${compName}'` }
console.warn(warn)
}
// Define Handler and cache it on the element
const bubble = binding.modifiers.bubble
const handler = (e) => {
if (bubble || (!el.contains(e.target) && el !== e.target)) {
binding.value(e)
}
}
el.__vueClickOutside__ = handler
// add Event Listeners
document.addEventListener('click', handler)
},
unbind: function (el, binding) {
// Remove Event Listeners
document.removeEventListener('click', el.__vueClickOutside__)
el.__vueClickOutside__ = null
}
}
回答by yann_yinn
This Worked for me with Vue.js 2.5.2 :
这对我有用 Vue.js 2.5.2 :
/**
* Call a function when a click is detected outside of the
* current DOM node ( AND its children )
*
* Example :
*
* <template>
* <div v-click-outside="onClickOutside">Hello</div>
* </template>
*
* <script>
* import clickOutside from '../../../../directives/clickOutside'
* export default {
* directives: {
* clickOutside
* },
* data () {
* return {
showDatePicker: false
* }
* },
* methods: {
* onClickOutside (event) {
* this.showDatePicker = false
* }
* }
* }
* </script>
*/
export default {
bind: function (el, binding, vNode) {
el.__vueClickOutside__ = event => {
if (!el.contains(event.target)) {
// call method provided in v-click-outside value
vNode.context[binding.expression](event)
event.stopPropagation()
}
}
document.body.addEventListener('click', el.__vueClickOutside__)
},
unbind: function (el, binding, vNode) {
// Remove Event Listeners
document.removeEventListener('click', el.__vueClickOutside__)
el.__vueClickOutside__ = null
}
}
回答by BogdanG
I have combined all answers (including a line from vue-clickaway) and came up with this solution that works for me:
我已经结合了所有答案(包括来自 vue-clickaway 的一行),并提出了这个对我有用的解决方案:
Vue.directive('click-outside', {
bind(el, binding, vnode) {
var vm = vnode.context;
var callback = binding.value;
el.clickOutsideEvent = function (event) {
if (!(el == event.target || el.contains(event.target))) {
return callback.call(vm, event);
}
};
document.body.addEventListener('click', el.clickOutsideEvent);
},
unbind(el) {
document.body.removeEventListener('click', el.clickOutsideEvent);
}
});
Use in component:
在组件中使用:
<li v-click-outside="closeSearch">
<!-- your component here -->
</li>
回答by Pax Exterminatus
I use this code:
我使用这个代码:
show-hide button
显示隐藏按钮
<a @click.stop="visualSwitch()"> show hide </a>
show-hide element
显示隐藏元素
<div class="dialog-popup" v-if="visualState" @click.stop=""></div>
script
脚本
data () { return {
visualState: false,
}},
methods: {
visualSwitch() {
this.visualState = !this.visualState;
if (this.visualState)
document.addEventListener('click', this.visualState);
else
document.removeEventListener('click', this.visualState);
},
},
Update:remove watch; add stop propagation
更新:移除手表;添加停止传播
回答by benrwb
I have updated MadisonTrash's answer to support Mobile Safari (which does not have click
event, touchend
must be used instead). This also incorporates a check so that the event isn't triggered by dragging on mobile devices.
我已经更新了 MadisonTrash 的答案以支持 Mobile Safari(它没有click
事件,touchend
必须改用)。这还包含一个检查,以便在移动设备上拖动不会触发事件。
Vue.directive('click-outside', {
bind: function (el, binding, vnode) {
el.eventSetDrag = function () {
el.setAttribute('data-dragging', 'yes');
}
el.eventClearDrag = function () {
el.removeAttribute('data-dragging');
}
el.eventOnClick = function (event) {
var dragging = el.getAttribute('data-dragging');
// Check that the click was outside the el and its children, and wasn't a drag
if (!(el == event.target || el.contains(event.target)) && !dragging) {
// call method provided in attribute value
vnode.context[binding.expression](event);
}
};
document.addEventListener('touchstart', el.eventClearDrag);
document.addEventListener('touchmove', el.eventSetDrag);
document.addEventListener('click', el.eventOnClick);
document.addEventListener('touchend', el.eventOnClick);
}, unbind: function (el) {
document.removeEventListener('touchstart', el.eventClearDrag);
document.removeEventListener('touchmove', el.eventSetDrag);
document.removeEventListener('click', el.eventOnClick);
document.removeEventListener('touchend', el.eventOnClick);
el.removeAttribute('data-dragging');
},
});
回答by Martin Prestone
I hate additional functions so... here is an awesome vue solution without an additional vue methods, only var
我讨厌附加功能所以......这是一个很棒的 vue 解决方案,没有额外的 vue 方法,只有 var
- create html element, set controls and directive
- 创建 html 元素,设置控件和指令
<p @click="popup = !popup" v-out="popup">
<div v-if="popup">
My awesome popup
</div>
- create a var in data like
- 在数据中创建一个变量,如
data:{
popup: false,
}
- add vue directive. its
- 添加 vue 指令。它的
Vue.directive('out', {
bind: function (el, binding, vNode) {
const handler = (e) => {
if (!el.contains(e.target) && el !== e.target) {
//and here is you toggle var. thats it
vNode.context[binding.expression] = false
}
}
el.out = handler
document.addEventListener('click', handler)
},
unbind: function (el, binding) {
document.removeEventListener('click', el.out)
el.out = null
}
})