Message消息提示是这样的页面提示
如果你在使用Vue那可能会使用element-ui中消息提示,如果你在使用React,那么可能会使用ant-design的消息提示。他们的原理都相似,这篇文章将会带你手写实现消息提示组件。这两个UI框架在消息提示组件上的用法大致相同,用例如下:
Message.success({message: '恭喜你,这是第一条成功消息'})
消息提示组件并不是直接在模板中使用,而是当做普通的方法进行调用,方法调用的时候会把组件渲染到页面中,那么它渲染的HTML是如何创建的呢?其实渲染的DOM还是一个组件,只不过是通过Message方法进行了一层包装,通过方法让外界调用更简单。
Vue
先准备好消息提示组件,消息提示是一个列表,可以添加多个消息内容,每次消息只有几秒的显示时间将会消失,那么代码如下结构:
<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;
}
}
</style>
通过方法进一步包装组件,可以调用某个方法让消息提示显示出来。关键是组件已经准备好了,要考虑如何挂在到页面中,有几个API大家很少用到的。注意下面代码:
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
其实一开始只准备Vue的消息提示,但是考虑到React也有很多人可能用到,所有添加了这部分内容。
原理也十分类似,先准备好组件DOM结构和基本的交互操作
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 {
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;
}
}
关键是DOM挂载的方式不一样
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()
现在你已经学会消息提示组件的原理,可以看出这样的做法是让使用组件的人更加简便,但是多添加了一层封装组件的代码逻辑。