mirror of
https://gitee.com/element-plus/element-plus.git
synced 2024-12-04 20:27:44 +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 |
|
| draggable | whether MessageBox is draggable | boolean | — | false |
|
||||||
| round-button | whether to use round button | 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 |
|
| 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
|
// @ts-nocheck
|
||||||
import { markRaw } from 'vue'
|
import { markRaw } from 'vue'
|
||||||
import { mount } from '@vue/test-utils'
|
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 { rAF } from '@element-plus/test-utils/tick'
|
||||||
import { triggerNativeCompositeClick } from '@element-plus/test-utils/composite-click'
|
import { triggerNativeCompositeClick } from '@element-plus/test-utils/composite-click'
|
||||||
import { QuestionFilled as QuestionFilledIcon } from '@element-plus/icons-vue'
|
import { QuestionFilled as QuestionFilledIcon } from '@element-plus/icons-vue'
|
||||||
@ -11,6 +11,10 @@ import { ElMessageBox } from '..'
|
|||||||
const selector = '.el-overlay'
|
const selector = '.el-overlay'
|
||||||
const QuestionFilled = markRaw(QuestionFilledIcon)
|
const QuestionFilled = markRaw(QuestionFilledIcon)
|
||||||
|
|
||||||
|
vi.mock('@element-plus/utils/error', () => ({
|
||||||
|
debugWarn: vi.fn(),
|
||||||
|
}))
|
||||||
|
|
||||||
const _mount = (invoker: () => void) => {
|
const _mount = (invoker: () => void) => {
|
||||||
return mount(
|
return mount(
|
||||||
{
|
{
|
||||||
@ -28,6 +32,7 @@ const _mount = (invoker: () => void) => {
|
|||||||
describe('MessageBox', () => {
|
describe('MessageBox', () => {
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
MessageBox.close()
|
MessageBox.close()
|
||||||
|
document.body.innerHTML = ''
|
||||||
await rAF()
|
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', () => {
|
describe('accessibility', () => {
|
||||||
test('title attribute should set aria-label', async () => {
|
test('title attribute should set aria-label', async () => {
|
||||||
const title = 'Hello World'
|
const title = 'Hello World'
|
||||||
|
@ -170,6 +170,9 @@ export interface ElMessageBoxOptions {
|
|||||||
|
|
||||||
/** Custom size of confirm and cancel buttons */
|
/** Custom size of confirm and cancel buttons */
|
||||||
buttonSize?: ComponentSize
|
buttonSize?: ComponentSize
|
||||||
|
|
||||||
|
/** Custom element to append the message box to */
|
||||||
|
appendTo?: HTMLElement | string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ElMessageBoxShortcutMethod = ((
|
export type ElMessageBoxShortcutMethod = ((
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import { createVNode, render } from 'vue'
|
import { createVNode, render } from 'vue'
|
||||||
import { isClient } from '@vueuse/core'
|
import { isClient } from '@vueuse/core'
|
||||||
import {
|
import {
|
||||||
|
debugWarn,
|
||||||
hasOwn,
|
hasOwn,
|
||||||
|
isElement,
|
||||||
isFunction,
|
isFunction,
|
||||||
isObject,
|
isObject,
|
||||||
isString,
|
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 = (
|
const initInstance = (
|
||||||
props: any,
|
props: any,
|
||||||
container: HTMLElement,
|
container: HTMLElement,
|
||||||
@ -51,7 +75,7 @@ const initInstance = (
|
|||||||
)
|
)
|
||||||
vnode.appContext = appContext
|
vnode.appContext = appContext
|
||||||
render(vnode, container)
|
render(vnode, container)
|
||||||
document.body.appendChild(container.firstElementChild!)
|
getAppendToElement(props).appendChild(container.firstElementChild!)
|
||||||
return vnode.component
|
return vnode.component
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user