10 changed files with 12544 additions and 14854 deletions
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.6 KiB |
@ -0,0 +1,170 @@ |
|||||
|
<template> |
||||
|
<transition name="fade"> |
||||
|
<div v-if="visible" class="custom-message" :class="[type, position]"> |
||||
|
<img v-if="showImage" :src="imageUrl" class="message-image" /> |
||||
|
<i v-else :class="iconClass"></i> |
||||
|
<span class="message-content">{{ message }}</span> |
||||
|
</div> |
||||
|
</transition> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
name: 'CustomMessage', |
||||
|
props: { |
||||
|
type: { |
||||
|
type: String, |
||||
|
default: 'info', |
||||
|
validator: value => ['success', 'warning', 'error', 'info'].includes(value) |
||||
|
}, |
||||
|
message: { |
||||
|
type: String, |
||||
|
required: true |
||||
|
}, |
||||
|
duration: { |
||||
|
type: Number, |
||||
|
default: 3000 |
||||
|
}, |
||||
|
position: { |
||||
|
type: String, |
||||
|
default: 'top-center', |
||||
|
validator: value => ['top-center', 'top-right', 'top-left', 'bottom-center', 'bottom-right', 'bottom-left'].includes(value) |
||||
|
}, |
||||
|
showImage: { |
||||
|
type: Boolean, |
||||
|
default: false |
||||
|
}, |
||||
|
imageUrl: { |
||||
|
type: String, |
||||
|
default: '' |
||||
|
}, |
||||
|
iconClass: { |
||||
|
type: String, |
||||
|
default: '' |
||||
|
} |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
visible: false |
||||
|
} |
||||
|
}, |
||||
|
mounted() { |
||||
|
this.visible = true |
||||
|
this.startTimer() |
||||
|
}, |
||||
|
methods: { |
||||
|
startTimer() { |
||||
|
if (this.duration > 0) { |
||||
|
setTimeout(() => { |
||||
|
this.close() |
||||
|
}, this.duration) |
||||
|
} |
||||
|
}, |
||||
|
close() { |
||||
|
this.visible = false |
||||
|
setTimeout(() => { |
||||
|
this.$destroy() |
||||
|
this.$el.parentNode.removeChild(this.$el) |
||||
|
}, 300) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.custom-message { |
||||
|
position: fixed; |
||||
|
z-index: 9999; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
padding: 14px 21px; |
||||
|
transition: all 0.3s; |
||||
|
font-size: 14px; |
||||
|
font-weight: normal; |
||||
|
line-height: normal; |
||||
|
letter-spacing: 0.08em; |
||||
|
color: #626573; |
||||
|
border-radius: 4px; |
||||
|
background: #FFFFFF; |
||||
|
/* 阴影/低阴影 */ |
||||
|
box-shadow: 0px 3px 8px 0px rgba(0, 0, 0, 0.16); |
||||
|
} |
||||
|
|
||||
|
/* 位置样式 */ |
||||
|
.top-center { |
||||
|
top: 20px; |
||||
|
left: 50%; |
||||
|
transform: translateX(-50%); |
||||
|
} |
||||
|
.top-right { |
||||
|
top: 20px; |
||||
|
right: 20px; |
||||
|
} |
||||
|
.top-left { |
||||
|
top: 20px; |
||||
|
left: 20px; |
||||
|
} |
||||
|
.bottom-center { |
||||
|
bottom: 20px; |
||||
|
left: 50%; |
||||
|
transform: translateX(-50%); |
||||
|
} |
||||
|
.bottom-right { |
||||
|
bottom: 20px; |
||||
|
right: 20px; |
||||
|
} |
||||
|
.bottom-left { |
||||
|
bottom: 20px; |
||||
|
left: 20px; |
||||
|
} |
||||
|
|
||||
|
/* 类型样式 */ |
||||
|
/* .success { |
||||
|
background-color: #f6ffed; |
||||
|
border: 1px solid #b7eb8f; |
||||
|
color: #52c41a; |
||||
|
} |
||||
|
.info { |
||||
|
background-color: #e6f7ff; |
||||
|
border: 1px solid #91d5ff; |
||||
|
color: #1890ff; |
||||
|
} |
||||
|
.warning { |
||||
|
background-color: #fffbe6; |
||||
|
border: 1px solid #ffe58f; |
||||
|
color: #faad14; |
||||
|
} |
||||
|
.error { |
||||
|
background-color: #fff2f0; |
||||
|
border: 1px solid #ffccc7; |
||||
|
color: #f5222d; |
||||
|
} */ |
||||
|
|
||||
|
.message-image { |
||||
|
width: 18px; |
||||
|
height: 18px; |
||||
|
margin-right: 10px; |
||||
|
} |
||||
|
|
||||
|
/* 动画效果 */ |
||||
|
.fade-enter-active, .fade-leave-active { |
||||
|
transition: opacity 0.3s, transform 0.3s; |
||||
|
} |
||||
|
.fade-enter, .fade-leave-to { |
||||
|
opacity: 0; |
||||
|
} |
||||
|
.fade-enter.top-center, .fade-leave-to.top-center { |
||||
|
transform: translate(-50%, -20px); |
||||
|
} |
||||
|
.fade-enter.top-right, .fade-leave-to.top-right, |
||||
|
.fade-enter.top-left, .fade-leave-to.top-left { |
||||
|
transform: translateY(-20px); |
||||
|
} |
||||
|
.fade-enter.bottom-center, .fade-leave-to.bottom-center { |
||||
|
transform: translate(-50%, 20px); |
||||
|
} |
||||
|
.fade-enter.bottom-right, .fade-leave-to.bottom-right, |
||||
|
.fade-enter.bottom-left, .fade-leave-to.bottom-left { |
||||
|
transform: translateY(20px); |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,94 @@ |
|||||
|
import Vue from 'vue' |
||||
|
import GuipMessage from './GuipMessage.vue' |
||||
|
|
||||
|
// 默认图标配置
|
||||
|
const defaultIcons = { |
||||
|
success: 'icon-success', // 替换为你的图标类名
|
||||
|
info: 'icon-info', |
||||
|
warning: 'icon-warning', |
||||
|
error: 'icon-error' |
||||
|
} |
||||
|
|
||||
|
// 默认图片配置
|
||||
|
const defaultImages = { |
||||
|
success: require('@/assets/message_Success.png'), |
||||
|
info: require('@/assets/message_Warning.png'), |
||||
|
warning: require('@/assets/message_Warning.png'), |
||||
|
error: require('@/assets/message_error.png') |
||||
|
} |
||||
|
const MessageConstructor = Vue.extend(GuipMessage) |
||||
|
|
||||
|
// let messageInstance = null
|
||||
|
let messageQueue = [] |
||||
|
|
||||
|
function showMessage(options) { |
||||
|
if (typeof options === 'string') { |
||||
|
options = { |
||||
|
message: options |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 合并默认配置
|
||||
|
const config = { |
||||
|
type: 'info', |
||||
|
duration: 3000, |
||||
|
position: 'top-center', |
||||
|
showImage: true, |
||||
|
...options |
||||
|
} |
||||
|
|
||||
|
// 设置图标或图片
|
||||
|
if (config.showImage) { |
||||
|
config.imageUrl = options.imageUrl || defaultImages[config.type] |
||||
|
} else { |
||||
|
config.iconClass = options.iconClass || defaultIcons[config.type] |
||||
|
} |
||||
|
|
||||
|
// 创建实例
|
||||
|
const instance = new MessageConstructor({ |
||||
|
propsData: config |
||||
|
}) |
||||
|
|
||||
|
// 挂载到DOM
|
||||
|
instance.$mount() |
||||
|
document.body.appendChild(instance.$el) |
||||
|
|
||||
|
// 添加到队列
|
||||
|
messageQueue.push(instance) |
||||
|
|
||||
|
// 返回关闭方法
|
||||
|
return { |
||||
|
close: () => instance.close() |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function install(Vue, options = {}) { |
||||
|
// 合并默认配置
|
||||
|
if (options.icons) { |
||||
|
Object.assign(defaultIcons, options.icons) |
||||
|
} |
||||
|
if (options.images) { |
||||
|
Object.assign(defaultImages, options.images) |
||||
|
} |
||||
|
|
||||
|
// 添加全局方法
|
||||
|
Vue.prototype.$Message = showMessage |
||||
|
Vue.prototype.$Message.closeAll = () => { |
||||
|
messageQueue.forEach(instance => instance.close()) |
||||
|
messageQueue = [] |
||||
|
} |
||||
|
|
||||
|
// 添加快捷方法
|
||||
|
const types = ['success', 'info', 'warning', 'error'] |
||||
|
types.forEach(type => { |
||||
|
Vue.prototype.$Message[type] = (message, options = {}) => { |
||||
|
return showMessage({ |
||||
|
message, |
||||
|
type, |
||||
|
...options |
||||
|
}) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export default { install } |
File diff suppressed because it is too large
Loading…
Reference in new issue