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