vue 3.0 封装 Toast 组件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue 3.0 封装 Toast 组件相关的知识,希望对你有一定的参考价值。

参考技术A

也可以使用 createVNode + render 这对组合

也支持直接导入函数使用 import Toast from \'@src/components/Toast\'

注: 本篇文章使用了 typescript ,如果你是使用的 javascript,只需要把类型去掉即可

Vue开发个简单的Toast组件新手入门实例

最近体验了下Vue,Toast都是前端常用组件,顺便写个入门的实例给同是新手入门的同学一个参考吧
废话不多说,直接放码过来了。。。

Toast.vue 组件代码

<template>
    <div ref="toast" class="toast" @click="fadeout" :class="classes" :style="styles"><span class="toast-icon"></span><span class="toast-message"> message </span></div>
</template>
<script>
    import lodash from 'lodash'
    export default 
        name: 'Toast',
        data() 
            return 
                classes: [],
                styles: 
                    color: '#FF5500',
                ,
            
        ,
        props: 
            message: String,
            duration: 
                type: Number,
                default: 2000 // 持续显示的时长,单位 ms 为 0 则不自动消失需手动点击
            ,
            position: 
                // 定位,数组格式支持自定义位置,左上比较常用所以顺序为[left, top, right, bottom],
                // 单位:px, 若为 0~1 之间的小数时则表示占屏幕的百分比%
                // default()return [.1, .1],
                // 定位,预设 topLeft|topCenter|topRight|centerLeft|center|centerRight|bottomLeft|bottomCenter|bottomRight
                default: 'center',
            ,
            zIndex: 
                type: Number,
                default: 100000
            ,
            maxWidth: 
                type: String,
                default: '300px', // 最大宽度
            ,
            offset: 
                type: Array,
                default() 
                    // 仅用于对预设定位点(如:topLeft|center...)坐标在 [X, Y] 轴的偏移量修正,单位 px
                    // 作用于 margin-top|margin-left, 可以为负数; > 0 则偏向右下角,< 0 则偏向左上角
                    return [0, -300]
                
            
        ,
        computed: 
        ,
        methods: 
            fadeout() 
                this.classes.push('fadeout'); // 淡出效果直接覆盖了 fadein 的 css 设置
                lodash.delay(() => this.$destroy(), 500); // 淡出动画结束后再销毁
            ,
            show()
                this.$set(this.styles, 'zIndex', this.zIndex);
                this.$set(this.styles, 'maxWidth', this.maxWidth);
                if (lodash.isArray(this.position)) 
                    const [left, top, right, bottom] = this.position;
                    const resolve = (s, n) => 
                        if (n !== undefined) this.$set(this.styles, s, (n > 0 && n < 1) ? (n*100) + '%' : n +'px');
                    ;
                    resolve('top', top);
                    resolve('right', right);
                    resolve('bottom', bottom);
                    resolve('left', left);
                
                const isPrePos = lodash.isString(this.position); // 是字符串则认定为默认的预设定位点
                if (isPrePos) 
                    const pos = this.position.toString();
                    const isC1 = pos.indexOf('center') > -1;
                    const isC2 = pos.indexOf('Center') > -1;

                    // 设置预设定位点样式
                    this.classes.push(pos.replace(/([A-Z])/, (s) => '-' + s.toLowerCase()));

                    // 居中定位修正
                    if (isC1 || isC2) 
                        if (pos === 'center' || isC1) 
                            this.$set(this.styles, 'marginTop',
                                ((isPrePos ? (this.$refs.toast.clientHeight * -1 / 2) : 0) + this.offset[1]) + 'px');
                        
                        if (pos === 'center' || isC2) 
                            this.$set(this.styles, 'marginLeft',
                                ((isPrePos ? (this.$refs.toast.clientWidth * -1 / 2) : 0) + this.offset[0]) + 'px');
                        
                    
                
                // 添加淡入效果
                this.classes.push('fadein');
                this.duration > 0 && lodash.delay(() => 
                    this.fadeout();
                , this.duration);
            ,
        ,
        created: function () 
            this.$nextTick(function()
                this.show();
            );
        ,
        destroyed: function () 
            this.$el.parentNode.removeChild(this.$el)
        
    
</script>
<style scoped>
    .toast 
        display: block;
        position: fixed;
        padding: .5rem;
        font-size: .8rem;
        background-color: #FFF;
        box-shadow: 0 0 5px rgba(0,0,0,.1);
        opacity: 0;
        word-break: break-all;
        word-wrap: break-word;
    
    .toast.top-left 
        top: 0;
        left: 0;
    
    .toast.top-center 
        top: 0;
        left: 50%;
    
    .toast.top-right 
        top: 0;
        right: 0;
    
    .toast.center-left 
        top: 50%;
        left: 0;
    
    .toast.center 
        top: 50%;
        left: 50%;
    
    .toast.center-right 
        top: 50%;
        right: 0;
    
    .toast.bottom-left 
        bottom: 0;
        left: 0;
    
    .toast.bottom-center 
        bottom: 0;
        left: 50%;
    
    .toast.bottom-right 
        bottom: 0;
        right: 0;
    
    .toast.fadein 
        opacity: 1;
        transition: opacity ease-in .2s;
    
    .toast.fadeout 
        opacity: 0;
        transform: scale(.5);
        transition: all ease-in-out .4s;
    
</style>

全局注册及使用方法

ToastTest.vue

<script>
    import Vue from "vue"
    import lodash from "lodash"
    import Toast from "Toast"

    let toastTimer;
    let toastIndex = 0;
    let toastQueueOffset = 0;

    const ToastConstructor = Vue.extend(Toast);
    Vue.prototype.$toast = function(data) 
        document.body.appendChild(new ToastConstructor(
            el: document.createElement('div'),
            propsData: data
        ).$el);
    ;
    export default 
        name: "ToastTest",
        components: Toast,
        methods: 
            showToast(e) 
                this.$toast(
                    message: 'Toast index '+ toastIndex++,
                    duration: 2000,
                    position: [e.clientX, e.clientY],
                );
            ,
            showToastRand() 
                this.$toast(
                    message: 'Toast index '+ toastIndex++,
                    duration: 0,
                    position: [parseInt(Math.random()*(window.innerWidth)), parseInt(Math.random()*window.innerHeight)],
                );
            ,
            showToastQueue(e) 
                const duration = 2000;
                clearTimeout(toastTimer);
                toastTimer = setTimeout(() => toastQueueOffset = 0, duration);
                this.$toast(
                    message: 'Toast index '+ toastIndex++,
                    duration: duration,
                    position: [e.clientX+100, 45*toastQueueOffset++],
                );
            
        ,
    
</script>
<template>
    <div class="articles-ct">
        <button class="draft-btn" @click="showToast"> + 鼠标 </button>
        <br><br>
        <button class="draft-btn" @click="showToastRand"> + 随机 </button>
        <br><br>
        <button class="draft-btn" @click="showToastQueue"> + 队列 </button>
    </div>
</template>

我随便写了三种使用方式示例

  1. 鼠标定位
  2. 全屏随机
  3. 屏幕队列

代码中有部分地方用到了 lodash 库,你可以安装下这个库或者修改下自己实现
下面看看效果图:

功能应该还是比较完善了,根据自己的需求再修改或搭配下参数就好了。

以上是关于vue 3.0 封装 Toast 组件的主要内容,如果未能解决你的问题,请参考以下文章

Vue 封装Toast消息提示

TypeScript(JavaScript)封装一个Toast组件

TypeScript(JavaScript)封装一个Toast组件

TypeScript(JavaScript)封装一个Toast组件

TypeScript(JavaScript)封装一个Toast组件

小程序如何封装自定义组件(Toast)