mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
fix(components): [loading] inherit app context (#20371)
* fix(components): [loading] inherit app context in ssr mode * chore: get appContext inherit in childApp * docs: add loading inheritance * Update docs/en-US/component/loading.md Co-authored-by: qiang <qw13131wang@gmail.com> --------- Co-authored-by: qiang <qw13131wang@gmail.com>
This commit is contained in:
@@ -79,6 +79,27 @@ Calling the `close` method on any one of them can close this full screen Loading
|
||||
|
||||
If Element Plus is imported entirely, a globally method `$loading` will be registered to `app.config.globalProperties`. You can invoke it like this: `this.$loading(options)`, and it also returns a Loading instance.
|
||||
|
||||
## App context inheritance ^(2.9.10)
|
||||
|
||||
Now loading accepts a `context` as second parameter of the loading constructor which allows you to inject current app's context to loading which allows you to inherit all the properties of the app.
|
||||
|
||||
You can use it like this:
|
||||
|
||||
:::tip
|
||||
|
||||
If you globally registered ElLoading component, it will automatically inherit your app context.
|
||||
|
||||
:::
|
||||
|
||||
```ts
|
||||
import { getCurrentInstance } from 'vue'
|
||||
import { ElLoading } from 'element-plus'
|
||||
|
||||
// in your setup method
|
||||
const { appContext } = getCurrentInstance()!
|
||||
ElLoading.service({}, appContext)
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Options
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { nextTick, ref } from 'vue'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { afterEach, describe, expect, test, vi } from 'vitest'
|
||||
import { Loading } from '../src/service'
|
||||
import { vLoading } from '../src/directive'
|
||||
import Loading from '../src/service'
|
||||
import vLoading from '../src/directive'
|
||||
import ElInput from '../../input'
|
||||
|
||||
import type { VNode } from 'vue'
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
import { Loading } from './src/service'
|
||||
import { vLoading } from './src/directive'
|
||||
import Loading from './src/service'
|
||||
import vLoading from './src/directive'
|
||||
|
||||
import type { App } from 'vue'
|
||||
import type { App, AppContext, Directive } from 'vue'
|
||||
import type { ElementLoading, LoadingBinding } from './src/directive'
|
||||
|
||||
// installer and everything in all
|
||||
export const ElLoading = {
|
||||
install(app: App) {
|
||||
Loading._context = app._context
|
||||
;(
|
||||
vLoading as Directive<ElementLoading, LoadingBinding> & {
|
||||
_context: AppContext | null
|
||||
}
|
||||
)._context = app._context
|
||||
app.directive('loading', vLoading)
|
||||
app.config.globalProperties.$loading = Loading
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// @ts-nocheck
|
||||
import { isRef, ref } from 'vue'
|
||||
import { hyphenate, isObject, isString } from '@element-plus/utils'
|
||||
import { Loading } from './service'
|
||||
import Loading from './service'
|
||||
import type { Directive, DirectiveBinding, UnwrapRef } from 'vue'
|
||||
import type { LoadingOptions } from './types'
|
||||
import type { LoadingInstance } from './loading'
|
||||
@@ -54,9 +54,11 @@ const createInstance = (
|
||||
body: getBindingProp('body') ?? binding.modifiers.body,
|
||||
lock: getBindingProp('lock') ?? binding.modifiers.lock,
|
||||
}
|
||||
const instance = Loading(options)
|
||||
instance._context = vLoading._context
|
||||
el[INSTANCE_KEY] = {
|
||||
options,
|
||||
instance: Loading(options),
|
||||
instance,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +72,7 @@ const updateOptions = (
|
||||
}
|
||||
}
|
||||
|
||||
export const vLoading: Directive<ElementLoading, LoadingBinding> = {
|
||||
const vLoading: Directive<ElementLoading, LoadingBinding> = {
|
||||
mounted(el, binding) {
|
||||
if (binding.value) {
|
||||
createInstance(el, binding)
|
||||
@@ -94,3 +96,6 @@ export const vLoading: Directive<ElementLoading, LoadingBinding> = {
|
||||
el[INSTANCE_KEY] = null
|
||||
},
|
||||
}
|
||||
|
||||
vLoading._context = null
|
||||
export default vLoading
|
||||
|
||||
@@ -14,10 +14,14 @@ import {
|
||||
import { removeClass } from '@element-plus/utils'
|
||||
import { useGlobalComponentSettings } from '@element-plus/components/config-provider'
|
||||
|
||||
import type { AppContext } from 'vue'
|
||||
import type { UseNamespaceReturn } from '@element-plus/hooks'
|
||||
import type { LoadingOptionsResolved } from './types'
|
||||
|
||||
export function createLoadingComponent(options: LoadingOptionsResolved) {
|
||||
export function createLoadingComponent(
|
||||
options: LoadingOptionsResolved,
|
||||
appContext: AppContext | null
|
||||
) {
|
||||
let afterLeaveTimer: ReturnType<typeof setTimeout>
|
||||
// IMPORTANT NOTE: this is only a hacking way to expose the injections on an
|
||||
// instance, DO NOT FOLLOW this pattern in your own code.
|
||||
@@ -149,6 +153,7 @@ export function createLoadingComponent(options: LoadingOptionsResolved) {
|
||||
})
|
||||
|
||||
const loadingInstance = createApp(elLoadingComponent)
|
||||
Object.assign(loadingInstance._context, appContext ?? {})
|
||||
const vm = loadingInstance.mount(document.createElement('div'))
|
||||
|
||||
return {
|
||||
|
||||
@@ -13,13 +13,11 @@ import type { UseNamespaceReturn, UseZIndexReturn } from '@element-plus/hooks'
|
||||
import type { LoadingInstance } from './loading'
|
||||
import type { LoadingOptionsResolved } from '..'
|
||||
import type { LoadingOptions } from './types'
|
||||
import type { CSSProperties } from 'vue'
|
||||
import type { AppContext, CSSProperties } from 'vue'
|
||||
|
||||
let fullscreenInstance: LoadingInstance | undefined = undefined
|
||||
|
||||
export const Loading = function (
|
||||
options: LoadingOptions = {}
|
||||
): LoadingInstance {
|
||||
const Loading = function (options: LoadingOptions = {}): LoadingInstance {
|
||||
if (!isClient) return undefined as any
|
||||
|
||||
const resolved = resolveOptions(options)
|
||||
@@ -28,13 +26,16 @@ export const Loading = function (
|
||||
return fullscreenInstance
|
||||
}
|
||||
|
||||
const instance = createLoadingComponent({
|
||||
...resolved,
|
||||
closed: () => {
|
||||
resolved.closed?.()
|
||||
if (resolved.fullscreen) fullscreenInstance = undefined
|
||||
const instance = createLoadingComponent(
|
||||
{
|
||||
...resolved,
|
||||
closed: () => {
|
||||
resolved.closed?.()
|
||||
if (resolved.fullscreen) fullscreenInstance = undefined
|
||||
},
|
||||
},
|
||||
})
|
||||
Loading._context
|
||||
)
|
||||
|
||||
addStyle(resolved, resolved.parent, instance)
|
||||
addClassList(resolved, resolved.parent, instance)
|
||||
@@ -163,3 +164,6 @@ const addClassList = (
|
||||
removeClass(parent, ns.bm('parent', 'hidden'))
|
||||
}
|
||||
}
|
||||
|
||||
Loading._context = null as AppContext | null
|
||||
export default Loading
|
||||
|
||||
Reference in New Issue
Block a user