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!");
}
);
这是我使用的解决方案,它基于Linus Borg Answer,并且与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 children
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)
},
});
var handleOutsideClick={}
const OutsideClick = {
// this directive is run on the bind and unbind hooks
bind (el, binding, vnode) {
// Define the function to be called on click, filter the excludes and call the handler
handleOutsideClick[el.id] = e => {
e.stopPropagation()
// extract the handler and exclude from the binding value
const { handler, exclude } = binding.value
// set variable to keep track of if the clicked element is in the exclude list
let clickedOnExcludedEl = false
// if the target element has no classes, it won't be in the exclude list skip the check
if (e.target._prevClass !== undefined) {
// for each exclude name check if it matches any of the target element's classes
for (const className of exclude) {
clickedOnExcludedEl = e.target._prevClass.includes(className)
if (clickedOnExcludedEl) {
break // once we have found one match, stop looking
}
}
}
// don't call the handler if our directive element contains the target element
// or if the element was in the exclude list
if (!(el.contains(e.target) || clickedOnExcludedEl)) {
handler()
}
}
// Register our outsideClick handler on the click/touchstart listeners
document.addEventListener('click', handleOutsideClick[el.id])
document.addEventListener('touchstart', handleOutsideClick[el.id])
document.onkeydown = e => {
//this is an option but may not work right with multiple handlers
if (e.keyCode === 27) {
// TODO: there are minor issues when escape is clicked right after open keeping the old target
handleOutsideClick[el.id](e)
}
}
},
unbind () {
// If the element that has v-outside-click is removed, unbind it from listeners
document.removeEventListener('click', handleOutsideClick[el.id])
document.removeEventListener('touchstart', handleOutsideClick[el.id])
document.onkeydown = null //Note that this may not work with multiple listeners
}
}
export default OutsideClick
const clickOutside = {
beforeMount: (el, binding) => {
el.clickOutsideEvent = event => {
// here I check that click was outside the el and his children
if (!(el == event.target || el.contains(event.target))) {
// and if it did, call method provided in attribute value
binding.value();
}
};
document.addEventListener("click", el.clickOutsideEvent);
},
unmounted: el => {
document.removeEventListener("click", el.clickOutsideEvent);
},
};
createApp(App)
.directive("click-outside", clickOutside)
.mount("#app");
export default function directive(app) {
// you can name the directive whatever you want. -> click-outside
app.directive('click-outside', {
beforeMount(el, binding) {
el.clickOutsideEvent = (evt) => {
evt.stopPropagation();
if (!(el === evt.target || el.contains(evt.target))) {
binding.value(evt, el);
}
};
window.requestAnimationFrame(() => {
document.addEventListener("click", el.clickOutsideEvent);
});
},
unmounted(el) {
document.removeEventListener("click", el.clickOutsideEvent);
},
})
}
Register指令:
main.JS
import { createApp } from "vue";
import App from "./App.vue";
// Import your directive, in order to register it.
import clickOutside from "./directives/click-outside.js"
createApp(App).use(clickOutside).mount("#app");