模仿quasar,给message添加了group

master
toesbieya 6 years ago
parent 8c8a7b4aca
commit 5408210238
  1. 33
      vue/src/assets/styles/element-ui.scss
  2. 102
      vue/src/components/Message/index.js
  3. 94
      vue/src/components/Message/main.vue
  4. 6
      vue/src/main.js
  5. 3
      vue/src/utils/message.js
  6. 1
      vue/vue.config.js

@ -68,6 +68,21 @@
.el-message {
@include deep-shadow;
border-width: 0;
overflow: visible;
&__badge {
animation: el-message-badge .42s;
padding: 4px 8px;
position: absolute;
box-shadow: 0 1px 3px rgba(#000, .2), 0 1px 1px rgba(#000, .14), 0 2px 1px -1px rgba(#000, .12);
background-color: $--color-danger;
color: #fff;
border-radius: 4px;
top: -10px;
left: -10px;
font-size: 12px;
line-height: 12px;
}
.el-message__icon, .el-message__content {
color: #fff !important;
@ -189,6 +204,24 @@
width: 100% !important;
}
@keyframes el-message-badge {
15% {
transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg)
}
30% {
transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg)
}
45% {
transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg)
}
60% {
transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg)
}
75% {
transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg)
}
}

@ -0,0 +1,102 @@
import Vue from 'vue'
import Main from './main.vue'
import {PopupManager} from 'element-ui/src/utils/popup'
import {isVNode} from 'element-ui/src/utils/vdom'
import {isEmpty} from "@/utils"
let MessageConstructor = Vue.extend(Main)
let instance
let instances = []
let seed = 1
//键:options.type+'|'+options.message,值:message实例
let groups = {}
const Message = function (options) {
options = options || {}
if (typeof options === 'string') {
options = {message: options}
}
if (isEmpty(options.type)) {
options.type = 'info'
}
const group = options.type + '|' + options.message
const originalMessage = groups[group]
//若不是新的message
if (originalMessage) {
//旧实例的badge+1,并重新计时(如果有的话)
originalMessage.badge++
originalMessage.clearTimer()
originalMessage.startTimer()
return originalMessage
}
let userOnClose = options.onClose
let id = 'message_' + seed++
options.onClose = function () {
Message.close(id, userOnClose)
}
instance = new MessageConstructor({data: options})
instance.id = id
instance.group = group
if (isVNode(instance.message)) {
instance.$slots.default = [instance.message]
instance.message = null
}
instance.$mount()
document.body.appendChild(instance.$el)
let verticalOffset = options.offset || 20
instances.forEach(item => {
verticalOffset += item.$el.offsetHeight + 16
})
instance.verticalOffset = verticalOffset
instance.visible = true
instance.$el.style.zIndex = PopupManager.nextZIndex()
instances.push(instance)
groups[group] = instance
return instance
};
['success', 'warning', 'info', 'error'].forEach(type => {
Message[type] = options => {
if (typeof options === 'string') {
options = {message: options}
}
options.type = type
return Message(options)
}
})
Message.close = function (id, userOnClose) {
let len = instances.length
let index = -1
let removedHeight
for (let i = 0; i < len; i++) {
if (id === instances[i].id) {
removedHeight = instances[i].$el.offsetHeight
index = i
if (typeof userOnClose === 'function') {
userOnClose(instances[i])
}
delete groups[instances[i].group]
instances.splice(i, 1)
break
}
}
if (len <= 1 || index === -1 || index > instances.length - 1) return
for (let i = index; i < len - 1; i++) {
let dom = instances[i].$el
dom.style.top =
parseInt(dom.style.top, 10) - removedHeight - 16 + 'px'
}
}
Message.closeAll = function () {
for (let i = instances.length - 1; i >= 0; i--) {
instances[i].close()
}
}
export default Message

@ -0,0 +1,94 @@
<template>
<transition name="el-message-fade" @after-leave="handleAfterLeave">
<div v-show="visible"
:class="messageClass"
:style="positionStyle"
role="alert"
@mouseenter="clearTimer"
@mouseleave="startTimer"
>
<div v-if="badge>1" :key="badge" class="el-message__badge">{{badge}}</div>
<i v-if="iconClass" :class="iconClass"/>
<i v-else :class="typeClass"/>
<slot>
<p v-if="!dangerouslyUseHTMLString" class="el-message__content">{{ message }}</p>
<p v-else v-html="message" class="el-message__content"/>
</slot>
<i v-if="showClose" class="el-message__closeBtn el-icon-close" @click="close"/>
</div>
</transition>
</template>
<script>
export default {
data() {
return {
visible: false,
badge: 1,
message: '',
duration: 3000,
type: '',
iconClass: '',
customClass: '',
onClose: null,
showClose: false,
closed: false,
verticalOffset: 20,
timer: null,
dangerouslyUseHTMLString: false,
center: false
}
},
computed: {
messageClass() {
return [
'el-message',
this.type && !this.iconClass ? `el-message--${this.type}` : '',
this.center ? 'is-center' : '',
this.showClose ? 'is-closable' : '',
this.customClass
]
},
typeClass() {
return this.type && !this.iconClass
? `el-message__icon el-icon-${this.type}`
: ''
},
positionStyle() {
return {
'top': `${this.verticalOffset}px`
}
}
},
watch: {
closed(newVal) {
if (newVal) {
this.visible = false
}
}
},
methods: {
handleAfterLeave() {
this.$destroy(true)
this.$el.parentNode.removeChild(this.$el)
},
close() {
this.closed = true
typeof this.onClose === 'function' && this.onClose(this)
},
clearTimer() {
clearTimeout(this.timer)
},
startTimer() {
if (this.duration > 0) {
this.timer = setTimeout(() => {
!this.closed && this.close()
}, this.duration)
}
}
},
mounted() {
this.startTimer()
}
}
</script>

@ -12,6 +12,9 @@ import * as filters from './filter'
import BottomTip from '@/components/BottomTip'
import Guide from '@/components/Guide'
import ImageViewer from '@/components/ImageViewer'
import Message from '@/components/Message'
Vue.use(Element)
//注册过滤器
Object.keys(filters).forEach(key => {
@ -25,8 +28,7 @@ store.dispatch('socket/init', store.state.user).then()
Vue.prototype.$bottomTip = BottomTip
Vue.prototype.$guide = Guide
Vue.prototype.$image = ImageViewer
Vue.use(Element)
Vue.prototype.$message = Message
Vue.config.productionTip = false

@ -1,4 +1,5 @@
import {Message, MessageBox} from 'element-ui'
import Message from '@/components/Message'
import {MessageBox} from 'element-ui'
import {isEmpty} from "@/utils"
export function elError(msg = '操作失败') {

@ -15,6 +15,7 @@ module.exports = {
publicPath: './',
outputDir: 'dist',
assetsDir: 'static',
runtimeCompiler: true,
lintOnSave: false,
productionSourceMap: false,
parallel: true,

Loading…
Cancel
Save