174 lines
4.1 KiB
TypeScript
174 lines
4.1 KiB
TypeScript
import { createApp, h } from 'vue'
|
||
import Loading from './Loading.vue'
|
||
|
||
// 加载组件配置接口
|
||
export interface LoadingOptions {
|
||
// 加载动画类型
|
||
type?: 'spinner' | 'dots' | 'pulse' | 'ring'
|
||
// 加载动画大小
|
||
size?: number | string
|
||
// 加载动画颜色
|
||
color?: string
|
||
// 是否全屏显示
|
||
fullscreen?: boolean
|
||
// 加载文本
|
||
text?: string
|
||
// 遮罩层背景色
|
||
background?: string
|
||
// 遮罩层透明度
|
||
opacity?: number
|
||
// 线条宽度(仅适用于spinner和ring类型)
|
||
strokeWidth?: number
|
||
// 线条末端样式(仅适用于spinner类型)
|
||
strokeLinecap?: 'round' | 'butt' | 'square'
|
||
}
|
||
|
||
// Loading 实例接口
|
||
interface LoadingInstance {
|
||
show: () => void
|
||
hide: () => void
|
||
close: () => void
|
||
}
|
||
|
||
// 当前活动的Loading实例
|
||
let activeInstance: LoadingInstance | null = null
|
||
|
||
/**
|
||
* 创建并显示一个加载组件
|
||
* @param options 加载组件配置选项
|
||
* @returns 加载组件实例,可用于手动控制显示和隐藏
|
||
*/
|
||
export function showLoading(options: LoadingOptions = {}): LoadingInstance {
|
||
// 如果已经有一个活动的全屏Loading实例,先隐藏它
|
||
if (activeInstance && options.fullscreen !== false) {
|
||
activeInstance.hide()
|
||
}
|
||
|
||
// 默认配置
|
||
const defaultOptions: LoadingOptions = {
|
||
type: 'spinner',
|
||
size: 40,
|
||
color: '#1890ff',
|
||
fullscreen: true,
|
||
text: '',
|
||
background: 'rgba(0, 0, 0, 0.3)',
|
||
opacity: 1,
|
||
strokeWidth: 3,
|
||
strokeLinecap: 'round'
|
||
}
|
||
|
||
// 合并配置
|
||
const mergedOptions = { ...defaultOptions, ...options }
|
||
|
||
// 创建一个容器元素
|
||
const container = document.createElement('div')
|
||
|
||
// 加载组件状态
|
||
let visible = true
|
||
|
||
// 创建应用实例
|
||
const app = createApp({
|
||
render() {
|
||
return h(Loading, {
|
||
visible,
|
||
type: mergedOptions.type,
|
||
size: mergedOptions.size,
|
||
color: mergedOptions.color,
|
||
fullscreen: mergedOptions.fullscreen,
|
||
text: mergedOptions.text,
|
||
background: mergedOptions.background,
|
||
opacity: mergedOptions.opacity,
|
||
strokeWidth: mergedOptions.strokeWidth,
|
||
strokeLinecap: mergedOptions.strokeLinecap
|
||
})
|
||
}
|
||
})
|
||
|
||
// 隐藏加载组件
|
||
function hideLoading() {
|
||
visible = false
|
||
// 卸载组件
|
||
setTimeout(() => {
|
||
app.unmount()
|
||
if (container.parentNode) {
|
||
container.parentNode.removeChild(container)
|
||
}
|
||
// 如果当前实例是活动实例,清除活动实例引用
|
||
if (activeInstance === instance) {
|
||
activeInstance = null
|
||
}
|
||
}, 300)
|
||
}
|
||
|
||
// 显示加载组件(默认为显示状态)
|
||
function showLoadingComp() {
|
||
visible = true
|
||
}
|
||
|
||
// 挂载组件
|
||
app.mount(container)
|
||
document.body.appendChild(container)
|
||
|
||
// 创建实例对象
|
||
const instance: LoadingInstance = {
|
||
show: showLoadingComp,
|
||
hide: hideLoading,
|
||
close: hideLoading
|
||
}
|
||
|
||
// 如果是全屏Loading,保存为活动实例
|
||
if (mergedOptions.fullscreen) {
|
||
activeInstance = instance
|
||
}
|
||
|
||
// 返回控制方法
|
||
return instance
|
||
}
|
||
|
||
/**
|
||
* 隐藏当前活动的全屏加载组件
|
||
*/
|
||
export function hideLoading() {
|
||
if (activeInstance) {
|
||
activeInstance.hide()
|
||
activeInstance = null
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 显示一个带有文本的全屏加载组件
|
||
* @param text 加载文本
|
||
* @param color 加载动画颜色
|
||
* @returns 加载组件实例
|
||
*/
|
||
export function showLoadingWithText(text: string, color: string = '#1890ff'): LoadingInstance {
|
||
return showLoading({
|
||
text,
|
||
color,
|
||
fullscreen: true
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 显示一个小型内联加载组件
|
||
* @param size 加载组件大小
|
||
* @param color 加载动画颜色
|
||
* @param type 加载动画类型
|
||
* @returns 加载组件实例
|
||
*/
|
||
export function showInlineLoading(size: number = 24, color: string = '#1890ff', type: 'spinner' | 'dots' | 'pulse' | 'ring' = 'spinner'): LoadingInstance {
|
||
return showLoading({
|
||
size,
|
||
color,
|
||
type,
|
||
fullscreen: false
|
||
})
|
||
}
|
||
|
||
// 默认导出
|
||
export default {
|
||
show: showLoading,
|
||
hide: hideLoading,
|
||
showWithText: showLoadingWithText,
|
||
showInline: showInlineLoading
|
||
} |