blog
blog copied to clipboard
Message消息提示实现原理
使用Vue的小伙伴可能使用过element-ui中的Message 消息提示 使用React的小伙伴可能使用过ant-designMessage全局提示
Message.success({message: '消息提示'})
他们的原理都相似,这篇文章将会带你手写实现消息提示组件。
Vue
对于这样的消息组件,是用函数执行的进行调用,并不是在模板中直接使用组件的形式,不是组件那他们的DOM是如何创建到页面中显示出来的呢?其实还是利用了组件的虚拟DOM渲染的。
先准备好消息提示组件
<template>
<div>
<ul>
<li v-for="(item, index) in messages" :key="index" class="message">
{{ item.message }}
</li>
</ul>
</div>
</template>
<script>
export default {
data () {
return {
messages: [],
id: 0
}
},
methods: {
add (options) {
let layer = {
id: this.id++,
...options
}
layer.timer = setTimeout(() => {
this.remove(layer)
}, 2000);
this.messages.push(layer)
},
remove (layer) {
this.messages = this.messages.filter(item => item.id !== layer.id)
}
}
}
</script>
<style>
.message {
position: fixed;
left: 50%;
top: 30px;
transform: translate3d(-50%, 0, 0);
background: #000;
background: #f0f9eb;
color: #67c23a;
padding: 10px 20px;
border-radius: 4px;
animation: move 0.3s;
}
@keyframes move {
0% {
top: 0;
opacity: 0;
}
100% {
top: 30px;
opacity: 1;
}
}
ul,li {
list-style: none;
}
</style>
然后调用方法再渲染DOM到页面
import Vue from 'vue'
import MessageComponent from './MessageComponent.vue'
class Msg {
constructor () {
let vm = new Vue({
render: h => h(MessageComponent)
}).$mount()
document.body.appendChild(vm.$el)
this.component = vm.$children[0]
}
success (options) {
this.component.add(options)
}
}
Msg.getInstance = (function () {
let instance;
return function () {
if (!instance) {
instance = new Msg()
}
return instance
}
})()
export const Message = Msg.getInstance()
React
先实现这个组件的DOM结构和基本的交换效果。MessageComponent.js
文件
import React, { Component } from 'react';
import './Message.css'
class MessageComponent extends Component {
constructor(props) {
super(props)
this.state = {
id: 0,
messages: [],
max: 5
}
}
add = (options) => {
let { id, messages } = this.state
let layer = {
id: id++,
...options
}
layer.timer = setTimeout(() => {
this.remove(layer)
}, 2000);
messages.push(layer)
this.setState({ id, messages })
}
remove = (layer) => {
clearTimeout(layer.timer)
let messages = this.state.messages.filter(item => item.id !== layer.id)
this.setState({ messages })
}
render() {
return (
<ul>
{this.state.messages.map(
(item, index) => <li key={item.id} className="message">{item.message}</li>
)}
</ul>
);
}
}
export default MessageComponent;
再加上一些样式。Message.css
文件
.message {
position: fixed;
left: 50%;
top: 30px;
transform: translate3d(-50%, 0, 0);
background: #000;
background: #f0f9eb;
color: #67c23a;
padding: 10px 20px;
border-radius: 4px;
animation: move 0.3s;
}
@keyframes move {
0% {
top: 0;
opacity: 0;
}
100% {
top: 30px;
opacity: 1;
}
}
ul,li {
list-style: none;
}
现在组件和样式都准备好了,我们需要考虑组件如何渲染到页面中。通过用法我们知道Message是当做函数来直接使用的。说明函数执行的过程中会把消息组件渲染到页面中。
Message.success({ message: Math.random() }) }
原理
import React from 'react';
import ReactDOM from 'react-dom';
import MessageComponent from './MessageComponent'
class Msg {
constructor () {
let myRef = {current: ''}
const div = document.createElement('div')
document.body.append(div)
ReactDOM.render(<MessageComponent ref={myRef} />, div)
this.refs = myRef
}
success (options) {
this.refs.current.add(options)
}
}
Msg.getInstance = (function () {
let instance;
return function () {
if (!instance) {
instance = new Msg()
}
return instance
}
})()
export const Message = Msg.getInstance()