preface

Vue.js is a set of progressive frameworks for building user interfaces (official description). In layman’s terms, Vue. Js is a lightweight, easy-to-use, convenient and flexible front-end MVVM framework. Concise API, good and sound Chinese documentation, so that developers can easily use the Vue framework.

This series of articles will combine some CAI experiences (KENG) and some cases in the use of Vue to export some knowledge of the Vue framework and consolidate the understanding of the Vue framework.

Vue custom command

The paper

In addition to providing default built-in directives, Vue also allows developers to customize directives based on the actual situation, which is useful when developers need to operate on common DOM elements in certain scenarios.

Register custom directives

Like components, Vue custom directives are registered globally and locally. Directive (id, [definition]). The first parameter is a custom directive name (the name of the directive does not need to be prefixed by v-. It is automatically prefixed by default. The second argument can be object data or an instruction function.

<div id="app" class="demo">
    <! -- Global registration -->
    <input type="text" placeholder="I'm a global custom directive." v-focus>
</div>
<script>
    Vue.directive("focus", {
        inserted: function(el){ el.focus(); }})new Vue({
        el: "#app"
    })
</script>
Copy the code

In this simple example, we registered a V-focus directive to automatically get the focus of the input field after the page was loaded. Inserted is the hook function of a custom instruction, more about this later.

With global registration now, let’s look at how to register local custom directives by adding the Cache object data to the Vue instance.

<div id="app" class="demo">
    <! -- Local registration -->
    <input type="text" placeholder="I'm a local custom instruction." v-focus2>
</div>
<script>
    new Vue({
        el: "#app",
        directives: {
            focus2: {
                inserted: function(el){ el.focus(); }}}})</script>
Copy the code

Hook function

An instruction definition object can provide the following hook functions (all optional) :

  • Bind: Called only once, the first time a directive is bound to an element. This is where you can perform one-time initialization Settings

  • Inserted: Called when the bound element is inserted into a parent (the parent is guaranteed to exist, but not necessarily inserted into the document).

  • Update: called when the component’s VNode is updated, but may occur 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: Invoked when the VNode of the component where the directive resides and its child VNodes are all updated.

  • Unbind: Called only once, when an instruction is unbound from an element.

This paragraph is from the official document copy, I believe it should be clear at a glance.

So how do you use these hook functions? Let’s take a look at a few arguments to the hook function. The instruction hook function is passed the following arguments:

  • El: The element to which the directive binds, which can be used to manipulate the DOM directly, is the element in which the directive is placed.

  • Binding: An object containing several attributes, which are described in more detail in the official documentation.

  • Vnode: virtual node generated by Vue compilation.

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

Custom directives can also pass multiple values, which can be passed using javascript expression literals, as shown in the following 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

So with all this theoretical knowledge, let’s start writing a simple case. Consider a scenario like this: When you are reading a website pictures, may be due to the larger image resources and load is slow, it takes a short period of time to present to the eyes, the experience is certainly not too friendly (like website page switch, sometimes slow loading resources, in order to give the user a better experience, usually first out a friendly prompt page is loaded). Therefore, the function of this case is to display the default background image before the image resource is loaded. When the image resource is actually loaded, the real image is placed in the corresponding position and displayed.

<div id="app2" class="demo">
    <div v-for="item in imageList">
        <img src=".. /assets/image/bg.png" alt="Default diagram" v-image="item.url">
    </div>
</div>
<script>
    Vue.directive("image", {
        inserted: function(el, binding) {
            // Use the delay operation for the real effect
            setTimeout(function(){
                el.setAttribute("src", binding.value);
            }, Math.random() * 1200)}})new Vue({
        el: "#app2".data: {
            imageList: [{url: "http://consumer-img.huawei.com/content/dam/huawei-cbg-site/greate-china/cn/mkt/homepage/section4/home-s4-p10-plus.jpg"
                },
                {
                    url: "http://consumer-img.huawei.com/content/dam/huawei-cbg-site/greate-china/cn/mkt/homepage/section4/home-s4-watch2-pro-ban ner.jpg"
                },
                {
                    url: "http://consumer-img.huawei.com/content/dam/huawei-cbg-site/en/mkt/homepage/section4/home-s4-matebook-x.jpg"}]}})</script>
Copy the code

The source code interpretation

The Vuetify framework library provides several custom commands, including v-resize for the browser window, v-Scroll for the browser bar, and other custom commands.

V-resize User-defined command

In SRC /directives/ resie.js, is the core code for the V-Resize custom directive operation.

function inserted (el, binding) {
    // The binding value of the directive is a function function
    const callback = binding.value

    // The number of milliseconds to delay function execution
    const debounce = binding.arg || 200

    // Disallows default actions associated with events
    const options = binding.options || { passive: true }

    let debounceTimeout = null
    const onResize = (a)= > {
        clearTimeout(debounceTimeout)
        debounceTimeout = setTimeout(callback, debounce, options)
    }

    // Listen for window scaling
    window.addEventListener('resize', onResize, options)

    // Store parameters that listen for window zooming events when unbind the hook function
    el._onResize = {
        callback,
        options
    }

    if(! binding.modifiers || ! binding.modifiers.quiet) { onResize() } }Emitted when the bound DOM element is removed
function unbind (el, binding) {
    const { callback, options } = el._onResize

    window.removeEventListener('resize', callback, options)
    delete el._onResize
}

export default {
    // Directive name
    name: 'resize',
    inserted,
    unbind
}
Copy the code

Inserted and unbind are defined. The unbind hook function is used to remove the listener event. Inserted Hook function, the binding listens for the window scaling event and executes the callback, and uses simple function shakiness to prevent too much manipulation, and this is how the process looks.

You may find that the above code is written in ES6 standard syntax. For those who are not familiar with THE ES6 syntax, it may be difficult to read. Then, we will convert the es5 syntax to fully implement the function of this instruction. Because this is the inevitable trend of front-end development.

function insertedFn (el, binding) {
    var callback = binding.value;
    var debounce = 200;
    var options = {passive: true};
    var debounceTimeout = null;
    var onResize = function () {
        clearTimeout(debounceTimeout);
        debounceTimeout = setTimeout(callback, debounce, options);
    }

    window.addEventListener("resize", onResize, options);

    el._onResize = {
        callback: callback,
        options: options
    };
}

function unbindFn (el, binding) {
    var callback = el._onResize.callback;
    var options = el._onResize.options;
    window.removeEventListener("resize", callback, options);
    delete el._onResize;
}

Vue.directive("resize", {
    inserted: insertedFn,
    unbind: unbindFn
})
Copy the code

The full example can be viewed here: the V-resize custom directive.

More examples of Vuetify’s custom directives can be found on Github at github.com/vuetifyjs/v… .

conclusion

Listed are some simple knowledge of Vue custom instructions, there will be various pits in different scenarios of actual projects. Vue custom instructions can also be used in the picture lazyload scenario, vue-lazyload is the use of custom instructions to achieve lazyload picture, if possible, can be analyzed after a wave of vue-lazyload source code.

Afterword.

In the spirit of learning and summarizing the attitude of the article, any mistakes and problems can be pointed out on Github. Examples are posted on Github at github.com/webproblem/… .