Click Off to Close is the first of five vue. js libraries I can’t live without. The main function is to trigger an event when the user clicks on something other than an element.
The goal of this article is to write custom instructions to achieve this functionality.
Functions such as encapsulating a drop-down box, or encapsulating a calendar, want to be able to close the drop-down box by clicking on the non-drop-down box.
A normal drop-down box
Start by implementing a normal drop-down box. It’s a box plus a panel. Click the box to show or hide the panel.
<div id="app">
<div class="select-box">
<div class="trigger-head" @click="clickSelect">Click the drop-down</div>
<div v-if="isShow" class="trigger-body">I'm the drop down box</div>
</div>
</div>
<script src="https://unpkg.com/vue"></script>
<script>
const vm = new Vue({
el: "#app".data: {
isShow: false
},
methods: {
clickSelect() {
this.isShow = !this.isShow; }}});</script>
<! --> < p style = "max-width: 100%;
<style>
.select-box {
width: 200px;
margin-left: 200px;
}
.trigger-head {
border: 1px solid #ccc;
padding: 10px;
}
.trigger-body {
width: 200px;
height: 300px;
background-color: #ccc;
position: absolute;
}
</style>
Copy the code
Important: Clicking on the outside will close the panel
Let me post the code first, after reading the code, basically understand
mounted() {
document.addEventListener("click".(e) = > {
SelectBox = ref= selectBox
const selectBox = this.$refs.selectBox;
SelectBox (selectBox, selectBox, selectBox, selectBox)
if(! selectBox.contains(e.target)) {this.isShow = false; }}); },Copy the code
Look at the code, in fact, the viewer about understand.
The click event is bound to the global, and then contains the key method to determine whether the element you clicked on is a descendant of the selectBox. If not, you must have clicked on the outside of the selectBox, thereby hiding the panel. At this point, the most critical logic is done.
Encapsulated as a custom instruction
The core logic is up here. And then what we’re going to do is encapsulate it into an instruction that’s going to deal with this, you know, clicking something outside of the element that triggers an action.
How do official documents encapsulate custom directives
So here we wrap a directive called clickOutside, which binds the element of the directive, which means that clicking outside the element will execute the corresponding function.
Vue.directive("click-outside".(el, bindings, vnode) = > {
// el is the bindings element, expression is the dynamic parameter, vnode is the virtual node of the bindings element, vnode.context is the VM instance of the node
document.addEventListener("click".e= > {
// Click on the binding directive element to execute the function
if(! el.contains(e.target)) {letmethod = bindings.expression; vnode.context[method](); }}); });HidePanel (){this.isshow = false}
Copy the code
Hooks for custom directives
That’s pretty much all there is to it, but there is an optimization, because the binding event is on the Document, so we should unbind it at a better time.
After reading the official website documentation, you can think of the unbind hook. Once the instruction is unbound, the document automatically unbinds the event.
Note here that the click event needs to be assigned to el.handle to facilitate unbinding.
The optimized instruction code is as follows:
Vue.directive("click-outside", {
// el is the bindings element, expression is the dynamic parameter, vnode is the virtual node of the bindings element, vnode.context is the VM instance of the node
bind(el, bindings, vnode) {
el.handle = e= > {
// Click on the binding directive element to trigger the function passed in
if(! el.contains(e.target)) {letmethod = bindings.expression; vnode.context[method](); }};document.addEventListener("click", el.handle);
},
unbind(el) {
// Related events are removed
document.removeEventListener("click", el.handle); }});Copy the code
Additional: auto focus instruction
I don’t know if you notice that even if we put the autofocus property on the input side, the focus is gone for a second, and then the cursor is gone.
Because the code in #app enters a fragment, compiles it, and then redumps it. So there’s an initial moment of focus, and then when you pour it in, the focus is gone.
So, if you want auto-focus, you can encapsulate a simple command, just use the official website here.
// <input type="text" v-focus>
Vue.directive('focus', {
// When the bound element is inserted into the DOM
inserted: function (el) {
// Focus the element
el.focus()
}
})
Copy the code