zl程序教程

您现在的位置是:首页 >  前端

当前栏目

自己封装一个简易的toast提示组件

封装组件 一个 自己 提示 简易 Toast
2023-09-11 14:19:39 时间

以下是仿照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

可以根据自己的要求调整