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 undertake
vue
Examples 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 > 0) { this.timer = setTimeout(() => { 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