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