Skip to content

Commit a4c98d2

Browse files
committed
fix(form-dialog): correct typo in onOpened event and improve portal setup
1 parent a34cdf1 commit a4c98d2

3 files changed

Lines changed: 134 additions & 140 deletions

File tree

docs/guide/form-dialog.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ type IFormDialogProps = Omit<DialogProps, 'title'> & {
4242
okText?: string | Component | VNode | (() => VNode)
4343
okButtonProps?: ButtonProps
4444
onOpen?: () => void
45-
onOpend?: () => void
45+
onOpened?: () => void
4646
onClose?: () => void
4747
onClosed?: () => void
4848
onCancel?: () => void

packages/components/src/__builtins__/shared/portal.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { defineComponent, onBeforeUnmount } from 'vue'
1+
import { defineComponent, getCurrentInstance, onBeforeUnmount } from 'vue'
22
import { h, Fragment } from '@formily/vue'
33
export interface IPortalProps {
44
id?: string | symbol
@@ -16,22 +16,21 @@ export const createPortalProvider = (id: string | symbol) => {
1616
},
1717
},
1818

19-
setup(props) {
19+
setup(props, { slots }) {
20+
const { appContext } = getCurrentInstance()
21+
22+
if (props.id && !PortalMap.has(props.id)) {
23+
PortalMap.set(props.id, appContext)
24+
}
25+
2026
onBeforeUnmount(() => {
2127
const { id } = props
2228
if (id && PortalMap.has(id)) {
2329
PortalMap.delete(id)
2430
}
2531
})
26-
},
27-
28-
render() {
29-
const { id } = this
30-
if (id && !PortalMap.has(id)) {
31-
PortalMap.set(id, this)
32-
}
3332

34-
return h(Fragment, {}, this.$slots)
33+
return () => h(Fragment, {}, slots)
3534
},
3635
})
3736

packages/components/src/form-dialog/index.ts

Lines changed: 124 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ import {
1919
Component,
2020
VNode,
2121
defineComponent,
22+
nextTick,
2223
Teleport,
23-
createApp,
24+
createVNode,
2425
PropType,
2526
h,
2627
onMounted,
2728
ref,
29+
render as vueRender,
2830
} from 'vue'
2931
import {
3032
isValidElement,
@@ -50,7 +52,7 @@ type IFormDialogProps = Omit<typeof ElDialogProps, 'title'> & {
5052
okButtonProps?: typeof ElButtonProps
5153
beforeClose?: (cb: Function) => void
5254
onOpen?: () => void
53-
onOpend?: () => void
55+
onOpened?: () => void
5456
onClose?: () => void
5557
onClosed?: () => void
5658
onCancel?: () => void
@@ -120,7 +122,6 @@ export function FormDialog(
120122
root: document.createElement('div'),
121123
form: null,
122124
promise: null,
123-
app: null,
124125
instance: null,
125126
openMiddlewares: [],
126127
confirmMiddlewares: [],
@@ -134,8 +135,7 @@ export function FormDialog(
134135
...props,
135136
onClosed: () => {
136137
props.onClosed?.()
137-
env.app?.unmount?.()
138-
env.app = null
138+
vueRender(null, env.root)
139139
env.instance = null
140140
env.root?.parentNode?.removeChild(env.root)
141141
env.root = undefined
@@ -161,135 +161,130 @@ export function FormDialog(
161161
)
162162

163163
const render = (visible = true, resolve?: () => any, reject?: () => any) => {
164-
if (!env.instance) {
165-
const ComponentConstructor = observer(
166-
defineComponent({
167-
props: { dialogProps: Object as PropType<typeof ElDialogProps> },
168-
data() {
169-
return {
170-
visible: false,
171-
}
172-
},
173-
render() {
174-
const {
175-
onClose,
176-
onClosed,
177-
onOpen,
178-
onOpend,
179-
onOK,
180-
onCancel,
181-
title,
182-
footer,
183-
okText,
184-
cancelText,
185-
okButtonProps,
186-
cancelButtonProps,
187-
...dialogProps
188-
} = this.dialogProps
189-
190-
return h(
191-
ElDialog,
164+
if (env.instance) {
165+
env.instance.visible = visible
166+
return
167+
}
168+
169+
const ComponentConstructor = observer(
170+
defineComponent({
171+
props: { dialogProps: Object as PropType<typeof ElDialogProps> },
172+
data() {
173+
return {
174+
visible: false,
175+
}
176+
},
177+
render() {
178+
const {
179+
onClose,
180+
onClosed,
181+
onOpen,
182+
onOpened,
183+
onOK,
184+
onCancel,
185+
title,
186+
footer,
187+
okText,
188+
cancelText,
189+
okButtonProps,
190+
cancelButtonProps,
191+
...dialogProps
192+
} = this.dialogProps
193+
194+
const renderFooter = () => {
195+
const FooterPortalTarget = h(
196+
'span',
192197
{
193-
class: [`${prefixCls}`],
194-
...dialogProps,
195-
modelValue: this.visible,
196-
'onUpdate:modelValue': (val) => {
197-
this.visible = val
198-
},
199-
onClose: () => {
200-
onClose?.()
201-
},
202-
onClosed: () => {
203-
onClosed?.()
204-
},
205-
onOpen: () => {
206-
onOpen?.()
207-
},
208-
onOpened: () => {
209-
onOpend?.()
210-
},
198+
id: PORTAL_TARGET_NAME,
211199
},
212-
{
213-
default: () =>
214-
h(FormProvider, { form: env.form }, () =>
215-
h(component, {}, {})
216-
),
217-
title: () =>
218-
h('div', {}, { default: () => resolveComponent(title) }),
219-
footer: () =>
220-
h(
221-
'div',
222-
{},
223-
{
224-
default: () => {
225-
const FooterPortalTarget = h(
226-
'span',
227-
{
228-
id: PORTAL_TARGET_NAME,
229-
},
230-
{}
231-
)
232-
if (footer === null) {
233-
return [null, FooterPortalTarget]
234-
} else if (footer) {
235-
return [resolveComponent(footer), FooterPortalTarget]
236-
}
237-
238-
return [
239-
h(
240-
ElButton,
241-
{
242-
...cancelButtonProps,
243-
onClick: (e) => {
244-
onCancel?.(e)
245-
reject()
246-
},
247-
},
248-
{
249-
default: () =>
250-
resolveComponent(
251-
cancelText || '取消'
252-
// t('el.popconfirm.cancelButtonText')
253-
),
254-
}
255-
),
256-
h(
257-
ElButton,
258-
{
259-
type: 'primary',
260-
...okButtonProps,
261-
loading: env.form.submitting,
262-
onClick: (e) => {
263-
onOK?.(e)
264-
resolve()
265-
},
266-
},
267-
{
268-
default: () =>
269-
resolveComponent(
270-
okText || '确定'
271-
// t('el.popconfirm.confirmButtonText')
272-
),
273-
}
274-
),
275-
FooterPortalTarget,
276-
]
277-
},
278-
}
279-
),
280-
}
200+
{}
281201
)
282-
},
283-
})
284-
)
285202

286-
env.app = createApp(ComponentConstructor, {
287-
dialogProps,
288-
parent: getPortalContext(id as string | symbol),
203+
if (footer === null) {
204+
return [null, FooterPortalTarget]
205+
}
206+
207+
if (footer) {
208+
return [resolveComponent(footer), FooterPortalTarget]
209+
}
210+
211+
return [
212+
h(
213+
ElButton,
214+
{
215+
...cancelButtonProps,
216+
onClick: () => {
217+
onCancel?.()
218+
reject()
219+
},
220+
},
221+
{
222+
default: () => resolveComponent(cancelText || '取消'),
223+
}
224+
),
225+
h(
226+
ElButton,
227+
{
228+
type: 'primary',
229+
...okButtonProps,
230+
loading: env.form.submitting,
231+
onClick: () => {
232+
onOK?.()
233+
resolve()
234+
},
235+
},
236+
{
237+
default: () => resolveComponent(okText || '确定'),
238+
}
239+
),
240+
FooterPortalTarget,
241+
]
242+
}
243+
244+
return h(
245+
ElDialog,
246+
{
247+
class: [`${prefixCls}`],
248+
...dialogProps,
249+
modelValue: this.visible,
250+
'onUpdate:modelValue': (val) => {
251+
this.visible = val
252+
},
253+
onClose,
254+
onClosed,
255+
onOpen,
256+
onOpened,
257+
},
258+
{
259+
default: () =>
260+
h(FormProvider, { form: env.form }, () => h(component, {}, {})),
261+
header: () =>
262+
h('div', {}, { default: () => resolveComponent(title) }),
263+
footer: () =>
264+
h(
265+
'div',
266+
{},
267+
{
268+
default: renderFooter,
269+
}
270+
),
271+
}
272+
)
273+
},
289274
})
290-
env.instance = env.app.mount(env.root)
291-
}
292-
env.instance.visible = visible
275+
)
276+
277+
const vnode = createVNode(ComponentConstructor, {
278+
dialogProps: dialogProps,
279+
})
280+
281+
vnode.appContext = getPortalContext(id as string | symbol)
282+
vueRender(vnode, env.root)
283+
284+
nextTick(() => {
285+
env.instance = vnode.component.proxy
286+
env.instance.visible = visible
287+
})
293288
}
294289

295290
const formDialog = {

0 commit comments

Comments
 (0)