Understand the principles of elementUI instructions and service modes thoroughly

Posted by theperfectdrug on Sun, 19 May 2019 15:16:05 +0200

Not willing to be a wheeler!!!

Recording the Hard Way of a Picture Preview Component for an Internship Rookie~

Instruction mode and service mode are used in many components of elementUI, such as: loding, message, etc.

Take the loading component as an example:

Instruction mode:

<template>
  <div :v-loading.fullscreen="true">Full screen coverage</div>
</template>

Service model:

const loading = this.$loading({
  lock: true,
  text: 'Loading',
  spinner: 'el-icon-loading',
  background: 'rgba(0, 0, 0, 0.7)'
});

Like most Mengxin, what is service?

  • First look at the directory structure of elmentUI:

Open the node_modules directory and find the elementUI directory below:

The element-ui_ src_ index. JS file has a large registration information for the components, focusing on finding the loading we are looking for.

// ...
// directive instruction loading
Vue.use(Loading.directive)
// prototype service loading
Vue.prototype.$loading = Loading.service
// ...

The instruction Vue.use() is used by Vue to install plug-ins. If the parameter passed in is an object, the object provides an install method. If it is a function, the function is regarded as an install method. When the install method is called, the Vue is passed in as a parameter.

Start!

Let's first look at what the ghost is in the load / index. JS file?

//Instruction file and service file are introduced, directive is instruction mode file, index.js is service mode file.
import directive from './src/directive';
import service from './src/index';

export default {
  //The install method registers components, not to repeat the use of install, as described in the star-pic-list Picture Preview Component article
  install(Vue) {
    Vue.use(directive);
    //Register a $loading object on the prototype object of vue. This $loading is very familiar. Look at the use of the above service mode, use this.$loading, and find the source.
    Vue.prototype.$loading = service;
  },
  //Introduced directive file
  directive,
  //Introduced index.js file
  service
};

v-loading instruction parsing

It's too long, and we only use fullscreen modifiers.

// Introduce. vue file
import Vue from 'vue'
// Introduce load. Vue basic file, which contains component infrastructure, such as html structure, page structure of loading display.
import Loading from './loading.vue'
// The extended () constructor will be highlighted later.
// Vue.extend() is a Vue constructor, which returns an extended instance constructor, that is, a Vue instance constructor with some preset options.

// Mask literally means mask, masking, you can guess that this return constructor through Vue.extend(Loading) should be used for the masking layer when we load.
// loading is the default option, just like in the vue example, there are components, name, data, methods... it seems a little clear.
const Mask = Vue.extend(Loading)

const loadingDirective = {}
// Remember how to use Vue.use()? If the object is passed in, the object needs an install attribute
loadingDirective.install = Vue => {
  // The toggle Loading method looks at the name by toggling the display and hiding of loading.~
  const toggleLoading = (el, binding) => {
    // If the binding value is true, insert the loading element
    // Binding value is an object, including instruction name, instruction binding value, modifiers modifier object, etc. Specifically, you can understand the content of custom instructions.
    if (binding.value) {  //binding.value is the bound instruction value
      if (binding.modifiers.fullscreen) {  Do you remember the instructions we inserted? : v-loading.fullscreen="true" ,  .fullscreen It's the modifier.
        insertDom(document.body, el, binding)    //insertDom knows by name that it is inserting new elements
      }
     // visible is the value defined in load. Vue data
    } else {
      el.instance.visible = false
    }
  }

  const insertDom = (parent, el, binding) => {
    // loading is set to visible
    el.instance.visible = true
    // If appendChild adds the same element, it will not be repeated
    parent.appendChild(el.mask)
  }
  // Register directive instructions here
  Vue.directive('loading', {
    bind: function(el, binding, vnode) {
      // Create a subcomponent, similar to new Vue(options)
      // Returns a component instance
      const mask = new Mask({
        el: document.createElement('div'),
        // Some people will be confused when they see this. Why does this data not follow the official Vue recommendation to pass in a function?
        // In fact, there are both.
        // A little bit of extension. In the Vue source code, data is delayed.
        // Stick a little Vue source code up
        // return function mergedInstanceDataFn() {
        //   let instanceData = typeof childVal === 'function'
        //     ? childVal.call(vm, vm)
        //     : childVal;
        //   let defaultData = typeof parentVal === 'function'
        //     ? parentVal.call(vm, vm)
        //     : parentVal;
        //   if (instanceData) {
        //     return mergeData(instanceData, defaultData)
        //   } else {
        //     return defaultData
        //   }
        // }
        // Instance Data is the data we are passing in now: {}
        // defaultData is the data() {} in our load. Vue
        // After reading this code, it should be easy to understand why objects can be passed in.
        data: {
          fullscreen: !!binding.modifiers.fullscreen
        }
      })
      // Mount the created subclass on el
      // Recommendations in directive documentation
      // It should be guaranteed that all parameters (binding, vnode) except el are read-only.
      el.instance = mask
      // Mount dom
      // Bid calls only once, assigning el.mask to bind, so el.mask refers to the same dom element.
      el.mask = mask.$el
      // Run toogle Loading if the binding value is true
      binding.value && toggleLoading(el, binding)
    },
    update: function(el, binding) {
      // If the old is not worth the new (usually when true is switched to false)
      if (binding.oldValue !== binding.value) {
        // Switch Display or Disappearance
        toggleLoading(el, binding)
      }
    },
    unbind: function(el, binding) {
      // Execute component destruction when component unbind
      el.instance && el.instance.$destroy()
    }
  })
}
export default loadingDirective

For more information on extend (), please refer to Here Very familiar and easy to understand!

Principle of loading Service Mode Call

Look directly at the source code:

import Vue from 'vue'
import loadingVue from './loading.vue'
// Like instruction mode, create instance constructors
const LoadingConstructor = Vue.extend(loadingVue)
// Define variables. If full-screen loading is used, ensure that there is only one global loading
let fullscreenLoading
// Here you can see something different from instruction mode.
// After close is invoked, the element is removed and the component is destroyed
LoadingConstructor.prototype.close = function() {
  setTimeout(() => {
    if (this.$el && this.$el.parentNode) {
      this.$el.parentNode.removeChild(this.$el)
    }
    this.$destroy()
  }, 3000)
}

const Loading = (options = {}) => {
  // If fullscreen is passed in when loading is called and fullscreenLoading is not falsy
  // Fulscreen Loading only assigns values below and points to the loading instance
  if (options.fullscreen && fullscreenLoading) {
    return fullscreenLoading
  }
  // There's no need to talk about it here. It's the same as in the instructions.
  let instance = new LoadingConstructor({
    el: document.createElement('div'),
    data: options
  })
  let parent = document.body
  // Direct addition of elements
  parent.appendChild(instance.$el)
  // Set it as visible
  // In addition, when I wrote here, I consulted the relevant information.
  // I've always understood that nextTick is a callback after the dom element has been updated
  // But that may not be the case. I will continue to study it later.
  // If there's enough dry goods, I'll write an article about next Tick ui-render microtask macrotask
  Vue.nextTick(() => {
    instance.visible = true
  })
  // If the fullscreen parameter is passed in, the instance is stored
  if (options.fullscreen) {
    fullscreenLoading = instance
  }
  // Return an instance to call the close() method on the prototype for convenience
  return instance
}
export default Loading

Now Learn to Use - Write a Click-on Picture Preview Component for a Trial

Directory structure:

directive.js is the instruction mode file, index.js is the service mode file, star-pic-preview.vue is the basic single file, including the basic html structure.

Look at the instruction mode first:

  • Use:

I used the instructions directly without passing parameters, because the function is simple and the default parameter is false.

 <img
    src="http://img5.imgtn.bdimg.com/it/u=3300305952,1328708913&fm=26&gp=0.jpg"
    v-pic-preview
 >
  • Effect:

Click to appear the mask layer and center the picture to display the preview.

Service model:

  • Use:
<img
    src="http://img4q.duitang.com/uploads/item/201502/22/20150222191447_jdBYa.thumb.700_0.jpeg"
    @click="openImagePreview2"
>
 methods: {
    // service mode
    openImagePreview2(e) {
        // If you only send pictures
        this.$picPreview(e.target.src);
        //If you pass complex objects, you can configure the background color of the mask layer, etc.
        // this.$picPreview({
        //     background: 'rgba(0, 0, 0, 0.7)',
        //     imageUrl: e.target.src,
        // });
    },
}
  • The effect is as good as above.

Refer to github address for source code: Source address

Topics: Javascript Vue Attribute github