Détecter cliquez à l'extérieur de l'élément
Comment puis-je détecter un clic en dehors de mon élément? Je suis l'aide de Vue.js donc ça va être en dehors de mon élément de gabarits. Je sais comment le faire dans Vanilla JS, mais je ne suis pas sûr qu'il y ait une meilleure façon de le faire, quand j'utilise Vue.js?
C'est la solution pour vanille JS: JavaScript détecter événement en dehors de div
je suppose que je peux utiliser une meilleure façon d'accéder à l'élément?
10 réponses
peut être résolu correctement en configurant une seule directive personnalisée:
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() }
})
Utilisation:
<div v-click-outside="nameOfCustomEventToCall">
Some content
</div>
dans le composant:
events: {
nameOfCustomEventToCall: function (event) {
// do something - probably hide the dropdown menu / modal etc.
}
}
démo de travail sur JSFiddle avec des informations supplémentaires sur les mises en garde:
il y a la solution que j'ai utilisée, qui se base sur la réponse de Linus Borg et fonctionne très bien avec 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)
},
});
Il y a un petit démo
vous pouvez trouver plus d'informations sur les directives personnalisées et ce que el, binding, vnode signifie dans https://vuejs.org/v2/guide/custom-directive.html#Directive-Hook-Arguments
Il y a deux paquets disponibles dans la communauté pour cette tâche (les deux sont maintenus):
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
}
}
ça a marché pour moi avec 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
}
}
vous pouvez enregistrer deux écouteurs d'événements pour click event comme ceci
document.getElementById("some-area")
.addEventListener("click", function(e){
alert("You clicked on the area!");
e.stopPropagation();// this will stop propagation of this event to upper level
}
);
document.body.addEventListener("click",
function(e) {
alert("You clicked outside the area!");
}
);
j'utilise ce code:
"bouton" tag
<a @click="visualSwitch()"> show hide </a>
Afficher/masquer la balise:
<div class="dialog-popup" v-if="visualState" @click.stop=""></div>
variable d'état
data () { return {
visualState: false,
}},
methods: {
visualSwitch() {
document.removeEventListener('click', this.visualSwitch);
this.visualState = !this.visualState;
},
},
regarder
watch: {
visualState() {
if (this.visualState)
document.addEventListener('click', this.visualSwitch);
}
}
j'ai une solution pour la manipulation À Bascule menu déroulant:
export default {
data() {
return {
dropdownOpen: false,
}
},
methods: {
showDropdown() {
console.log('clicked...')
this.dropdownOpen = !this.dropdownOpen
// this will control show or hide the menu
$(document).one('click.status', (e)=> {
this.dropdownOpen = false
})
},
}
j'ai mis à jour la réponse de MadisonTrash pour prendre en charge le Safari Mobile (qui n'a pas" événement 151910920", touchend
doit être utilisé à la place). Cela inclut également une vérification afin que l'événement ne soit pas déclenché par glisser sur les appareils mobiles.
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');
},
});
les gens veulent souvent savoir si l'utilisateur quitte le composant root (fonctionne avec tous les composants de niveau)
Vue({
data: {},
methods: {
unfocused : function() {
alert('good bye');
}
}
})
<template>
<div tabindex="1" @blur="unfocused">Content inside</div>
</template>