乐趣区

Vue-封装Toast消息提示

Vue 封装 Toast 消息提示

学习 Vue 的道路上, 封装一些自定义的组件不可避免,今天就来封装一个 Toast 消息提示。后面还有 dialog 对话框,原理差不多。

首先先看看效果图

现在才知道用 qq 录制 gif 图是真方便。(非广告, 后面会多用 gif 图)

1 正常组件调用

2 全局注册对象调用 (不知道是不是叫这个名字)

一 首先,我们先封装一个正常组件看看效果。

  • 1 首先创建一个最普通的组件 /toast/Toast.vue 看看效果.
<template>
    <div class="Toast"
         v-if="showToast">
        {{message}}
    </div>
</template>
<script>
    export default {
        name: "Toast",
        props: {
            showToast: {
                // 激活
                type: Boolean,
                default: false
            },
            message: {
                type: String,
                required: true
            },
            delay: {
                type: Number,
                default: 3000
            }
        },
        data() {return {}
        },
        methods: {
            // Toast 消失
            disappear() {if (this.showToast) {setTimeout(() => {this.$emit("disappear");
                    }, this.delay)
                }
            },
        },
        watch: {showToast() {this.disappear()
            },
        },
    }
</script>

<style scoped>
    .Toast {
        position: fixed;
        left: 50%;
        top: 50%;
        background: rgb(233, 233, 235);
        padding: 10px;
        border-radius: 5px;
        transform: translate(-50%, -50%);
        animation: show-toast .2s;
        color: #909399;
        overflow: hidden;
        display: flex;
        align-items: center;
    }

    @keyframes show-toast {
        from {opacity: 0;}
        to {opacity: 1;}
    }
</style>
  • 2 调用看看效果

<template>
    <div>
        <toast
                :showToast="true"
                message="测试"
        />
    </div>

</template>

<script>
    import Toast from '@/components/common/toast/Toast'

    export default {
        name: 'Profile',
        data() {return {}
        },
        methods:{ },
        components: {Toast,}
    }
</script>

<style scoped>
  

</style>

然后就能看到这样的效果,但是样式不够好看。

  • 3 稍微美化一下

我颜色搭配也没什么经验,就参考的 ElementUI。

添加了 type 样式,还有提示的小图标,共四种,需要自行去阿里矢量图下载。

<template>
    <div class="Toast"
         :class="type"
         v-if="showToast">
        <span class="icon">
            <!--<img :src="iconSrc"/>-->
        </span>
        {{message}}
    </div>
</template>

<script>
    /**
     * 自己封装的 Toast v0.1
     * params: showToast Boolean 是否激活 toast 默认 false
     * params: type String       toast 提示类型 共 normal success,fail,warning 四个选项 默认 normal
     * params: message String    toast 消息
     * params: delay Number      toast 显示时间 默认 3000ms
     * */
    export default {
        name: "Toast",
        props: {
            showToast: {
                // 激活
                type: Boolean,
                default: false
            },
            type: {
                // 三种弹窗提示类型
                type: String,
                default: "normal"
            },
            message: {
                type: String,
                required: true
            },
            delay: {
                type: Number,
                default: 3000
            }
        },
        data() {return {}
        },
        methods: {
            // Toast 消失
            disappear() {if (this.showToast) {setTimeout(() => {this.$emit("disappear");
                    }, this.delay)
                }
            },
        },
        watch: {showToast() {this.disappear()
            },
        },
        computed: {iconSrc() {
                // 这里使用的阿里矢量图
                let tipType = ["normal", "success", "warning", "fail"];
                if (tipType.includes(this.type)) {return require(`@/assets/img/common/${this.type}.svg`)
                } else {throw "Toast type 数据只允许为 normal, success, warning, fail 四种其中的一种,默认为 normal"}
            }
        },


    }
</script>

<style scoped>
    .Toast {
        position: fixed;
        left: 50%;
        top: 50%;
        background: rgb(233, 233, 235);
        padding: 10px;
        border-radius: 5px;
        transform: translate(-50%, -50%);
        animation: show-toast .2s;
        color: #909399;
        overflow: hidden;
        display: flex;
        align-items: center;
    }

    @keyframes show-toast {
        from {opacity: 0;}
        to {opacity: 1;}
    }

    .success {
        color: #67C23A;
        background: rgb(225, 243, 216);
    }

    .warning {
        color: #E6A23C;
        background: rgb(250, 236, 216);
    }

    .fail {
        color: #F56C6C;
        background: rgb(253, 226, 226);
    }

    .icon img {
        width: 20px;
        height: 20px;
        margin-top: 3px;
        margin-right: 4px;
    }
</style>
  • 4 再看看美化后的效果, 有四种类型,就只看 success 类型的。

对应完整代码 Github 地址 https://github.com/CoderCharm…

组件调用总结

调用非常不方便,使用需要导入,传入参数,回调之类的,不符合使用习惯,像 ElementUI 那种,使用起来就特别方便。
下一步就是超那个方向封装。

二 组件封装全局注册

  • 1 这次重新创建一个 /toast/CustToast.vue 组件,里面就不怎么写逻辑.
<template>

    <div class="CustToast"
         :class="type"
         v-if="showToast">

        <span class="icon">
            <img :src="iconSrc"/>
        </span>

        {{message}}
    </div>

</template>

<script>
    export default {
        /**
         * 自己封装的 Toast v0.2
         * params: showToast Boolean 是否激活 toast 默认 false
         * params: type String       toast 提示类型 共 normal success,fail,warning 四个选项 默认 normal
         * params: message String    toast 消息
         * params: duration Number      toast 显示时间 默认 3000ms
         * */
        name: "CustToast",
        data() {
            return {
                showToast: true,
                type: "normal",
                message: "消息提示",
                duration: 3000
            }
        },
        computed: {iconSrc() {window.console.log("当前类型", this.type);
                let tipType = ["normal", "success", "warning", "fail"];
                if (tipType.includes(this.type)) {return require(`@/assets/img/common/${this.type}.svg`)
                } else {throw "Toast type 数据只允许为 normal, success, warning, fail 四种其中的一种,默认为 normal"}
            }
        },
    }
</script>

<style scoped>
    .CustToast {
        position: fixed;
        left: 50%;
        top: 50%;
        background: rgb(233, 233, 235);
        padding: 10px;
        border-radius: 5px;
        transform: translate(-50%, -50%);
        animation: show-toast .2s;
        color: #909399;
        overflow: hidden;
        display: flex;
        align-items: center;
    }

    @keyframes show-toast {
        from {opacity: 0;}
        to {opacity: 1;}
    }

    .success {
        color: #67C23A;
        background: rgb(225, 243, 216);
    }

    .warning {
        color: #E6A23C;
        background: rgb(250, 236, 216);
    }

    .fail {
        color: #F56C6C;
        background: rgb(253, 226, 226);
    }

    .icon img {
        width: 20px;
        height: 20px;
        margin-top: 3px;
        margin-right: 4px;
    }

</style>
  • 2 然后在同级目录创建 /toast/index.js 文件组册,给 Vue 添加原型 $toast
//
import vue from 'vue'

// 导入自定义到 Toast 组件
import CustToast from './CustToast.vue'


// 生成一个扩展实例构造器
const ToastConstructor = vue.extend(CustToast);

// 定义弹出组件的函数 接收三个参数 消息 toast 类型 显示时间
function showToast(message, type="normal", duration = 2000) {

    // 实例化一个 CustToast.vue
    const _toast = new ToastConstructor({data() {
            return {
                showToast: true,
                type: type,
                message: message,
                duration: duration
            }
        }
    });

    // 把实例化的 CustToast.vue 添加到 body 里
    let element = _toast.$mount().$el;
    document.body.appendChild(element);

    // duration 时间到了后隐藏
    setTimeout(() => {_toast.showToast = false} ,duration)
}

// 需要在 main.js 里面使用 Vue.use(showToast);
showToast.install = (Vue) => {
    // 将组件注册到 vue 的 原型链里去,
    // 这样就可以在所有 vue 的实例里面使用 this.$toast()
    Vue.prototype.$toast = showToast
};

// 导出
export default showToast
  • 3 vue-cli main.js 文件注册
import showToast from '@/ 你的路径 /toast/index'

Vue.use(showToast);
  • 4 使用
// 封装的时候, 定义了三个参数,message 必须要传
// message, type="normal", duration = 2000

this.$toast("测试普通")
this.$toast("测试成功", "success", 5000)
this.$toast("测试警告", "warning")
this.$toast("测试失败", "fail")

就可以看到开头,我那个演示的 gif 了。

当然呢,消息提示显示的位置,我没自定义统一显示在中间,同样是按照 type 一样的思路, 给个 class 样式就可以了。
还有就消失的动画没处理,多个消息弹出的时候直接折叠了。

第二个封装样式 Github 地址: https://github.com/CoderCharm…

封装总结

我是第一次封装自己的全局对象,Vue 原型挂载, vue.extend 的用法。官网 Vue.extend 说明 https://cn.vuejs.org/v2/api/i…

感觉还行的话,就去我那个项目点个 star 吧????

退出移动版