mirror of
https://gitee.com/element-plus/element-plus.git
synced 2024-12-03 11:47:48 +08:00
feat(components): [message-box] add append-to option (#10071)
This commit is contained in:
parent
01ce124940
commit
04820a4dcf
@ -191,3 +191,4 @@ The corresponding methods are: `ElMessageBox`, `ElMessageBox.alert`, `ElMessageB
|
||||
| draggable | whether MessageBox is draggable | boolean | — | false |
|
||||
| round-button | whether to use round button | boolean | — | false |
|
||||
| button-size | custom size of confirm and cancel buttons | string | small / default / large | default |
|
||||
| append-to | set the root element for the message box | string \| HTMLElement | — | — |
|
||||
|
@ -1,7 +1,7 @@
|
||||
// @ts-nocheck
|
||||
import { markRaw } from 'vue'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { afterEach, describe, expect, it, test } from 'vitest'
|
||||
import { afterEach, describe, expect, it, test, vi } from 'vitest'
|
||||
import { rAF } from '@element-plus/test-utils/tick'
|
||||
import { triggerNativeCompositeClick } from '@element-plus/test-utils/composite-click'
|
||||
import { QuestionFilled as QuestionFilledIcon } from '@element-plus/icons-vue'
|
||||
@ -11,6 +11,10 @@ import { ElMessageBox } from '..'
|
||||
const selector = '.el-overlay'
|
||||
const QuestionFilled = markRaw(QuestionFilledIcon)
|
||||
|
||||
vi.mock('@element-plus/utils/error', () => ({
|
||||
debugWarn: vi.fn(),
|
||||
}))
|
||||
|
||||
const _mount = (invoker: () => void) => {
|
||||
return mount(
|
||||
{
|
||||
@ -28,6 +32,7 @@ const _mount = (invoker: () => void) => {
|
||||
describe('MessageBox', () => {
|
||||
afterEach(async () => {
|
||||
MessageBox.close()
|
||||
document.body.innerHTML = ''
|
||||
await rAF()
|
||||
})
|
||||
|
||||
@ -275,6 +280,52 @@ describe('MessageBox', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('append to', () => {
|
||||
it('should append to body if parameter is not provided', () => {
|
||||
MessageBox({
|
||||
title: 'append to test',
|
||||
message: 'append to test',
|
||||
})
|
||||
const msgbox: HTMLElement = document.querySelector(`body > ${selector}`)
|
||||
expect(msgbox).toBeDefined()
|
||||
})
|
||||
|
||||
it('should append to body if element does not exist', () => {
|
||||
MessageBox({
|
||||
title: 'append to test',
|
||||
message: 'append to test',
|
||||
appendTo: '.not-existing-selector',
|
||||
})
|
||||
const msgbox: HTMLElement = document.querySelector(`body > ${selector}`)
|
||||
expect(msgbox).toBeDefined()
|
||||
})
|
||||
|
||||
it('should append to HtmlElement provided', () => {
|
||||
const htmlElement = document.createElement('div')
|
||||
document.body.appendChild(htmlElement)
|
||||
MessageBox({
|
||||
title: 'append to test',
|
||||
message: 'append to test',
|
||||
appendTo: htmlElement,
|
||||
})
|
||||
const msgbox: HTMLElement = htmlElement.querySelector(selector)
|
||||
expect(msgbox).toBeDefined()
|
||||
})
|
||||
|
||||
it('should append to selector provided', () => {
|
||||
const htmlElement = document.createElement('div')
|
||||
htmlElement.className = 'custom-html-element'
|
||||
document.body.appendChild(htmlElement)
|
||||
MessageBox({
|
||||
title: 'append to test',
|
||||
message: 'append to test',
|
||||
appendTo: '.custom-html-element',
|
||||
})
|
||||
const msgbox: HTMLElement = htmlElement.querySelector(selector)
|
||||
expect(msgbox).toBeDefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('accessibility', () => {
|
||||
test('title attribute should set aria-label', async () => {
|
||||
const title = 'Hello World'
|
||||
|
@ -170,6 +170,9 @@ export interface ElMessageBoxOptions {
|
||||
|
||||
/** Custom size of confirm and cancel buttons */
|
||||
buttonSize?: ComponentSize
|
||||
|
||||
/** Custom element to append the message box to */
|
||||
appendTo?: HTMLElement | string
|
||||
}
|
||||
|
||||
export type ElMessageBoxShortcutMethod = ((
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { createVNode, render } from 'vue'
|
||||
import { isClient } from '@vueuse/core'
|
||||
import {
|
||||
debugWarn,
|
||||
hasOwn,
|
||||
isElement,
|
||||
isFunction,
|
||||
isObject,
|
||||
isString,
|
||||
@ -33,6 +35,28 @@ const messageInstance = new Map<
|
||||
}
|
||||
>()
|
||||
|
||||
const getAppendToElement = (props: any): HTMLElement => {
|
||||
let appendTo: HTMLElement | null = document.body
|
||||
if (props.appendTo) {
|
||||
if (isString(props.appendTo)) {
|
||||
appendTo = document.querySelector<HTMLElement>(props.appendTo)
|
||||
}
|
||||
if (isElement(props.appendTo)) {
|
||||
appendTo = props.appendTo
|
||||
}
|
||||
|
||||
// should fallback to default value with a warning
|
||||
if (!isElement(appendTo)) {
|
||||
debugWarn(
|
||||
'ElMessageBox',
|
||||
'the appendTo option is not an HTMLElement. Falling back to document.body.'
|
||||
)
|
||||
appendTo = document.body
|
||||
}
|
||||
}
|
||||
return appendTo
|
||||
}
|
||||
|
||||
const initInstance = (
|
||||
props: any,
|
||||
container: HTMLElement,
|
||||
@ -51,7 +75,7 @@ const initInstance = (
|
||||
)
|
||||
vnode.appContext = appContext
|
||||
render(vnode, container)
|
||||
document.body.appendChild(container.firstElementChild!)
|
||||
getAppendToElement(props).appendChild(container.firstElementChild!)
|
||||
return vnode.component
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user