The research idea of this paper is to read Element source code, and then automatically write components step by step to improve their corresponding functions.

The preparatory work

To prepare, write a test page MessageShownPage

<template> <div> contents <el-message /> </div> </template> <script> import ElMessage from '.. /.. /components/Message/message.vue' export default { name: 'MessageShownPage', components: { ElMessage } } </script> <style> </style>Copy the code

Basic implementation

The next component does the simplest implementation of message:

<template> <transition name="el-message-fade"> <div :class="[ 'el-message', type ? `el-message--${ type }` : "', ]" :style="positionStyle" v-show="visible" > <i :class="typeClass"></i> <slot> <p class="el-message__content">{{ message  }}</p> </slot> </div> </transition> </template> <script> const typeMap = { success: 'success', info: 'info', warning: 'warning', error: 'error' }; Export default {data() {return {visible: true, message: 'This is a message ', type: 'info', verticalOffset: 20,}; }, computed: { typeClass() { return this.type ? `el-message__icon el-icon-${ typeMap[this.type] }` : ''; }, positionStyle() { return { 'top': `${ this.verticalOffset }px` }; } } } </script>Copy the code

The effect is as follows:

A static message on the page.

Take a look at the style:

.el-message {
    min-width: 380px;
    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;
}
Copy the code

You can see that message is passed position: fixed; Navigate to the page.

Realize the effect of automatic disappearance after 3 seconds

Our component is wrapped under the Transition name=”el-message-fade” tag. The following div’s V-show =”visible” control component triggers the transition animation when it shows hidden. So let’s define a timer and set visible = false after 3 seconds.

methods: {
    close() {
        this.closed = true;
        this.visible = false
    },
    startTimer() {
        // duration是3000
        if (this.duration > 0) {
            this.timer = setTimeout(() => {
                if (!this.closed) {
                    this.close();
                }
            }, this.duration);
        }
    },
},
mounted() {
  this.startTimer();
},
Copy the code

In this way, our component will automatically disappear after 3 seconds.

Call Message by instruction

Now mount the message object on Vue:

import messageService from './components/Message/service.js'
Vue.prototype.$message = messageService;
Copy the code

So we can use this.$message() in the component. Next, implement service.js

import Vue from 'vue'; import Main from './message.vue'; let MessageConstructor = Vue.extend(Main); let instance; Const Message = function (options) {/ / call this $Message passed parameters when the options = options | | {}; // If the argument is a string, assign the value directly to message if (typeof options === 'string') {options = {message: options}; } // Create a message instance instance = new MessageConstructor({data: options}); instance.$mount(); / / add the dom to the web page document. The body. The appendChild (instance. $el); instance.visible = true; return instance; } export default Message;Copy the code

We wrote in the test page:

Mounted () {setTimeout(() => {this.$message(' this? Is this it? ')}, 1000); },Copy the code

One second later, message appears, and three seconds later, message disappears. Call message by instruction.

Different message states

Message can be ‘SUCCESS ‘, ‘warning’, ‘info’, or’ error’.

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

With the above code, we can call up a success message. There is another way to call it.

This.$message.error(' error, this is an error message ');Copy the code

To invoke an error message, simply click on the error method. Let’s back it up. Add code to service.js:

const status = ['success', 'warning', 'info', 'error']
status.forEach(type => {
    Message[type] = options => {
        if (typeof options === 'string') {
            options = {
                message: options
            };
        }
        options.type = type;
        return Message(options);
    };
});
Copy the code

This adds four more methods to our $message. The display is identical to passing the Options object directly.

The effect is as follows:

Can be closed

Call method:

This.$message({showClose: true, message: 'this is a message'});Copy the code

We add code to the component:

 <i v-if="showClose" class="el-message__closeBtn el-icon-close" @click="close"></i>
Copy the code

The effect is as follows:

The close method was implemented earlier.

Writing in the middle

Call method:

This.$message({message: 'center ', center: true});Copy the code

This is achieved through the Center control style. Add center? To the component div style. ‘is – center’ : ‘ ‘.

The effect is as follows:

Using HTML fragments

Call method:

Enclosing $message ({dangerouslyUseHTMLString: true, the message: '< strong > this is < / I > < I > HTML fragment < / strong >'});Copy the code

Add code to the component:

<slot> <p v-if="! dangerouslyUseHTMLString" class="el-message__content">{{ message }}</p> <p v-else v-html="message" class="el-message__content"></p> </slot>Copy the code

V-html can support HTML fragments display.

The effect is as follows:

VNode support

Call method:

const h = this.$createElement; Enclosing $message ({message: h (" p ", null, [h (" span ", null, 'content can be), h (' I', {style: 'color: teal'}, 'VNode)])});Copy the code

Add to the Message function in service.js

// If it's a vnode, just assign it to instance.$slot.default. if (isVNode(instance.message)) { instance.$slots.default = [instance.message]; instance.message = null; }Copy the code

Now look at the isVNode method:

// Node is an object and has a componentOptions property, so we consider it a VNode. function isVNode(node) { return node ! == null && typeof node === 'object' && hasOwn(node, 'componentOptions'); }Copy the code

I think by analyzing the vUE source code, it should be seen that the VNode object has componentOptions properties, which are not detailed here.

The effect is as follows:

Multiple messages can be displayed

Let’s support continuous message occurrences. Js: in the service.

let instances = []; const Message = function(options) { ... / / add mesagge to dom / / when a new message, after its verticalOffset is all previous message high added 16 let verticalOffset = options. Offset | | 20; instances.forEach(item => { verticalOffset += item.$el.offsetHeight + 16; }); instance.verticalOffset = verticalOffset; instance.visible = true; instances.push(instance); return instance; }Copy the code

The effect is as follows:

conclusion

In this article we look at one of the more interesting components, Message.

Code in the code cloud: gitee.com/DaBuChen/my…

Other component source code study:

Element component source research -Button

Element component source research -Input Input box

Element component source research -Layout, Link, Radio

Element component source research -Checkbox multi-checkbox

Element component source research -InputNumber counter

Element component source code study -Loading component

Element component source research -Message component