UNPKG

ivue-material-plus

Version:

A high quality UI components Library with Vue.js

130 lines (115 loc) • 3.51 kB
import { isRef, ref } from 'vue'; import { hyphenate, isObject, isString } from '@vue/shared'; import Loading from './loading'; // ts import { LoadingInstance } from './createLoadingComponent'; import { LoadingOptions } from './types/loading'; import type { Directive, DirectiveBinding, UnwrapRef } from 'vue'; const INSTANCE_KEY = Symbol('IvueLoading'); export type LoadingBinding = boolean | UnwrapRef<LoadingOptions>; export interface ElementLoading extends HTMLElement { INSTANCE_KEY: { instance: LoadingInstance; options: LoadingOptions; }; } const createInstance = ( el: ElementLoading, binding: DirectiveBinding<LoadingBinding> ) => { // 当前实例 const vm = binding.instance; // 获取绑定的props const getBindingProp = <K extends keyof LoadingOptions>( key: K ): LoadingOptions[K] => isObject(binding.value) ? binding.value[key] : undefined; const resolveExpression = (key: any) => { const data = (isString(key) && vm?.[key]) || key; if (data) return ref(data); else return data; }; // 获取prop const getProp = <K extends keyof LoadingOptions>(name: K) => resolveExpression( getBindingProp(name) || el.getAttribute(`ivue-loading-${hyphenate(name)}`) ); // 开启全屏 const fullscreen = getBindingProp('fullscreen') ?? binding.modifiers.fullscreen; // 设置参数 const options: LoadingOptions = { // 显示在加载图标下方的加载文案 text: getProp('text'), // 自定义加载图标类名 iconClass: getProp('iconClass'), // 图标 slot iconText: getProp('iconText'), // 遮罩背景色 background: getProp('background'), // Loading 的自定义类名 customClass: getProp('customClass'), // 开启全屏 fullscreen, // 需要覆盖的 DOM 节点 target: getBindingProp('target') ?? (fullscreen ? undefined : el), // 使遮罩插入至 DOM 中的 body 上 body: getBindingProp('body') ?? binding.modifiers.body, // 锁定屏幕的滚动 lock: getBindingProp('lock') ?? binding.modifiers.lock, }; // 重置实例 el[INSTANCE_KEY] = { options, instance: Loading(options), }; }; // 更新选项 const updateOptions = ( // 新的选项 newOptions: UnwrapRef<LoadingOptions>, // 原始选项 originalOptions: LoadingOptions ) => { for (const key of Object.keys(originalOptions)) { // 替换选项是否是 isRef if (isRef(originalOptions[key])) { originalOptions[key].value = newOptions[key]; } } }; const vLoading: Directive<ElementLoading, LoadingBinding> = { // mounted mounted(el, binding) { if (binding.value) { createInstance(el, binding); } }, // 更新 updated(el, binding) { const instance = el[INSTANCE_KEY]; // 是否需要更新 if (binding.oldValue !== binding.value) { // 初始化实例 if (binding.value && !binding.oldValue) { createInstance(el, binding); } // 更新选项 else if (binding.value && binding.oldValue) { if (isObject(binding.value)) { updateOptions(binding.value, instance.options); } } // 清除是实例 else { instance?.instance.close(); } } }, // 销毁 unmounted(el) { // 关闭实例 el[INSTANCE_KEY]?.instance.close(); }, }; export default vLoading;