A detailed guide to custom directives in Vue

A detailed guide to custom directives in Vue

1. What is a custom instruction?

The inline attributes starting with v- that we see are all instructions. Different instructions can complete or implement different functions and perform low-level operations on ordinary DOM elements. This is when custom instructions are used. In addition to the default built-in instructions for core functions (v-model and v-show), Vue also allows you to register custom instructions.

Several ways to use the command:

//Will instantiate a command, but this command has no parameter `v-xxx`
 
// -- Pass the value to the instruction `v-xxx="value"`  
 
// -- Pass the string into the directive, such as `v-html="'<p>Content</p>'"`
`v-xxx="'string'"` 
 
// -- pass parameters (`arg`), such as `v-bind:class="className"`
`v-xxx:arg="value"` 
 
// -- Use modifiers (`modifier`)
`v-xxx:arg.modifier="value"` 

2. How to customize instructions

Registering a custom directive can be done globally or locally.

Global registration is mainly registered using the Vue.directive method

The first parameter of Vue.directive is the name of the directive (without the v- prefix), and the second parameter can be object data or a directive function

// Register a global custom directive `v-focus`
Vue.directive('focus', {
  // When the bound element is inserted into the DOM...
  inserted: function (el) {
    // Focus element el.focus() // A small function that automatically focuses the input box after the page is loaded}
})

Local registration is done by setting the directive attribute in the component options

directives: {
  focus:
    // Definition of instruction inserted: function (el) {
      el.focus() // A small function that automatically focuses the input box after the page is loaded}
  }
}

You can then use the new v-focus property on any element in your template like this:

<input v-focus />

Hook function

Custom instructions also have hook functions like components:

  • bind: Called only once, when the directive is first bound to an element. Here you can perform a one-time initialization setup
  • inserted: called when the bound element is inserted into the parent node (it only guarantees that the parent node exists, but it is not necessarily inserted into the document)
  • update: Called when the VNode of the component is updated, but it may happen before its child VNodes are updated. The value of the instruction may or may not have changed. But you can ignore unnecessary template updates by comparing the values ​​before and after the update.
  • componentUpdated: Called after the VNode of the component where the instruction is located and its child VNodes are all updated
  • unbind: Called only once, when the instruction is unbound from the element

All hook function parameters are as follows:

  • el: The element to which the instruction is bound, which can be used to directly manipulate the DOM
  • binding: An object containing the following properties:

`name`: The name of the directive, without the v- prefix.

`value`: The binding value of the directive. For example, in v-my-directive="1 + 1", the binding value is 2.

`oldValue`: The previous value of the directive binding, only available in update and componentUpdated hooks. Available whether the value has changed or not.

`expression`: A directive expression as a string. For example, in v-my-directive="1 + 1", the expression is "1 + 1".

`arg`: Parameter passed to the command, optional. For example, in v-my-directive:foo, the parameter is "foo".

`modifiers`: An object containing modifiers. For example: in v-my-directive.foo.bar, the modifier object is { foo: true, bar: true }

`vnode`: Virtual node generated by Vue compilation

`oldVnode`: the previous virtual node, only available in update and componentUpdated hooks

Except for el, all other parameters should be read-only and should not be modified. If you need to share data between hooks, it is recommended to do so through the element's dataset

For example:

<div v-demo="{ color: 'white', text: 'hello!' }"></div>
<script>
    Vue.directive('demo', function (el, binding) {
    console.log(binding.value.color) // "white"
    console.log(binding.value.text) // "hello!"
    })
</script>

3. Application Scenarios

Using custom components can meet some of our daily scenarios. Here are a few examples of custom components:

  • Stabilization
  • Lazy loading of images
  • One-click Copy function

Input box anti-shake

In this case, set a v-throttle custom instruction to achieve anti-shake

For example:

// 1. Set v-throttle custom directive Vue.directive('throttle', {
  bind: (el, binding) => {
    let throttleTime = binding.value; // Anti-shake timeif (!throttleTime) { // If the user does not set the anti-shake time, the default is 2s
      throttleTime = 2000;
    }
    let cbFun;
    el.addEventListener('click', event => {
      if (!cbFun) { // First execution cbFun = setTimeout(() => {
          cbFun = null;
        }, throttleTime);
      } else {
        event && event.stopImmediatePropagation();
      }
    }, true);
  },
});
// 2. Set v-throttle custom instructions for the button tag <button @click="sayHello" v-throttle>Submit</button>

Lazy loading of images

Set a v-lazy custom component to complete image lazy loading

const LazyLoad = {
    // install method install(Vue,options){
       // Loading image instead of image let defaultSrc = options.default;
        Vue.directive('lazy',{
            bind(el,binding){
                LazyLoad.init(el,binding.value,defaultSrc);
            },
            inserted(el){
                // Compatibility processing if('InterpObserver' in window){
                    LazyLoad.observe(el);
                }else{
                    LazyLoad.listenerScroll(el);
                }
                
            },
        })
    },
    // Initialization init(el,val,def){
        // src stores the real src
        el.setAttribute('src',val);
        // Set src to loading image el.setAttribute('src',def);
    },
    // Use InterpObserver to monitor el
    observe(el){
        let io = new InterpObserver(entries => {
            let realSrc = el.dataset.src;
            if (entries[0].isIntersecting) {
                if(realSrc){
                    el.src = realSrc;
                    el.removeAttribute('src');
                }
            }
        });
        io.observe(el);
    },
    // Listen for scroll events listenerScroll(el){
        let handler = LazyLoad.throttle(LazyLoad.load,300);
        LazyLoad.load(el);
        window.addEventListener('scroll',() => {
            handler(el);
        });
    },
    // Load the real image load(el){
        let windowHeight = document.documentElement.clientHeight
        let elTop = el.getBoundingClientRect().top;
        let elBtm = el.getBoundingClientRect().bottom;
        let realSrc = el.dataset.src;
        if(elTop - windowHeight<0&&elBtm > 0){
            if(realSrc){
                el.src = realSrc;
                el.removeAttribute('src');
            }
        }
    },
    // throttle(fn,delay){
        let timer; 
        let prevTime;
        return function(...args){
            let currTime = Date.now();
            let context = this;
            if(!prevTime) prevTime = currTime;
            clearTimeout(timer);
            
            if (currTime - prevTime > delay) {
                prevTime = currTime;
                fn.apply(context,args);
                clearTimeout(timer);
                return;
            }
 
            timer = setTimeout(function(){
                prevTime = Date.now();
                timer = null;
                fn.apply(context,args);
            },delay);
        }
    }
 
}
export default LazyLoad;

One-click Copy function

import { Message } from 'ant-design-vue';
 
const vCopy = { //
  /*
    bind hook function, called when binding for the first time, can be used to do initialization settings el: the DOM object to be acted on value: the value passed to the instruction, that is, the value we want to copy*/
  bind(el, { value }) {
    el.$value = value; // Use a global property to store the passed value, because this value will be used in other hook functions el.handler = () => {
      if (!el.$value) {
      // When the value is empty, give a prompt. The prompt I use here is the prompt of ant-design-vue. You can use it at will. Message.warning('No copy content');
        return;
      }
      // Dynamically create textarea tag const textarea = document.createElement('textarea');
      // Set the textarea to readonly to prevent the keyboard from automatically appearing on iOS, and move the textarea out of the visible area textarea.readOnly = 'readonly';
      textarea.style.position = 'absolute';
      textarea.style.left = '-9999px';
      // Assign the value to be copied to the value attribute of the textarea tag textarea.value = el.$value;
      //Insert textarea into body document.body.appendChild(textarea);
      // Select the value and copy textarea.select();
      // textarea.setSelectionRange(0, textarea.value.length);
      const result = document.execCommand('Copy');
      if (result) {
        Message.success('Copy successful');
      }
      document.body.removeChild(textarea);
    };
    // Bind click event, which is the so-called one-click copy el.addEventListener('click', el.handler);
  },
  // When the incoming value is updated, trigger componentUpdated(el, { value }) {
    el.$value = value;
  },
  // When the instruction is unbound from the element, remove the event binding unbind(el) {
    el.removeEventListener('click', el.handler);
  },
};
 
export default vCopy;

Drag

<div ref="a" id="bg" v-drag></div>

  directives: {
    drag: {
      bind() {},
      inserted(el) {
        el.onmousedown = (e) => {
          let x = e.clientX - el.offsetLeft;
          let y = e.clientY - el.offsetTop;
          document.onmousemove = (e) => {
            let xx = e.clientX - x + "px";
            let yy = e.clientY - y + "px";
            el.style.left = xx;
            el.style.top = yy;
          };
          el.onmouseup = (e) => {
            document.onmousemove = null;
          };
        };
      },
    },
  },

There are many application scenarios for custom components, such as drag and drop instructions, page watermarks, permission verification, etc.

Summarize

This is the end of this article about custom directives in Vue. For more relevant Vue custom directive content, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope you will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Detailed explanation of Vue custom instructions
  • Vue custom directive details
  • Implementation of Vue custom copy instruction v-copy function

<<:  Analysis of parameter transfer process of driver module in Linux

>>:  How to install Solr 8.6.2 in Docker and configure the Chinese word segmenter

Recommend

Solution to mysql login warning problem

1. Introduction When we log in to MySQL, we often...

Simple encapsulation of axios and example code for use

Preface Recently, when I was building a project, ...

Master-slave synchronous replication configuration of MySQL database under Linux

The advantage of the master-slave synchronization...

Detailed explanation of gcc command usage under Linux system

Table of contents 1. Preprocessing 2. Compilation...

How to handle images in Vue forms

question: I have a form in Vue for uploading blog...

Detailed explanation of as, question mark and exclamation mark in Typescript

1. The as keyword indicates an assertion In Types...

Install Python 3.6 on Linux and avoid pitfalls

Installation of Python 3 1. Install dependent env...

React introduces antd-mobile+postcss to build mobile terminal

Install antd-mobile Global import npm install ant...

Deployment and Chinese translation of the docker visualization tool Portainer

#docker search #docker pull portainer 1. Download...

Detailed explanation of two ways to dynamically change CSS styles in react

The first method: dynamically add a class to show...