Message in the development of a high frequency of use, is also a relatively simple Element-UI component library, for interested friends can discuss the implementation of Message components

What is the component function

Often used for feedback after active action, such as a successful or failed form submission

Component Usage

this.$message('This is a message prompt');

this.$message({
 message: 'Congratulations, this is a success.'.  type: 'success'
}); Copy the code

Component design Ideas

$Message is called through this.$Message, and different options are passed to control the style and content of the component. The HTML displayed is inserted into the Document dynamically and removed after duration, and the display of the component is accessed and controlled by the Vue instance.

The overall structure of the component is divided into the display part and the control part

  • The presentation part is separated from a component, and the presentation logic and interactive encapsulation of the component are processed in a centralized manner
  • The control part is to undertakevueExamples and component presentations

Overall execution process

Vue project

// 1. Import the component library
import ElementUI from 'element-ui';

// 2. Use the component library
Vue.use(ElementUI); 
Copy the code

Every time that vue.use is invoked, the install method of the Element-UI is triggered inside the Element-UI. Then the Element is registered as a global component and the method is placed on vue.prototype

// 1. Introduce the Message object
import Message from '.. /packages/message/index.js';

// 2. Define the install function,
const install = function(Vue, opts = {}) {
 // Register the component traversal as a global component, such as the Button component  components.forEach(component= > {  Vue.component(component.name, component);  });  // Put the method on the Vue prototype  Vue.prototype.$message = Message; }; Copy the code

After the above two steps, the edge can be directly in the project through this.$message component display control, next to explore the Element UI internal processing

Show some

First, take a look at the component content of the display part after the deleted version. The code will delete part of the logic display, tightly show the basic functions, display icon and other functions can be viewed by themselves, relatively simple

<template>
  <transition name="el-message-fade" @after-leave="handleAfterLeave">
    <div
      class="el-message"
      :style="positionStyle"
      v-show="visible">
      <slot>
        <p>{{ message }}</p>
      </slot>
    </div>
  </transition>
</template>

<script type="text/javascript"> export default { data() { return { visible: false, message: '', duration: 3000, onClose: null, closed: false, verticalOffset: 20, timer: null }; },

Computed: {positionStyle() {// control the display location of the current component return {'top': ${this.verticaloffset}px}; }},

Watch: {// watch closed(newVal) {if (newVal) {this.visible = false; }}},

Methods: {// The hook of the transtion component executes handleAfterLeave() {this.el.parentNode.removeChild(this.$el); // Remove the DOM from the component},

close() { this.closed = true; If (typeof this.onclose === 'function') {this.onclose (this); }}, // close the startTimer() {if (this.duration &gt; 0) { this.timer = setTimeout(() =&gt; { if (! this.closed) { this.close(); } }, this.duration); }}Copy the code

}, mounted() { this.startTimer(); }}; </script>

Copy the code

<style>
.el-message{
min-width: 280px;
height: 42px;
box-sizing: border-box;
border-radius: 4px;
border: 1px solid #ebeef5;
position: fixed;
left: 50%;
top: 20px;
transform: translateX(-50%);
background-color: #edf2fc;
transition: opacity .3s,transform .4s,top .4s;
overflow: hidden;
padding: 15px 15px 15px 20px;
display: flex;
align-items: center;
background-color: #f0f9eb;
border-color: #e1f3d8;
}
</style>

Template section

The transition component (visible) is used to control the display and destruction of components. The transition component (visible) is used to control the display and destruction of components. The transition component (visible) is used to control the display and destruction of components. The positionStyle attribute is used to set the display location of the component, and the message attribute is used to display the content data of the component

The script section can be understood by referring to the comments, which need to be noted in two places

The first thing you need to notice is what you do when you mount the lifecycle hook. Why? Because there is no EL option, the instance does not immediately enter the compilation phase, and the display call $mount is required to manually start compilation

It is also important to note that the close function does two things. Setting the value closed triggers the corresponding watch, and calls the onClose method if it exists. Note that the onClose function is defined in the control section, as explained later

The control part

So far, it is clear that Vue triggers the display of components through this.$message, and the component content in the display part has been completed. Now, it is necessary to link the two through the control part to achieve the desired function

Associating with Vue is simple. You just define a method and export it

const Message = options= > {
  // Write the logic....
}

export default Message;
Copy the code

Introduce it and tie it to the Vue prototype, omitting extraneous code

// Introduce the Message object
import Message from '.. /packages/message/index.js';

// Put the method on the Vue prototype
Vue.prototype.$message = Message;
Copy the code

This is called with this.$message, and the next step is to associate the message function with the component and control the presentation

The Message core needs to do that

  • Compile the component, use rendering, and insert into the Body

  • Controls the visible variable within the component, triggering the display of the component

  • Controls the verticalOffset variable in a component that determines where the component should be displayed

Manually start component compilation, get sample access to internal data and render to the page

// 1. Create a "subclass" using the base Vue constructor
let MessageConstructor = Vue.extend(Main);
// 2. Component instance, visible and verticalOffset can be accessed through instance
instance = new MessageConstructor({
  data: options
}); Copy the code

The rest of the Message method is fault tolerant and robust. The clean version of the code is as follows

let MessageConstructor = Vue.extend(Main);

let instance; // The current component
let instances = []; // Collect all components for location determination, destruction, etc
let seed = 1;
 const Message = options= > {  // Robust processing  if (Vue.prototype.$isServer) return;  options = options || {  message: 'content' + Date.now(),  onClose(message){  console.log('Closed callback, taking the closed message instance',message);  }  };   if (typeof options === 'string') {  options = {  message: options  };  }   // The closed callback takes the closed message instance  let userOnClose = options.onClose;  let id = 'message_' + seed++;   // Add an onClose method that is called inside the component when it is destroyed  options.onClose = function() {  Message.close(id, userOnClose);  };   // Component instance  instance = new MessageConstructor({  data: options  });  instance.id = id; / / set ID   instance.$mount(); // Since the EL option does not exist, the instance will not be compiled immediately  document.body.appendChild(instance.$el); // Insert the Message component into the body   // Set the distance from the top of the component  let verticalOffset = options.offset || 20;  instances.forEach(item= > {  verticalOffset += item.$el.offsetHeight + 16;  });  instance.verticalOffset = verticalOffset;   instance.visible = true; // Control display  instance.$el.style.zIndex = 99; // Control hierarchy  instances.push(instance);  return instance; }; Copy the code

The Message component supports this.$message.error(‘ wrong, this is an error Message ‘); Call to use, so far is not supported, the code is relatively simple directly on the code

// We define a method for each type, such as message.success (options), which can be called directly
['success'.'warning'.'info'.'error'].forEach(type= > {
  Message[type] = options= > {
    if (typeof options === 'string') {
      options = {
 message: options  };  }  options.type = type;  return Message(options);  }; }); Copy the code

The display component internally calls this.onclose (this), sets this.visible=false to close the popup and remove its corresponding DOM structure, but when multiple components are displayed on the page, you need to change the position of the remaining components

The onClose function is defined in the Message function

// The closed callback takes the closed message instance
let userOnClose = options.onClose;

// Add an onClose method that is called inside the component when it is destroyed
options.onClose = function() { 
 Message.close(id, userOnClose); }; Copy the code

The onClose function ultimately calls the static method close on Message

The function message.close does a few things inside

  • Locate the component you want to close in the array of components displayed on the page and remove it
  • Recalculate the locations of the remaining components
Message.close = function(id, userOnClose) {
  let len = instances.length;
  let index = - 1;

  for (let i = 0; i < len; i++) {
 // If a match is found, the for loop is introduced  if (id === instances[i].id) {  index = i;  // The onClose callback passed when the component was initialized takes the message instance that was closed  if (typeof userOnClose === 'function') {  userOnClose(instances[i]);  }  instances.splice(i, 1);  break;  }  }   console.log(Each close `${len} -- ${index}`);  // There is no need to continue processing the display location of the existing components on the page when only one component exists or when there is no match for the component to be destroyed  if (len <= 1 || index === - 1 || index > instances.length - 1) return;   // Each time a valid component is destroyed, and there is more than one component on the page, it is necessary to adjust the position of the component displayed on the page  const removedHeight = instances[index].$el.offsetHeight;  for (let i = index; i < len - 1 ; i++) {  let dom = instances[i].$el;  dom.style['top'] =  parseInt(dom.style['top'].10) - removedHeight - 16 + 'px';  } }; Copy the code

So far, the basic version of Message has been completed, and the component code is less than 200 lines. Through the simple reading and analysis of the source code, the knowledge is not a lot, but the idea of excellent component encapsulation is still worth learning and reference