Bs part

The article was written by CSDN before. I’m going to rewrite it. I’m going to take heat. Because the previous batch migration of this document is not hot, typesetting problems. There is also the mass migration of blogs, resulting in some good articles.

I think the rich text development section of my homepage is quite deep, but there are few people writing about it, so I won’t promote it much.

And just to recap, it’s been a long time. It is difficult for me to make any progress in the simple business process of company projects. Now I rely on myself to write other things to improve myself.

1. Understand vUE instruction development

This part I will not say, you go to see the vUE official website, or more detailed, mainly to see this picture

Let us understand the instruction in the development process need to pay attention to the occurrence of function behavior.



2. HTML code and parameters

There’s not much to say about this, just write a fixed mask. In fact, there are many parameters of the meaning of things mainly lies in beautification and customization

<template>
  <div
    :class="fullscreen ? 'dhtMask-FullScreen' : 'dhtMask'"
    :style="{
      zIndex: this.$dhtUI.zIndex,
      background: 'rgba(' + background + ')',
      fontSize: fontSize + 'px',
      color: color
    }"
  >
    <img
      class="dht-loading-icon"
      :src="iconSrc"
      alt="loading"
      :style="{ width: iconWidth + 'px', height: iconHeight + 'px' }"
    />
    <span>{{ text }}</span>
  </div>
</template>

<script>
export default {
  name: "dhtMask".data() {
    return {
      fullscreen: false,
      background: "0, 0, 0, 0.5",
      text: "Loading...",
      iconSrc: null,
      iconWidth: null,
      iconHeight: null,
      color: null,
      fontSize: null
    };
  },
  beforeCreate() {},
  created() {},
  beforeMount() {},
  mounted() {
    if (this.fullscreen) {
      document.body.style.overflow = "hidden"; }},beforeUpdate() {},
  updated() {},
  activated() {},
  deactivated() {},
  beforeDestroy() {},
  destroyed() {
    document.body.style.overflowX = "hidden";
  },
  errorCaptured() {},
  methods: {}
};
</script>

<style lang="scss"> .dhtMask { position: absolute; z-index: 2000; Background: Rgba (0, 0, 0, 0.5); width: 100%; height: 100%; color:#ffffff;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 12px;
  flex-flow: column;
}
.dhtMask-FullScreen {
  @extend .dhtMask;
  width: 100vw;
  height: 100vh;
  top: 0;
  background: (0, 0, 0, 0.5);
}
.dht-loading-icon {
  width: 25px;
  height: 25px;
  object-fit: cover;
  margin-bottom: 5px;
  animation: dht-rotate 2s linear infinite;
  @keyframes dht-rotate {
    0% {
      transform: rotate(0deg);
    }
    100% {
      transform: rotate(360deg);
    }
  }
}
</style>
Copy the code

2, the specified function writing (emphasis)

1. The header imports the file

Here’s a vue.extend, which is key because you need it to process your Vue files before instantiating your HTML code. There’s not much to say about this standard format.

import vue from "vue";
import maskLoading from "./mask.vue";

const Mask = vue.extend(maskLoading);Copy the code

2, first write your specified basic format, this is the basic format

// Const directive = () => {vue.directive()"dhtLoading", {// called only once, when the directive is first bound to the element. This is where you can perform one-time initialization Settings.bind(el, binding) {}, // When the bound element is inserted into the DOM... // called when the bound element is inserted into the parent (the parent is guaranteed to exist, but not necessarily inserted into the document). inserted:function(el, binding, vnode, oldVnode) {
      //console.log("When the element is inserted"); }, // call update(el, binding) {} when the VNode of the component is updated, // call when the VNode of the component and its child VNodes are updatedcomponentUpdated() {
      //console.log("Render is done."); }, // only once, unbind(el) {}}); };export default directive;Copy the code

3. Bind function

This is the beginning of the specified function, where all initialization is done. I cut out the cosmetic code and left the core

const mask = new Mask({
  el: document.createElement("div"), data: { } }); el.instance = mask; // save mask to el.mask = mask.$el; // toggleLoading(el, binding);Copy the code

In this case, the vUE file is instantiated and initialized. That is, the virtual DOM is formed without the page being inserted.

Because I’m writing it from elementUI source code. Just to illustrate the key points. So you don’t get confused

el.instance = mask; // Store the maskCopy the code

This section is to instantiate the vue file temporary save, later need additional use

el.mask = mask.$el; //dom storage, easy accessCopy the code

So let’s do the DOM here

toggleLoading(el, binding);Copy the code

El and binding are directives that pass in the currently bound DOM element and directive parameters when binding the page. Not in the same way as elementUI, which uses HTML custom elements.

The core is this function. Is the key

4. Remove and insert elements from the pagetoggleLoading

// Mask operation updates const toggleLoading =function(el, binding) {
  //console.log(binding);
  if (binding.value) {
    vue.nextTick(() => {
      if(binding. Modifiers. Fullscreen) {/ / full screen case. / / el instance. The fullscreen =true;
        //document.body.style.overflow = "hidden";
        document.body.appendChild(el.mask);
      } else {
        //el.instance.fullscreen = false; // In full screen modeletheight = el.clientHeight; // Current element heightletwidth = el.clientWidth; // The current element widthletoffsetTop = el.offsetTop; // The current distance from the top of the element // Assign the mask value el.mask.style.top = offsetTop +"px";
        el.mask.style.height = height + "px";
        el.mask.style.width = width + "px"; //console.log(offsetTop); el.appendChild(el.mask); }}); }else{/ / remove node el. Mask && el. Mask. ParentNode && el. Mask. ParentNode. RemoveChild (el) mask); el.instance && el.instance.$destroy(a); }Copy the code

Key point analysis: Vue.nexttick

Note that if not added, the page will be directly inserted into the wrong position. Because you need to wait for the page to finish rendering. I’m not doing too well here, because elementUI doesn’t refresh the page and cause element positioning errors. But I don’t study it much, and I know the general reason. The main thing is to know the core principles.

This code is actually very simple, one is to update the width and height of the element, can overwrite the current element. All that is left is to insert the element directly into the page.

Handles repeated calls, supports deletion and insertion.

5. Be aware that instructions have changed

Update (el, binding) {//console.log("Updated", binding);
  if (binding.oldValue !== binding.value) {
    toggleLoading(el, binding);
  }
},Copy the code

It’s simple to check if the data is consistent, and to call the function again to remove the element. This is to prevent the same place from being inserted twice.

6. Unbinding instruction.

// Call unbind(el) {//console.log("Unbound."); / / don't know how instruction unbundling, first write el. Mask && el. Mask. ParentNode && el. Mask. ParentNode. RemoveChild (el) mask); el.instance && el.instance.$destroy(a); }Copy the code

It’s not very clear here. Because you don’t know when the untying instruction is.

7. Js file of the entire instruction

Let’s start with registration. This is easy.

That is, importing js files like yours

import directive from "./mask/directive";Copy the code
vue.use(directive);Copy the code

The entire JS file section

import vue from "vue";
import maskLoading from "./mask.vue"; const Mask = vue.extend(maskLoading); // Main function const directive = () => {// Mask updates const toggleLoading =function(el, binding) {
    //console.log(binding);
    if (binding.value) {
      vue.nextTick(() => {
        if(binding. Modifiers. Fullscreen) {/ / full screen case. / / el instance. The fullscreen =true;
          //document.body.style.overflow = "hidden";
          document.body.appendChild(el.mask);
        } else {
          //el.instance.fullscreen = false; // In full screen modeletheight = el.clientHeight; // Current element heightletwidth = el.clientWidth; // The current element widthletoffsetTop = el.offsetTop; // The current distance from the top of the element // Assign the mask value el.mask.style.top = offsetTop +"px";
          el.mask.style.height = height + "px";
          el.mask.style.width = width + "px"; //console.log(offsetTop); el.appendChild(el.mask); }}); }else{/ / remove node el. Mask && el. Mask. ParentNode && el. Mask. ParentNode. RemoveChild (el) mask); el.instance && el.instance.$destroy();
    }
  };
  //let timer = "";
  vue.directive("dhtLoading", {// called only once, when the directive is first bound to the element. This is where you can perform one-time initialization Settings.bind(el, binding) {
      //console.log(el, binding, vnode);
      let background = binding.value.background,
        text = binding.value.text,
        iconSrc = binding.value.iconSrc,
        iconWidth = binding.value.iconWidth,
        iconHeight = binding.value.iconHeight,
        color = binding.value.color,
        fontSize = binding.value.fontSize;
      const mask = new Mask({
        el: document.createElement("div"), data: { fullscreen: !! binding.modifiers.fullscreen, background: background ? background :"0, 0, 0, 0.5",
          text: text ? text : "Loading...",
          iconSrc: iconSrc ? iconSrc : require(".. /.. /style/img/loading.png"), iconWidth: iconWidth ? iconWidth : null, iconHeight: iconHeight ? iconHeight : null, color: color ? color : null, fontSize: fontSize ? fontSize : null } }); el.instance = mask; // save mask to el.mask = mask.$el; // toggleLoading(el, binding); }, // When the bound element is inserted into the DOM... // called when the bound element is inserted into the parent (the parent is guaranteed to exist, but not necessarily inserted into the document). // eslint-disable-next-line no-unused-vars inserted:function(el, binding, vnode, oldVnode) {
      //console.log("When the element is inserted"); }, // Call update(el, binding) {//console.log("Updated", binding);
      if(binding.oldValue ! == binding.value) { toggleLoading(el, binding); }}, // call after the component's VNode and its child VNodes are all updatedcomponentUpdated() {
      //console.log("Render is done."); }, // only once, unbind(el) {//console.log("Unbound."); / / don't know how instruction unbundling, first write el. Mask && el. Mask. ParentNode && el. Mask. ParentNode. RemoveChild (el) mask); el.instance && el.instance.$destroy();
    }
  });
};

export default directive;
Copy the code

8, documentation,

Command mode (mask) fullscreen Boolean v-dht-loading.fullscreen In non-full-screen mode, dom rendering is not complete, resulting in top alignment of elements
background String 0, 0, 0, 0.5
text String Loading in…
iconSrc String Default loading diagram Modify the loading prompt picture
iconWidth String Image width
iconHeight String Picture height
color String The font color
fontSize String The font size

3. Overall thinking and acknowledgements

Ideas:

Specifying patterns is not so special, but rather a more elegant way to use components.

The whole thing is to bind to the current element, then get the width and height of the current element, set the mask to the same width and height, and position the current element, and finally insert. If necessary, detect data changes and remove elements. It’s not amazing in and of itself, but before you write it, you’re really like, this is awesome.

Let me introduce git to you. If you see the execl file, you can go directly to it.

https://github.com/ht-sauce/dream



Thanks again to the elementUI open source component