What is a directive

Before we get started, let’s start with the word instruction system. Instruction system is the language system of computer hardware, also known as machine language, and it’s the primary property of the computer that systems programmers see. So the instruction system represents the basic functions of the computer and determines the capabilities required of the machine

Vue provides a set of operations that are more convenient for data-driven views. These operations are called the instruction system. The in-line properties that we see at the beginning of the V – are all instructions. Different instructions can do different things or do different things in addition to the core functions. The default built-in instructions (V-Model and V-show), Vue also allows you to register custom directives in several ways:

// instantiates an instruction that has no argument 'v-xxx' // -- passes the value to the instruction. 'v-xxx="value"' Such as ` v - HTML = "' content < / p > < p >" ` ` v - XXX = "' string '" ` / / - parameter (` arg `), For example, 'v-bind:class="className"' v-xxx:arg="value" '// -- use the modifier (' modifier') 'v-xxx:arg. Modifier ="value"'Copy the code

Two, how to achieve

Directive: the first argument to the directive is the name of the directive. The second argument to the directive can be object data or a directive function

// Register a global custom directive v-focus

Directive ('focus', {// when the bound element is inserted into the DOM... El.focus (); // Inserted: function (el) {el.focus(); // Inserted: function (el) {// Element el.focus();Copy the code

Local registration is done by setting the directive property in the component options option

Inserted: function (el) {el.focus() // Directives: {focus: {// Definition of directivesCopy the code

Then you can use the new V-Focus Property on any element in the template, as follows:

<input v-focus />
Copy the code

Custom directives also have hook functions just like components:

  • Bind: called only once, the first time a directive is bound to an element. This is where you can do one-time initialization
  • Inserted: called when the bound element is inserted into the parent (only ensures that the parent exists, but not necessarily has been inserted into the document)
  • Update: called when the component’s VNode is updated, but may occur before its children 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: component VNode directive and its children VNode all updated call
  • Unbind: called only once, when a directive is unbound from an element

All hook functions take the following arguments:

  • El: The element bound by the directive, which can be used to manipulate the DOM directly
  • Binding: an object containing the following properties:
    • Name: indicates the directive name, excluding the V – prefix.
    • Value: indicates the binding value of a directive. For example, if v-my-directive=”1 + 1″, the binding value is 2.
    • OldValue: The previous value of the instruction binding, available only in update and componentUpdated hooks. It is available regardless of whether the value has changed.
    • Expression: a string of instruction expressions. For example, if v-my-directive=”1 + 1″, the expression is “1 + 1”.
    • Arg: Parameter passed to the instruction, optional. For example, in v-my-directive:foo, the parameter is “foo”.
    • Modifiers: An object that contains 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 last virtual node, available only in update and componentUpdated hooks

All parameters except EL should be read-only and should not be modified. If you need to share data between hooks, it is recommended to use the dataset of the element as an 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>Copy the code

3. Application Scenarios

Using custom components Components can be used in some of our everyday scenarios. Here are a few examples of custom components:

  • Image stabilization
  • Lazy image loading
  • One-click Copy function
  • Input box anti – shake

For example, you can set a custom V-throttle command to do this:

Directive (' throttleTime ', {bind: (el, binding) => {let throttleTime = binding. // If (! ThrottleTime) {// If the user does not set the throttleTime, 2s throttleTime = 2000 by default; } let cbFun; el.addEventListener('click', event => { if (! CbFun) {// First time to execute cbFun = setTimeout(() => {cbFun = null; }, throttleTime); } else { event && event.stopImmediatePropagation(); } }, true); }}); < button@click ="sayHello" > </button>Copy the code

Lazy image loading – Sets a custom v-lazy component to complete lazy image loading

Const LazyLoad = {// install method install(Vue,options){// replace the loading image let defaultSrc = options.default; Vue.directive('lazy',{ bind(el,binding){ LazyLoad.init(el,binding.value,defaultSrc); }, inserted(el){// insert if('IntersectionObserver' in window){lazyload.observe (EL); }else{ LazyLoad.listenerScroll(el); }},})}, // init(el,val,def){// data-src stores the real SRC el.setAttribute('data-src',val); El.setattribute (' SRC ',def); }, // Using IntersectionObserver to listen to EL observe(EL){let IO = new IntersectionObserver(entries => {let realSrc = el.dataset.src; if(entries[0].isIntersecting){ if(realSrc){ el.src = realSrc; el.removeAttribute('data-src'); }}}); io.observe(el); }, listenerScroll(el){let handler = lazyload.load (lazyload.load,300); LazyLoad.load(el); window.addEventListener('scroll',() => { handler(el); }); }, / / load the real images load (el) {let windowHeight = document. The documentElement. ClientHeight let elTop = el. GetBoundingClientRect (). The top;  let elBtm = el.getBoundingClientRect().bottom; let realSrc = el.dataset.src; if(elTop - windowHeight<0&&elBtm > 0){ if(realSrc){ el.src = realSrc; el.removeAttribute('data-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;Copy the code

One-click Copy function

import { Message } from 'ant-design-vue'; Const vCopy = {// /* bind = const vCopy = {// /* bind = const vCopy = { */ bind(el, {value}) {el.$value = value; El.handler = () => {if (! El. $value) {// if the value is null, it will give you a Message. Warning (' no copy '); return; Const textarea = document.createElement('textarea'); Textarea. readonly = 'readonly'; // Set the textarea to readonly to prevent automatic keyboard arousal on iOS and remove the Textarea from the visual area. textarea.style.position = 'absolute'; textarea.style.left = '-9999px'; Textarea. value = el.$value; // Assign the copy value to the value attribute of the textarea tag. / / insert the textarea to document in the body. The body. The appendChild (textarea); Textarea.select (); textarea.select(); // textarea.setSelectionRange(0, textarea.value.length); const result = document.execCommand('Copy'); If (result) {message.success (' copy succeeded '); } document.body.removeChild(textarea); }; El.addeventlistener ('click', el.handler); }, // componentUpdated(el, {value}) {el.$value = value; }, // unbind(el) {el.removeEventListener('click', el.handler); }}; export default vCopy;Copy the code

There are many application scenarios for custom components, such as drag-and-drop instructions, page watermarking, permission verification, and so on