SoFunction
Updated on 2025-04-14

Detailed explanation of the packaging of common global custom instructions for Vue2

Preparation

Create directory file: src/directive/

import copy from "./copy";
import longpress from "./longpress"
import debounce from "./debounce";
import emoji from "./emoji";
import LazyLoad from "./LazyLoad";
import permission from "./permission";
import waterMarker from "./waterMarker";
import draggable from "./draggable";
import empty from "./empty";
const directives = {
  copy,longpress,debounce,emoji,LazyLoad,permission,waterMarker,draggable,empty
};
export default {
  install(Vue) {
    (directives).forEach((key) => {
      (key, directives[key]);
    });
  },
};

Then introduce and register

// Introduce global custom commandsimport directive from './directive'
(directive)

Comment: Custom directive hook function

  • bind: Only once, the command is used when the first time it is bound to an element, you can use this hook function to define an initial action that is executed once during binding
  • inserted: Called when the bound element is inserted into the parent node (it can be called if the parent node exists, and it does not need to exist in the document)
  • update: Called when the template where the bound element is located is updated. Regardless of whether the binding value changes, by comparing the changes before and after the update, unnecessary updates can be ignored.
  • componentUpdated: Called when the template where the bound element is located has completed an update cycle
  • unbind: Only called once, when the directive is unbined with the element

Notes on the parameters of the hook function:

  • el: The element bound to the instruction can be used to directly operate the DOM
  • binding: An object containing the following properties:
    • name: directive name, excluding v-prefix
    • value: The binding value of the instruction, this value is passed in when used. If it is a reference, it will be copied directly. If it is a function, it can be called directly.
    • oldValue: The previous value bound by the directive is only available in update and componentUpdated, and is available regardless of whether the value changes or not.
    • expression: the expression or variable name of the bound value,
    • arg: The parameter passed to the instruction, for example, v-my-directive: foo, the value of arg is "foo"
    • modifiers: an object containing modifiers. For example, the value of modifier object modifiers is {foo:true, bar:true}
  • vnode: Vue compiles the generated virtual node.
  • oldVnode: Previous virtual node, available only in update and componentUpdated hooks.

Except for el, all other parameters should be read-only and must not be modified.

One-click copy

Requirements: Implement one-click copying of text content, used for right-click pasting

Ideas:

Dynamically create textarea tags, set readOnly attribute and move out of the visual area

Assign the value to be copied to the value property of the textarea tag and insert it into the body

Select the value textarea and copy

Remove the textarea inserted in the body

Binding events on the first call, removing events when unbinding

export default {
 bind(el, { value }) {
   el.$value = value;
    = () => {
     if (!el.$value) {
       // When the value is empty, give a prompt.  Can be carefully designed according to the project UI       ("No copy content");
       return;
     }
     // Dynamically create textarea tags     const textarea = ("textarea");
     // Set the textarea to readonly to prevent the keyboard from being automatically evoked under iOS, and to move the textarea out of the visual area      = "readonly";
      = "absolute";
      = "-9999px";
     // Assign the value to copy to the value attribute of the textarea tag      = el.$value;
     // Insert textarea into body     (textarea);
     // Select the value and copy     ();
     const result = ("Copy");
     if (result) {
       ("Copy successfully"); // Can be carefully designed according to the project UI     }
     (textarea);
   };
   // // Bind click event is the so-called one-click copy   ("click", );
 },
 // Triggered when the value passed in is updated componentUpdated(el, { value }) {
   el.$value = value;
 },
 // When the command is unbinded with the element, remove the event binding unbind(el) {
   ("click", );
 },
};
<button v-copy="copyContent">Click to copy</button>

data(){
 return {
   copyContent: "Copyed information",
 }
}

One-click long press

need:

Implement long pressing, the user needs to press and hold the button for a few seconds to trigger the corresponding event

Ideas:

Create a timer and execute the function after 2 seconds

The mousedown event is triggered when the user presses the button, and the timer is started; the mouseout event is called when the user releases the button.

If the mouseup event is triggered within 2 seconds, clear the timer as a normal click event

If the timer is not cleared within 2 seconds, it is determined that a long press can be used to execute the associated function.

On mobile, you should consider touchstart and touchend events

export default {
 bind: function (el, binding, vNode) {
   //Judge type   if (typeof  !== "function") {
     throw "callback must be a function";
   }
   // Define variables   let pressTimer = null;
   // Create a timer and execute it after two seconds   let start = (e) => {
     if ( === "click" &&  !== 0) {
       return;
     }
     if (pressTimer === null) {
       pressTimer = setTimeout(() => {
         handler();
       }, 2000);
     }
   };
   // Cancel the timer   let cancel = (e) => {
     if (pressTimer !== null) {
       clearTimeout(pressTimer);
       pressTimer = null;
     }
   };
   // Run the function   const handler = (e) => {
     (e);
   };
   // Add event listener   ("mousedown", start);
   ("touchstart", start);
   // Cancel the timer   ("click", cancel);
   ("mouseout", cancel);
   ("touchend", cancel);
   ("touchcancel", cancel);
 },
 // Triggered when the value passed in is updated componentUpdated(el, { value }) {
   el.$value = value;
 },
 // When the command is unbinded with the element, remove the event binding unbind(el) {
   ("click", );
 },
};
<!-- longpress Must be a function -->
<button v-longpress="longpress">Press for two seconds</button>

Anti-shake

need:

Prevent the button from being clicked multiple times in a short period of time, and use the anti-shake function to limit the number of clicks only once within the specified time.

Ideas:

Define a method that delays execution. If the method is called again within the delay time, the execution time will be recalculated.

Bind time to the click method.

export default {
    inserted: function(el,binding) {
        let timer;
        ("click", () => {
            if(timer) {
                clearTimeout(timer)
            }
            timer = setTimeout(() => {
                ()
            },1000)
        })
    }
}
<!-- Anti-shake -->
<button v-debounce="debounceClick">点击Anti-shake</button>

 debounceClick() {
    ("It should only be triggered once");
  },

Limit input box type

Form input encountered during development often has restrictions on the input content, such as not being able to enter emoticons and special characters, only digits or letters, etc.

Our regular method is to process the on-change event of each form. This is the code volume is relatively large and difficult to maintain

need:

According to regular expressions, design instructions to customize the input rules of form. The following is an example of prohibiting the input of emoticons and special characters.

let findEle = (parent, type) => {
return () === type
  ? parent
  : (type);
};

const trigger = (el, type) => {
const e = ("htmlEvents");
(type, true, true);
(e);
};

export default {
bind: function (el, binding, vnode) {
  // Regular rules can be customized according to requirements  // var regRule = /[^u4E00-u9FA5|d|a-zA-Z|rns,.?!,。?!…—&$=()-+/*{}[]]|s/g;
  var regRule = /[^\u4E00-\u9FA5\dA-Za-z]|/g; // Only enter Chinese, English and numbers  let $inp = findEle(el, "input");
  el.$inp = $inp;
  $ = function () {
    let val = $;
    $ = (regRule, "");
    trigger($inp, "input");
  };
  $("keyup", $);
},
unbind: function (el) {
  el.$("keyup", el.$);
},
};

use

 <!-- Limit input types -->
<input type="text" v-model="value" v-emoji>

Lazy image loading

Requirements: Implement a lazy image loading instruction, which only loads pictures in the visible area of ​​the browser.

Ideas:

The principle of lazy image loading is mainly to determine whether the current image has reached the visual area.

Get all the pictures Dom and traverse each picture to determine whether the current picture is within the visual area.

If it arrives, set the src attribute of the picture, otherwise the default picture will be displayed

There are two ways to achieve lazy loading of images. One is to bind srcoll events for monitoring, and the other is to use IntersectionObserver to determine whether the image has reached the visual area.

But there are browser compatibility issues.

The following encapsulates two methods of compatible with a lazy loading instruction to determine whether the browser supports the IntersectionObserver API.

If supported, use IntersectionObserver to implement lazy loading, otherwise use the srcoll event listening + throttling method.

When using:<img v-LazyLoad="" /> Change the src of the tag in the component to v-LazyLoad

export default {
  install(Vue, options) {
    const defaultSrc = ; 
    ("lazy", {
      bind(el, binding) {
        (el, , defaultSrc);
      },
      inserted(el) {
        if (IntersectionObserver) {
          (el);
        } else {
          (el);
        }
      },
    });
  },
  // Initialization  init(el, val, def) {
    ("data-src", val);
    ("src", def);
  },
  // Use IntersectionObserver to listen on el  observe(el) {
    var io = new IntersectionObserver((entries) =&gt; {
      const realSrc = ;
      if (entries[0].isIntersecting) {
        if (realSrc) {
           = realSrc;
          ("data-src");
        }
      }
    });
    (el);
  },
  // Listen to scroll events  listenerScroll(el) {
    const handler = (, 300);
    (el);
    ("scroll", () =&gt; {
      handler(el);
    });
  },
  // Load real pictures  load(el) {
    const windowHeight = ;
    const elTop = ().top;
    const elBtm = ().bottom;
    const realSrc = ;
    if (elTop - windowHeight &lt; 0 &amp;&amp; elBtm &gt; 0) {
      if (realSrc) {
         = realSrc;
        ("data-src");
      }
    }
  },
  // throttling  throttle(fn, delay) {
    let timer;
    let prevTime;
    return function (...args) {
      const currTime = ();
      const context = this;
      if (!prevTime) prevTime = currTime;
      clearTimeout(timer);

      if (currTime - prevTime &gt; delay) {
        prevTime = currTime;
        (context, args);
        clearTimeout(timer);
        return;
      }

      timer = setTimeout(function () {
        prevTime = ();
        timer = null;
        (context, args);
      }, delay);
    };
  },
};

Verification of permissions for specified containers on the page

background:

In some background management systems, we may need to make some judgments on operational permissions based on user roles.

Many times we roughly add v-if/v-show to an element to display and hide it.

However, if the judgment conditions are cumbersome and multiple places need to be judged, the code in this method is not only inelegant but also redundant.

In this case, we can handle it through global custom directives.

Requirements: Customize a permission directive to display and hide the Dom that requires permission judgment.

Ideas:

Customize an array of permissions

Determine whether the user's permissions are in this array. If so, it will be displayed. Otherwise, it will be removed.

function checkArray(key) {
  let arr = ["1", "2", "3", "4"];
  let index = (key);
  if (index &gt; -1) {
    return true; // Permissions  } else {
    return false; // No permission  }
}

export default {
  inserted: function (el, binding) {
    let permission = ; // Get the value of v-permission    if (permission) {
      let hasPermission = checkArray(permission);
      if (!hasPermission) {
        // No permissions to remove Dom elements         &amp;&amp; (el);
      }
    }
  },
};

When using: Example

&lt;!-- show --&gt;
  &lt;button v-permission="'1'"&gt;Permission Button1&lt;/button&gt;

  &lt;!-- 不show --&gt;
  &lt;button v-permission="'10'"&gt;Permission Button2&lt;/button&gt;&lt;/div&gt;

Add watermark to the page

Requirements: Add background watermark to the entire page

Ideas:

Use the canvas feature to generate a base64 format image file, set its font size, color, etc.

Set it as a background image to achieve the page or component watermark effect

function addWaterMarker(str, parentNode, font, textColor) {
  // Watermark text, parent element, font, text color  var can = ("canvas");
  (can);
   = 200;
   = 150;
   = "none";
  var cans = ("2d");
  ((-20 * ) / 180);
   = font || "16px Microsoft JhengHei";
   = textColor || "rgba(180, 180, 180, 0.3)";
   = "left";
   = "Middle";
  (str,  / 10,  / 2);
   = "url(" + ("image/png") + ")";
}
export default {
    bind: function (el, binding) {
        addWaterMarker(, el, , )
    },
}

When using:

&lt;div v-waterMarker="{text:'bjg All rights reserved',textColor:'rgba(180, 180, 180, 0.4)'}"&gt;&lt;/div&gt;

Specify DOM drag and drop

need:

Implement a drag and drop command, which can drag elements in any viewing area of ​​the page.

Ideas:

Set the element that needs to be dragged is relative positioning, and its parent element is absolute positioning.

Record the current left and top values ​​of the target element when the mouse is pressed (onmousedown).

When the mouse is onmousemove, the change values ​​of the horizontal and vertical distances of each movement are calculated, and the left and top values ​​of the element are changed.

Complete drag and drop when the mouse is released (onmouseup)

export default {
 inserted: function (el) {
    = "move";
    = function (e) {
     let disx =  - ;
     let disy =  - ;
      = function (e) {
       let x =  - disx;
       let y =  - disy;
       let maxX =
          -
         parseInt((el).width);
       let maxY =
          -
         parseInt((el).height);
       if (x < 0) {
         x = 0;
       } else if (x > maxX) {
         x = maxX;
       }

       if (y < 0) {
         y = 0;
       } else if (y > maxY) {
         y = maxY;
       }

        = x + "px";
        = y + "px";
     };
      = function () {
        =  = null;
     };
   };
 },
};

When using:

<div class="el-dialog" v-draggable></div>

Specify whether the container is displayed based on the content

If the object or array passed in is empty, the DOM element will not be displayed

// Determine whether the object or array is emptyfunction isEmpty(obj) {
 if ((obj)) {
   return  === 0;
 } else if (typeof obj === "object") {
   return (obj).length === 0;
 }
 return true; // Other types are empty by default}
export default {
 inserted: function (el, binding) {
   const value = ;
   if (isEmpty(value)) {
      = "none";
   }
 },
};

The above is the detailed explanation of the packaging of Vue2's commonly used global custom instructions. For more information about Vue2's global custom instructions, please pay attention to my other related articles!