Files
element-plus/packages/message/src/message.ts
Bruno Santos e900aac6ea Feat/message (#291)
* feat(message): add message component

- [WIP] Messages component
- TODOs: tests, VNode Bug

re #101

* test(message): add tests for message component

* fix(message): fix message z-index

Co-authored-by: Herrington Darkholme <2883231+HerringtonDarkholme@users.noreply.github.com>
2020-10-03 20:55:23 +08:00

112 lines
2.4 KiB
TypeScript

import { createVNode, nextTick, render } from 'vue'
import type {
IMessage,
MessageQueue,
IMessageOptions,
MessageVM,
IMessageHandle,
} from './types'
import MessageConstructor from './index.vue'
import { isVNode } from '@element-plus/utils/util'
import PopupManager from '@element-plus/utils/popup-manager'
import isServer from '@element-plus/utils/isServer'
let vm: MessageVM
const instances: MessageQueue = []
let seed = 1
const Message: IMessage = function (opts = {}): IMessageHandle {
if (isServer) return
if (typeof opts === 'string') {
opts = {
message: opts,
}
}
let options: IMessageOptions = <IMessageOptions>opts
let verticalOffset = opts.offset || 20
instances.forEach(({ vm }) => {
verticalOffset += (vm.el.offsetHeight || 0) + 16
})
verticalOffset += 16
const id = 'message_' + seed++
const userOnClose = options.onClose
options = {
...options,
onClose: () => {
close(id, userOnClose)
},
offset: verticalOffset,
id,
zIndex: PopupManager.nextZIndex(),
}
const container = document.createElement('div')
container.className = `container_${id}`
const message = options.message
vm = createVNode(
MessageConstructor,
options,
isVNode(options.message) ? { default: () => message } : null,
)
render(vm, container)
instances.push({ vm, $el: container })
document.body.appendChild(container)
return {
close: options.onClose,
}
}
export function close(id: string, userOnClose?: (vm: MessageVM) => void): void {
const idx = instances.findIndex(({ vm }) => {
const { id: _id } = vm.component.props
return id === _id
})
if (idx === -1) {
return
}
const { vm, $el } = instances[idx]
if (!vm) return
userOnClose?.(vm)
const removedHeight = vm.el.offsetHeight
render(null, $el)
nextTick(() => {
document.body.removeChild($el)
})
instances.splice(idx, 1)
// adjust other instances vertical offset
const len = instances.length
if (len < 1) return
for (let i = idx; i < len; i++) {
const pos =
parseInt(instances[i].vm.el.style['top'], 10) - removedHeight - 16
instances[i].vm.component.props.offset = pos
instances[i].vm.component.props.vertOffset = pos
}
}
export function closeAll(): void {
for (let i = instances.length - 1; i >= 0; i--) {
const instance = instances[i].vm.component as any
instance.ctx.close()
}
}
Message.closeAll = closeAll
export default Message