以下是仿照nutui的toast组件进行封装的:
文件结构:(在components下)
index.js:
import cusToast from './_toast'; import './toast.scss'; cusToast.install = function (Vue) { Vue.prototype['$cusToast'] = cusToast; } export default cusToast;
_toast.js
import Vue from "vue"; import settings from "./toast.vue"; let ToastConstructor = Vue.extend(settings); let instance;//实例 let instanceArr = [];//实例列表 let defaultOptionsMap = {};//默认配置参数地图 const defaultOptions = {//默认配置参数 msg:"",//提示文字 type:"",//提示框类型 visible:false,//是否显示 duration: 2000, //显示时间(毫秒) timer: null,//计时器 textTimer: null,//文本的计时器 onClose: null,//关闭提示框回调 closeOnClickOverlay: false,//是否可以点击遮罩来关闭提示框 textAlignCenter: true,//文字是否居中 bgColor: "#ffffff",//背景颜色 coverColor: "rgba(0, 0, 0, 0.3)",//遮罩颜色 customClass: "",//自定义类名 msgColor:"#686f80",//提示文字颜色 }; let currentOptions = { //浅克隆一个默认配置 ...defaultOptions }; function _showToast() { //挂载组件 instance.vm = instance.$mount(); document.body.appendChild(instance.$el); Vue.nextTick(() => { instance.visible = true; }); } function _getInstance(obj) { //获取组件实例 let opt = { id: new Date().getTime(),//new Date().getTime() 避免重复出现弹出框 ...currentOptions,//默认配置 ...defaultOptionsMap[obj.type],//??? ...obj,//传入的配置 }; //有相同id者共用一个实例,否则新增实例 if (opt["id"] && instanceArr[opt["id"]]) { instance = instanceArr[opt["id"]]; instance.hide(true); instance = Object.assign(instance, opt); } else { instance = new ToastConstructor({ data: Object.assign(opt, obj) }); opt["id"] && (instanceArr[opt["id"]] = instance); } _showToast(); return instance; } function errorMsg(msg) { if (!msg) { console.warn(" msg不能为空"); return; } } let Toast = { text(msg, obj = {}) { errorMsg(msg); return _getInstance({ ...obj, msg, type: "text" }); }, loading(msg, obj = {}){ obj = { ...obj, id: obj.id || "loading", msg, type: "loading" }; obj.duration = 0; //loading类型默认不自动关闭 return _getInstance(obj); } }; export default Toast;
toast.vue
<template> <transition name="toastfade"> <div :id="id" :class="toastClass" v-if="visible" :style="{ 'background-color': coverColor }" @click="clickCover"> <div class="cus-toast-inner" :style="{ 'text-align': textAlignCenter ? 'center' : 'left', 'background-color': type != 'loading' ? bgColor :'' }"> <div v-if="type != 'loading'" class="cus-toast-text" :style="{ 'color':msgColor }">{{msg}}</div> <div class="cus_confirm_btn" v-if="type != 'loading'" @click="closeToast">确认</div> <div class="cus_loading" v-else> <i class="cus-toast-icon-rotate"></i> <div>{{msg}}</div> </div> </div> </div> </transition> </template> <script> export default { watch: { visible(val) { if (val) { this.show(); } } }, computed: { toastClass(){ return [ "cus_toast", this.customClass, ] }, }, data(){ return{ id:"", msg:"", type:"", visible:false, duration:2000, timer: null,//计时器 textTimer: null,//文本的计时器 onClose: null,//关闭提示框回调 closeOnClickOverlay: false,//是否可以点击遮罩来关闭提示框 textAlignCenter: true,//文字是否居中 bgColor: "#ffffff",//背景颜色 coverColor: "rgba(0, 0, 0, 0.3)",//遮罩颜色 customClass: "",//自定义类名 msgColor:"#686f80",//提示文字颜色 } }, methods: { show(force) { //显示 this.clearTimer(); clearTimeout(this.textTimer); if (this.duration) { this.timer = setTimeout(() => { this.hide(force); }, this.duration); } }, hide(force) { //隐藏 this.clearTimer();//清除计时器 this.visible = false; if (force) { //清除文字计时器 clearTimeout(this.textTimer); } else { //清除文字计时器 带提示语一起清空 this.textTimer = setTimeout(() => { clearTimeout(this.textTimer); this.msg = ""; }, 300); } typeof this.onClose === "function" && this.onClose(); }, clearTimer() { //清除计时器 if (this.timer) { clearTimeout(this.timer); this.timer = null; } }, clickCover() { //点击遮罩 关闭提示框 if (this.closeOnClickOverlay) { this.hide(); } }, closeToast(){ //关闭弹窗 this.hide(); } }, destroyed() { this.textTimer = null; this.timer = null; } } </script>
toast.scss
.cus_toast{ position: fixed; left:0; top:0; bottom:0; right:0; height:100vh; text-align: center; box-sizing: border-box; // pointer-events: none; z-index: 9999; .cus-toast-inner { position: absolute; top:50%; left:50%; transform: translate(-50%,-50%); font-size: 14px; max-width: 65%; min-width:180px; text-align: center; line-height: 1.5; word-break: break-all; border-radius: 7px; color: #fff; overflow: hidden; .cus-toast-text{ font-weight: bold; padding: 20px 10px 10px; } .cus_confirm_btn{ height:40px; color:#136be0; line-height: 40px; border-top:1px solid #ededed; } .cus_loading{ color:#136be0; .cus-toast-icon-rotate { display: inline-block; width: 30px; height: 30px; background-repeat: no-repeat; background-size: 100%; animation: rotation 2s linear infinite; background: url("data:image/svg+xml, %3Csvg class='icon' viewBox='0 0 1024 1024' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='rgb(12,110,228)' d='M874.667 533.333h-192c-12.8 0-21.334-8.533-21.334-21.333 0-12.8 8.534-21.333 21.334-21.333h192c12.8 0 21.333 8.533 21.333 21.333 0 12.8-8.533 21.333-21.333 21.333zM648.533 407.467C640 416 627.2 416 618.667 407.467c-8.534-8.534-8.534-21.334 0-29.867L755.2 241.067c8.533-8.534 21.333-8.534 29.867 0 8.533 8.533 8.533 21.333 0 29.866L648.533 407.467zM512 896c-12.8 0-21.333-8.533-21.333-21.333v-192c0-12.8 8.533-21.334 21.333-21.334s21.333 8.534 21.333 21.334v192c0 12.8-8.533 21.333-21.333 21.333zm0-533.333c-12.8 0-21.333-8.534-21.333-21.334v-192c0-12.8 8.533-21.333 21.333-21.333s21.333 8.533 21.333 21.333v192c0 12.8-8.533 21.334-21.333 21.334zM270.933 782.933c-8.533 8.534-21.333 8.534-29.866 0s-8.534-21.333 0-29.866L377.6 616.533c8.533-8.533 21.333-8.533 29.867 0 8.533 8.534 8.533 21.334 0 29.867L270.933 782.933zm104.534-375.466L238.933 270.933c-8.533-8.533-8.533-21.333 0-29.866s21.334-8.534 29.867 0L405.333 377.6c8.534 8.533 8.534 21.333 0 29.867-6.4 6.4-21.333 6.4-29.866 0zM362.667 512c0 12.8-8.534 21.333-21.334 21.333h-192C136.533 533.333 128 524.8 128 512c0-12.8 8.533-21.333 21.333-21.333h192c12.8 0 21.334 8.533 21.334 21.333zm285.866 104.533l136.534 136.534c8.533 8.533 8.533 21.333 0 29.866-8.534 8.534-21.334 8.534-29.867 0L618.667 646.4c-8.534-8.533-8.534-21.333 0-29.867 6.4-6.4 21.333-6.4 29.866 0z'/%3E%3C/svg%3E") no-repeat; background-size: cover; } } } } //渐变 .toastfade-enter-active { transition: opacity 0.1s; } .toastfade-leave-active { transition: opacity 0.3s; } .toastfade-enter, .toastfade-leave-active { opacity: 0; }
使用
在main.js中注册
import cusToast from '@/components/cusToast';
cusToast.install(Vue);
在页面中使用
this.$toast.text("提示语",3000)
loading的使用
import cusToast from '@/components/cusToast'; var loading; loading=cusToast.loading('');//开启loading loading.hide();//关闭loading
可以根据自己的要求调整
。