使用方法:html
import $ from '@/component/Toast/index';
...
$.toast({
type:0,
content: "我是默認Toast",
time: 1000,
opacity: .5,
onSucc() {
console.log("我是Toast的回調!")
}
});
$.toast("我是默認Toast");
$.toast({
type:3,
content: "我是默認loading",
time: 1000,
});
setTimeout(() => { //3s後隱藏
$.hide();
}, 3000);
$.dialog({
type: 0,
opacity:0.5,
title: "我是title",
content: "我是content",
btnSucc: "我是成功",
btnFail: "我是取消",
onSucc(e) {
e.stopPropagation();
$.toast("我是默認Toast");
},
onFail(e) {
e.stopPropagation();
console.log("我是失敗的回調!");
}
});
複製代碼
在Vue裏,通常將toast,alert等非業務相關的寫成插件,掛載在Vue的原型鏈上,使用的時候直接this.$toast便可,很是方便!相關原理在這裏就不說了,感興趣的能夠查閱官網. 先看看Vue的插件寫法:vue
@/components/vue-toast/index.jsreact
import ToastComponent from "./vue-toast.vue"; // 引入先前寫好的vue
var Toast = {};
//避免重複install,設立flag
Toast.installed = false;
Toast.install = function(Vue, options = {
type: "success", //success fail warning loading toast
msg: "操做成功",
time: 1000,
callback() {
}
}) {
if(Toast.installed) return;
var obj;
Vue.prototype.$toast = (config = {}, type) => {
if(type == 'close') {
obj && obj.removeToast();
return false;
}
if(typeof config=="object"){
config = {
...options,
...config
}
}else{
config = {
...options,
...{
type: "toast",
msg: config
}
}
}
// 若是頁面有toast則不繼續執行
if(document.querySelector('.vue-toast')) return;
// 一、建立構造器,定義好提示信息的模板
const toastTip = Vue.extend(ToastComponent);
obj = new toastTip();
for(var property in config) {
obj[property] = config[property];
}
//刪除彈框
obj.removeToast = function() {
document.body.removeChild(tpl);
}
//插入頁面
let tpl = obj.$mount().$el;
document.body.appendChild(tpl);
Toast.installed = true;
if(['success', 'fail', 'warning','toast'].indexOf(config.type) > -1) {
setTimeout(() => {
obj.removeToast();
obj.callback();
}, config.time)
}
['close'].forEach(function(type) {
Vue.prototype.$toast[type] = function(msg) {
return Vue.prototype.$toast({}, type)
}
});
};
};
// 自動安裝 ,有了ES6就不要寫AMD,CMD了
if(typeof window !== 'undefined' && window.Vue) {
window.Vue.use(Toast)
};
export default Toast
複製代碼
@/components/vue-toast/vue-toast.vuegit
<template>
<div class="mask vue-toast">
<div>
<div class="toast" v-if="['success', 'fail', 'warning','loading'].indexOf(type) > -1">
<div class="icon" v-if="['success', 'fail', 'warning'].indexOf(type) > -1">
<div v-if="type=='success'" class="success-icon"></div>
<div v-if="type=='fail'" class="fail-icon"></div>
<div v-if="type=='warning'" class="warning-icon"></div>
</div>
<div class="loading-icon" v-else>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
<div class="msg" v-html="msg"></div>
</div>
<div v-else class="toast-msg" v-html="msg"></div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
msg: " ",
type: "success"
};
}
};
</script>
<style scoped="scoped " lang="less">
.mask {
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.4);
position: fixed;
left: 0px;
top: 0px;
display: flex;
justify-content: center;
align-items: center;
z-index: 10000;
.toast-msg {
font-size: 0.24rem;
text-align: center;
position: relative;
transform: translateX(-50%);
color: #fff;
left: 50%;
padding: 0.18rem 0.27rem;
overflow: hidden;
border-radius: 4px;
white-space: nowrap;
display: block;
background: rgba(0, 0, 0, 0.7);
}
.toast {
font-size: 0rem;
padding: 0.27rem .090rem;
width: 2.26rem;
overflow: hidden;
display: flex;
align-items: center;
flex-direction: column;
color: #f2f2f2;
background: rgba(51, 51, 51, 0.94);
border-radius: 0.09rem;
text-align: center;
.icon {
width: 0.72rem;
height: 0.72rem;
border-radius: 50%;
border: 1px solid #f2f2f2;
position: relative;
justify-content: center;
align-items: center;
display: flex;
position: relative;
.success-icon {
border-right: 1px solid #f2f2f2;
border-bottom: 1px solid #f2f2f2;
transform: rotate(45deg);
width: 0.27rem;
height: 0.45rem;
margin-top: -0.18rem;
}
.fail-icon {
&:before {
content: " ";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotate(45deg);
border-top: 1px solid #f2f2f2;
width: 0.5rem;
height: 0px;
}
&:after {
content: " ";
content: " ";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotate(-45deg);
border-top: 1px solid #f2f2f2;
width: 0.5rem;
height: 0px;
}
}
.warning-icon {
&:before {
content: " ";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -500%) rotate(90deg);
border-top: 1px solid #f2f2f2;
width: 0.27rem;
height: 0px;
}
&:after {
content: " ";
content: " ";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, 250%) rotate(-45deg);
background: #f2f2f2;
width: 3px;
border-radius: 50%;
height: 3px;
}
}
}
.msg {
margin-top: 0.18rem;
font-size: 0.24rem;
}
}
}
.loading-icon {
font-size: 0px;
box-sizing: border-box;
width: 0.72rem;
height: 0.72rem;
position: relative;
span {
position: absolute;
height: 1px;
left: 50%;
top: 50%;
width: 0.18rem;
animation: loading-fade-light 1.1s infinite linear;
background: rgba(255, 255, 255, 0.3);
transform-origin: -0.18rem 50%;
margin-left: 0.18rem;
&:nth-child(1) {
animation-delay: 0s;
transform: rotate(0deg);
}
&:nth-child(2) {
animation-delay: 0.1s;
transform: rotate(30deg);
}
&:nth-child(3) {
animation-delay: 0.2s;
transform: rotate(60deg);
}
&:nth-child(4) {
animation-delay: 0.3s;
transform: rotate(90deg);
}
&:nth-child(5) {
animation-delay: 0.4s;
transform: rotate(120deg);
}
&:nth-child(6) {
animation-delay: 0.5s;
transform: rotate(150deg);
}
&:nth-child(7) {
animation-delay: 0.6s;
transform: rotate(180deg);
}
&:nth-child(8) {
animation-delay: 0.7s;
transform: rotate(210deg);
}
&:nth-child(9) {
animation-delay: 0.8s;
transform: rotate(240deg);
}
&:nth-child(10) {
animation-delay: 0.9s;
transform: rotate(270deg);
}
&:nth-child(11) {
animation-delay: 1s;
transform: rotate(300deg);
}
&:nth-child(12) {
animation-delay: 1.1s;
transform: rotate(330deg);
}
}
}
@-webkit-keyframes loading-fade-light {
0% {
background-color: #fff;
}
100% {
background-color: rgba(255, 255, 255, 0);
}
}
@keyframes loading-fade-light {
0% {
background-color: #fff;
}
100% {
background-color: rgba(255, 255, 255, 0);
}
}
</style>
複製代碼
入口文件註冊:github
import vueToast from '@/components/vue-toast'
Vue.use(vueToast);
複製代碼
Toast/index.jsweb
import React from "react";
import ReactDOM from 'react-dom';
import Toast from './toast';
export default class Global {
static toastEle='';
static toast(option) {
var setting={
type:0,
content:"默認信息",
time:2000,
opacity:0,
onSucc:()=>{}
};
if(typeof option =="string"){
setting={...setting,content:option,type:4}
}else{
setting={...setting,...option}
}
this.show(0,setting);
if(setting.type!==3){ //loading須要手動關閉
setTimeout(() => {
this.hide();
setting.onSucc();
}, setting.time);
}
}
static dialog(option) {
var setting={
type:0,
title:"我是默認title",
content:"我是默認content",
btnSucc:"我是默認btn",
CloseShow:false,
onClose(){
console.log("蒙層回調");
},
onSucc(){
console.log("成功回調");
},
onFail(){
console.log("失敗回調");
}
};
setting={...setting,...option};
this.show(1,setting);
}
static show(n,setting) {
var div = document.createElement('div');
var id = document.createAttribute("id");
this.toastEle='pluginEle-'+new Date().getTime();
id.value = this.toastEle;
div.setAttributeNode(id);
document.body.appendChild(div);
ReactDOM.render(<Toast setting={setting} />, div);
}
static hide() {
var toastEle = document.querySelector("#"+this.toastEle);
if(toastEle){
ReactDOM.unmountComponentAtNode(toastEle);
document.body.removeChild(toastEle);
}
}
}
複製代碼
Toast/toast.jsbash
import React from "react";
import './toast.less'
export default class Toast extends React.Component {
constructor(props) {
super(props);
}
checkToast(n) {
switch(n) {
case 0:
return (<div className="icon">
<div className="success-icon"></div>
</div>)
break;
case 1:
return (<div className="icon">
<div className="fail-icon"></div>
</div>)
break;
case 2:
return (<div className="icon">
<div className="warning-icon"></div>
</div>)
break;
case 3:
return (
<div className="loading-icon">
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
)
break;
default:
return null
}
}
render() {
let {
type,content,opacity = 0
} = this.props.setting;
let style = {
"background": `rgba(0,0,0,${opacity})`
}
return(
<div className="mask" style={style}>
<div className="toast">
{this.checkToast(type)}
<div className="msg">{content}</div>
</div>
</div>
);
}
}
複製代碼
Toast/toast.lessapp
.mask {
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.4);
position: fixed;
left: 0px;
top: 0px;
display: flex;
justify-content: center;
align-items: center;
z-index: 10000;
.toast-msg {
font-size: 24px;
text-align: center;
position: relative;
transform: translateX(-50%);
color: #fff;
left: 50%;
padding:18px 27px;
overflow: hidden;
border-radius: 4px;
white-space: nowrap;
display: block;
background: rgba(0, 0, 0, 0.7);
}
.toast {
font-size: 0px;
padding: 27px 9px;
width: 226px;
overflow: hidden;
display: flex;
align-items: center;
flex-direction: column;
color: #f2f2f2;
background: rgba(51, 51, 51, 0.94);
border-radius: 9px;
text-align: center;
.icon {
width:72px;
height:72px;
border-radius: 50%;
border: 1px solid #f2f2f2;
position: relative;
justify-content: center;
align-items: center;
display: flex;
position: relative;
margin-bottom: 18px;
.success-icon {
border-right: 1px solid #f2f2f2;
border-bottom: 1px solid #f2f2f2;
transform: rotate(45deg);
width:27px;
height: 45px;
margin-top: -18px;
}
.fail-icon {
&:before {
content: " ";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotate(45deg);
border-top: 1px solid #f2f2f2;
width: 50px;
height: 0px;
}
&:after {
content: " ";
content: " ";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotate(-45deg);
border-top: 1px solid #f2f2f2;
width: 50px;
height: 0px;
}
}
.warning-icon {
&:before {
content: "";
display: block;
position: absolute;
top: 15px;
left: 50%;
background:#f2f2f2;
width:1px;
height: 30px;
}
&:after {
content: "";
position: absolute;
bottom: 14px;
left: 50%;
background:#f2f2f2;
width: 6px;
margin-left: -2px;
border-radius: 50%;
height: 6px;
}
}
}
.msg {
font-size:24px;
}
}
}
.loading-icon {
font-size: 0px;
margin-bottom: 18px;
box-sizing: border-box;
width: 72px;
height: 72px;
position: relative;
span {
position: absolute;
height: 1px;
left: 50%;
top: 50%;
width: 18px;
animation: loading-fade-light 1.1s infinite linear;
background: rgba(255, 255, 255, 0.3);
transform-origin: -18px 50%;
margin-left: 18px;
&:nth-child(1) {
animation-delay: 0s;
transform: rotate(0deg);
}
&:nth-child(2) {
animation-delay: 0.1s;
transform: rotate(30deg);
}
&:nth-child(3) {
animation-delay: 0.2s;
transform: rotate(60deg);
}
&:nth-child(4) {
animation-delay: 0.3s;
transform: rotate(90deg);
}
&:nth-child(5) {
animation-delay: 0.4s;
transform: rotate(120deg);
}
&:nth-child(6) {
animation-delay: 0.5s;
transform: rotate(150deg);
}
&:nth-child(7) {
animation-delay: 0.6s;
transform: rotate(180deg);
}
&:nth-child(8) {
animation-delay: 0.7s;
transform: rotate(210deg);
}
&:nth-child(9) {
animation-delay: 0.8s;
transform: rotate(240deg);
}
&:nth-child(10) {
animation-delay: 0.9s;
transform: rotate(270deg);
}
&:nth-child(11) {
animation-delay: 1s;
transform: rotate(300deg);
}
&:nth-child(12) {
animation-delay: 1.1s;
transform: rotate(330deg);
}
}
}
@-webkit-keyframes loading-fade-light {
0% {
background-color: #fff;
}
100% {
background-color: rgba(255, 255, 255, 0);
}
}
@keyframes loading-fade-light {
0% {
background-color: #fff;
}
100% {
background-color: rgba(255, 255, 255, 0);
}
}
複製代碼
使用less
import $ from '@/component/Toast/index';
...
$.toast({
type:0,
content: "我是默認Toast",
time: 1000,
opacity: .5,
onSucc() {
console.log("我是Toast的回調!")
}
});
// $.toast("我是默認Toast");
複製代碼
有坑!主要緣由仍是組件的this神出鬼沒!dom