最近碰到一个实现全局toast的面试题,然后翻阅资料发现Vue提供了Vue.extend()可以实现这个功能,后续封装其他业务组件时也可使用此方法。以此文章以作笔记。
题目大概如下:
Toast支持string/object两种类型的调用,其基本的样式为垂直/水平居中于屏幕中央,图片文字上下混排
首先
我先准备好一个vue2.x的项目,然后写好一个组件Toast。一般我会放在components目录下。
// toast.vue文件
<template>
<div class="toast" v-if="show">
<div>
<img v-if="imgUrl" :src="imgUrl" alt="">
</div>
<span>{{ msg }}</span>
</div>
</template>
<style scoped>
.toast{
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
border-radius: 3px;
max-width: 200px;
padding: 10px;
background: #333;
color: #fff;
font-size: 14px;
opacity: .9;
text-align: justify;
word-break: break-all;
word-wrap: break-word;
display: flex;
flex-direction: column;
align-items: center;
}
.toast img{
width: 50px;
height: 50px;
}
</style>
这里就是vue文件的样式结构代码。其中通过show参数来控制toast的显示隐藏,imgUrl参数控制传入的图片,msg参数代表轻提示的文案。
第二步
在plugins目录下建了个toast.js文件,代码如下:
import toast from "@/components/toast"
export default (Vue) => {
let toastComp = Vue.extend(toast);
function showToast(msg ,imgUrl = '', duration = 3e3){
let toastDom = new toastComp({
data(){
return{
show: true,
msg: typeof msg === 'object'? msg.msg: msg,
imgUrl: typeof msg === 'object'? msg.imgUrl: imgUrl,
}
}
}).$mount()
document.body.appendChild(toastDom.$el);
setTimeout(() => {
toastDom.show = false
}, duration)
}
Vue.prototype.$toast = showToast;
}
-
Vue.extend: 可以简单的理解为当在模板中遇到该组件名称作为标签的自定义元素时,会自动调用扩展实例构造器来生产组件实例,并挂载到自定义元素上。官网地址:https://cn.vuejs.org/v2/api/#Vue-extend
-
通过new创建实例传入的data函数代表的就是toast.vue文件里面的data对象,所以可以直接在toast.vue文件中直接使用这些
-
在通过appendChild方法把他添加到document.body中。
-
setTimeout就是用来控制toast显示的时间。
-
最后把方法挂在到全局变量vue的身上,这样就能通过this来调用。
第三步
在main.js中引入使用
import toast from "@/plugins/toast";
Vue.use(toast);
最后在组件中使用
//字符串调用
this.$toast("message","https://img1.baidu.com/it/u=3548238993,1758041513&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500", 3000);
//object方式调用
// this.$toast({
// msg: 'toast',
// imgUrl: 'https://img1.baidu.com/it/u=3548238993,1758041513&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500'
// });
效果如下: