1. Review the Directives

(1) Hook function

A directive defining an object can provide the following hook functions:

  • 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 node (only ensures that the parent exists, but not necessarily that it 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.

(2) Hook function arguments

<div v-directive.foo.bar="1+1"></div>Copy the code

Take the two DOM elements above as an example:

  • elThe: directive can be used to directly manipulate the DOM. In the two examples above, it is the div element itself.
  • binding: An object containing the following properties:
  1. Name: indicates the directive name, excluding the V – prefix. All of the examples above are ‘directive’ strings

  2. Value: indicates the binding value of the directive. A = method; b = 2

  3. OldValue: The previous value of the instruction binding, available only in update and componentUpdated hooks.

  4. Expression: a string of instruction expressions. Example A is a ‘method’ string, example B is a ‘1+1’ string

  5. Arg: the argument passed to the directive. A example is the string ‘foo’.

  6. Modifiers: An object that contains modifiers. B Examples are {foo: true, bar: true} objects

  • Vnode: virtual node generated by Vue compilation.

  • OldVnode: The last virtual node, available only in update and componentUpdated hooks.

See Vue Directive for more details

2. The element – the directives of the UI

(1)mousewheel.js

Source:

import normalizeWheel from 'normalize-wheel'; const isFirefox = typeof navigator ! == 'undefined' && navigator.userAgent.toLowerCase().indexOf('firefox') > -1; const mousewheel = function(element, callback) { if (element && element.addEventListener) { element.addEventListener(isFirefox ? 'DOMMouseScroll' : 'mousewheel', function(event) { const normalized = normalizeWheel(event); callback && callback.apply(this, [event, normalized]); }); }}; export default { bind(el, binding) { mousewheel(el, binding.value); }}Copy the code

Explanation:

First, explain the introduction of normalize-wheel, a package that is used to listen for mouse wheel events uniformly. Wheel events can be a tedious process when considering compatibility between different browsers and old and new versions of browsers. In different types and versions of browsers, we can scroll through the following 4 DOM event listener wheels:

  1. ‘Wheel’ : Chrome(61+), FireFox(17+), IE(9+)

  2. ‘Mousewheel’ : Chrome, IE(6+), Opera, Safari

  3. ‘MozMousePixelScroll: FireFox (3.5 only!

  4. ‘DOMMouseScroll: FireFox (0.9.7 +)

To add insult to injury, the value of the event parameter passed to the callback function for the heavily used ‘mousewheel’ event also varies by browser, device and operating system. For example:

  • event.detail: This value is always 0 for all browsers except Opera. In Opera, a positive value means the scroll bar is moving to the bottom or right, and a negative value means the scroll bar is moving to the top or left. In Mac, however, the value is calculated based on the amount of accelerated scrolling. In Linux, the value will always be either 2 or -2.
  • event.wheelDeltaX&event.wheelDeltaY: Chrome(window), Chrome(Linux), Opera, Safari, these two values are different, too many do not want to write the article, interested to seeMDN mousewheel.

Therefore, in order to unify listening events and callback incoming parameters, here is a reference to the ‘normalize-wheel’ component extracted from Facebook’s fixed-data-table component.

const normalized = normalizeWheel(event);
Copy the code

After executing the above code returned by the normalized data structure is: {spinX, spinY, pixelX pixelY}. These parameters can be explained by referring to the explanations in the source code:

spin is trying to normalize how far the wheel was spun (or trackpad dragged). This is super useful for zoom support where you want to throw away the chunky scroll steps on the PC and make those equal to the slow and smooth tiny steps on the Mac. Key data: This code tries to resolve a single slow step on a wheel to 1.

SpinX (horizontal) and spinY (vertical) are calculated in the same way as incremental scrolling of Mac in mousewheel, in abstract scrolling units. In the scrolling event, spinY=1 if the vertical displacement is one distance scrolling, and spinY=2 if the vertical displacement is two distances scrolling. If the value is regular, scroll to the right or down; if the value is negative, scroll to the left or up.

pixel is normalizing the desired scroll delta in pixel units. You’ll get the crazy differences between browsers, but at least it’ll be in pixels!

Meaning that pixelX (landscape) and pixelY (portrait) show the shift in pixels. If pixelY is 100, it will move down 100px.

Why are there spinX, spinY (or pixels)?

 spinX is a 2-finger side drag on the trackpad, and a shift + wheel turn with a mouse. It results in side-scrolling in the browser by default. 

 spinY is what you expect — it’s the classic axis of a mouse wheel.

This paragraph is used to explain why spinX and spinY, or pixelX and pixelY. I don’t think there’s much to explain. Horizontal scrolling events can be triggered by the laptop trackpad or by holding shift+ scroll wheel.

In addition, the introduced normalizeWheel also has a static method called getEventType (see below for the source code), which will tell you which DOM event is most suitable for listening for scroll events in the user’s browser.

/**
 * The best combination if you prefer spinX + spinY normalization.  It favors
 * the older DOMMouseScroll for Firefox, as FF does not include wheelDelta with
 * 'wheel' event, making spin speed determination impossible.
 */
normalizeWheel.getEventType = function() /*string*/ {
  return (UserAgent_DEPRECATED.firefox())
           ? 'DOMMouseScroll'
           : (isEventSupported('wheel'))
               ? 'wheel'
               : 'mousewheel';
};

module.exports = normalizeWheel;
Copy the code

Therefore, for the mousewheel.js code that starts with element-UI, you can also change it like this:

const mousewheel = function(element, callback) { if (element && element.addEventListener) { // element.addEventListener(isFirefox ? 'DOMMouseScroll' : 'mousewheel', function (event) {/ / change the following line element. AddEventListener (normalizeWheel. GetEventType (), function(event) { const normalized = normalizeWheel(event); callback && callback.apply(this, [event, normalized]); }); }}Copy the code

(2)repeat-click.js

Source:

import { once, on } from 'element-ui/src/utils/dom';

export default {
  bind(el, binding, vnode) {
    let interval = null;
    let startTime;
    const handler = () => vnode.context[binding.expression].apply();
    const clear = () => {
      if (Date.now() - startTime < 100) {
        handler();
      }
      clearInterval(interval);
      interval = null;
    };

    on(el, 'mousedown', (e) => {
      if (e.button !== 0) return;
      startTime = Date.now();
      once(document, 'mouseup', clear);
      clearInterval(interval);
      interval = setInterval(handler, 100);
    });
  }
}
Copy the code

Explanation:

Here’s a brief description of what the imported ON and once methods do: The imported ON method is used to bind to the listener event, which is equivalent to addEventListener. AddEventListener (type(event type),listener(callback function),{once:true}) Element-ui encapsulates the appearance mode of the two methods, solving compatibility issues between different browsers.

What the above code does is that the dom element bound to the directive triggers the callback function that executes the directive binding every 100ms after the mouse is pressed. The callback function is also triggered if the time difference between the release of the mouse and the time when the mouse was pressed is less than 100ms. In general, a long mouse press will trigger the callback function every 100ms. Short time, less than 100ms will also trigger the callback function.

The most intuitive element of the element-UI that uses this directive is the el-input-number. The effect is as follows:

(3)clickoutside.js

This directive is in SRC \utils\ clickout.js.

I have written the corresponding article analysis before, and the address is directly posted here:

Know v-clickoutside directive