根据自己需求,设计出自己想要的弹窗!
该文章用了代码用了typescript,注意一下。
alert弹窗组件
该组件设计需求是模范微信小程序的Toast
效果如图:
代码如下:
<template>
<div class="alert">
<!-- 遮罩层防穿透 -->
<div class="alert-mask" v-if="messageInfo.mask"></div>
<div class="alert-box" v-if="messageInfo.content">
<!-- icon -->
<div v-if="messageInfo.icon==='success'">
<img class="alert-icon" src="/static/images/icon-success.png" alt />
</div>
<!-- 消息 一行设置7个汉字,最多2行-->
<span>{{messageInfo.content}}</span>
</div>
</div>
</template>
<style scoped>
.alert-box {
position: fixed;
top: 50%;
transform: translateY(-50%);
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.6);
color: white;
text-align: center;
padding: 10px 8px;
border-radius: 5px;
width: 115px;
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
-webkit-line-clamp: 2;
z-index: 999;
}
.alert-mask {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 998;
}
.alert-icon {
width: 50px;
height: 50px;
}
</style><script lang="ts">
import { Vue, Component } from "vue-property-decorator";
@Component({})
export default class Alert extends Vue {
private messageInfo: Object = {};
private count = 0;
public setMsgID() {
return "alert_" + this.count++;
}
public add(msg) {
this.messageInfo = msg;
const duration = msg.duration;
if ((this.messageInfo as any).success) {
try {
(this.messageInfo as any).success();
} catch (error) {
console.error(error);
}
}
setTimeout(() => {
this.remove();
}, duration);
}
public remove() {
this.messageInfo = {};
return;
}
mounted() {}
}
</script>
实例调用:
this.$Toast.info({
message:'提交成功',
duration:1500,
icon:'success',
mask:true,
success:()=>{
console.log('调用成功')
}
})代码分析:
调用全局$Toast.info方法,创建一个alert组件。以相对于窗口垂直居中显示。
组件设置:宽度固定值115px,一行最多可显示7个中文汉字,至多2行。根据'-webkit-line-clamp: 2;'样式来修改行数。
Loading组件
效果图如图:,实际为动图(不会截GIF图片),类似跳动的动画效果
代码如下:
<style scoped>
.loading-box {
position: fixed;
top: 50%;
transform: translateY(-50%);
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.6);
color: white;
text-align: center;
padding: 15px 8px;
border-radius: 5px;
width: 115px;
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
-webkit-line-clamp: 2;
z-index: 999;
}
.loading-mask {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 998;
}
.loading {
width: 80px;
margin: 0 auto;
display: flex;
padding: 10px 0;
}
.loading-item {
width: 4px;
height: 50px;
background: white;
animation: loading 1s infinite;
margin: 0 auto;
}
.loading-item:nth-child(1) {
animation-delay: -0.9s;
}
.loading-item:nth-child(2) {
animation-delay: -0.8s;
}
.loading-item:nth-child(3) {
animation-delay: -0.7s;
}
.loading-item:nth-child(4) {
animation-delay: -0.6s;
}
.loading-item:nth-child(5) {
animation-delay: -0.5s;
}
.loading-item:nth-child(6) {
animation-delay: -0.4s;
}
@keyframes loading {
0%,
40%,
100% {
transform: scaleY(0.25);
}
20% {
transform: scaleY(1);
}
}
</style>
<template>
<div class="loading">
<!-- 遮罩层防穿透 -->
<div class="loading-mask" v-if="loading.mask"></div>
<div class="loading-box" v-if="loading !=''">
<div class="loading">
<div class="loading-item" v-for="item in 6" :key="item"></div>
</div>
<!-- 消息 一行设置7个汉字,最多2行-->
<span v-if="loading.content">{{loading.content}}</span>
</div>
</div>
</template>
<script lang="ts">
import { Vue, Component, Prop } from "vue-property-decorator";
@Component({})
export default class Loading extends Vue {
private loading = "";
private count = 0;
mounted() {}
private setLoadingID() {
return "loading_" + this.count;
}
private add(loading) {
// 关闭之前调用的loading
if (this.loading) {
this.close();
}
this.loading = loading;
if ((this.loading as any).success) {
try {
(this.loading as any).success();
} catch (error) {
console.error(error);
}
}
}
public close() {
this.loading = "";
}
}
</script>
实例调用:
this.$Toast.loading({
message:'加载中',
duration:30000,
mask:true,
success:()=>{
console.log('调用成功')
}
})代码分析:
loading调用其实跟alert差不多,少了个icon参数。
icon在loading组件中用css动画实现了,以后想实现那种加载样式自己改就行了。(菊花式加载,涟漪缓动等花里胡哨的样式)。
动画参考文章juejin.cn/post/684490…
挂载全局
创建 mountCompoment.ts 文件
import Alert from './alert.vue';
import Loading from './loading.vue'
import Vue from 'vue';
// alert 实例
(Alert as any).newInstance = ( properties )=> {
let prop = properties||{}
const instance = new Vue({
data:prop,
render(h) {
return h(Alert)
}
})
const component = instance.$mount();
document.body.appendChild(component.$el);
const alert = instance.$children[0];
return{
add(msg) {
alert.add(msg);
},
remove(id) {
alert.remove(id);
}
}
}
let messageInstance;
function getMessageInstance() {
messageInstance = messageInstance||(Alert as any).newInstance()
return messageInstance;
}
// 设置 alert组件参数
function message(options) {
let instance = getMessageInstance();
instance.add({
content:options.message||'',
duration:options.duration||1500,
icon:options.icon||'',
mask:options.mask||false,
success:options.success||null
})
}
// loading 实例
(Loading as any).newInstance = ( properties )=> {
let prop = properties||{}
const instance = new Vue({
data:prop,
render(h) {
return h(Loading)
}
})
const component = instance.$mount();
document.body.appendChild(component.$el);
const alert = instance.$children[0];
return{
add(loading) {
alert.add(loading);
},
close() {
alert.close();
}
}
}
let loadingInstance;
function getLoadingInstance() {
loadingInstance = loadingInstance||(Loading as any).newInstance()
return loadingInstance;
}
// 设置 Loading组件
function setLoading(options,type) {
let instance = getLoadingInstance();
if(type === 'loading') {
instance.add({
content:options.message||'',
duration:options.duration||60000,
icon:options.icon||'',
mask:options.mask||false,
success:options.success||null
})
} else {
instance.close();
}
}
// 实例挂载
export default{
// alert 和 loading 只能存在一个
info(options) {
if(loadingInstance) {
loadingInstance.close();
}
return message(options)
},
loading(options) {
if(messageInstance) {
messageInstance.remove()
}
return setLoading(options,'loading')
},
close(options) {
return setLoading(options,'close')
}
}
代码分析:
创建组件:在方法newInstance中,创建了一个Vue实例,用render函数返回组件alert/loading。通过$mount()挂载,插入文档。获取组件alert/loading 方法 add、remove、close。返回给 实例 messageInstance/loadingInstance。
最后export方法(info,loading,close)。设置 alert/loading 组件 只能单独出现。
相互调用的话就突出覆盖掉。
全局挂载
import mount from './components/alert/mountCompoment';
Vue.prototype.$Toast = mount
总结
很少写文章,语言组织的不是很好,见谅
希望这篇文章对你有所帮助,谢谢。
参考文章
封装Vue组件的一些技巧 juejin.cn/post/684490…
优化
loading组件 可设置为无时间限制,只能调用close来关闭。
多次调用alert组件,依次显示,参考上面文章链接