UNPKG

ivue-material-plus

Version:

A high quality UI components Library with Vue.js

461 lines (416 loc) • 10.7 kB
import { createApp, h, getCurrentInstance, ComponentInternalInstance, } from 'vue'; import Modal from './index.vue'; import { isClient } from '../../utils/helpers'; import IvueIcon from '../ivue-icon'; import IvueButton from '../ivue-button'; import IvueSpin from '../ivue-spin'; // type import type { Props } from './types/modal'; const prefixCls = 'ivue-modal-instance'; Modal.newInstance = (properties) => { if (!isClient) { return; } const _props = properties || {}; const container = document.createElement('div'); document.body.appendChild(container); // 当前实例 let _instance: ComponentInternalInstance | null = null; const Instance = createApp({ data() { return Object.assign({}, _props, { /** * 显示/隐藏 * * @type {Boolean} */ visible: false, /** * 对话框宽度,对话框的宽度是响应式的, * 当屏幕尺寸小于 768px 时,宽度会变为自动auto。 * 当其值不大于 100 时以百分比显示,大于 100 时为像素 * * @type {Number | String} */ width: 416, /** * 标题 * * @type {String} */ title: '', /** * 内容 * * @type {String} */ content: '', /** * 图标类型 * * @type {String} */ iconType: '', /** * 图标名称 * * @type {String} */ iconName: '', /** * 确定按钮文字 * * @type {String} */ confirmText: '确认', /** * 关闭文案 * * @type {String} */ cancelText: '取消', /** * 显示取消按钮 * * @type {Boolean} */ showCancel: false, /** * 点击确定按钮时,确定按钮是否显示 loading 状态, * 开启则需手动设置value来关闭对话框 * * @type {Boolean} */ loading: false, /** * loading类型 * * @type {String} */ loadingType: 'spin', /** * 页面是否可以滚动 * * @type {Boolean} */ scrollable: false, /** * 是否显示关闭按钮 * * @type {Boolean} */ closable: false, /** * 关闭有动画,期间使用此属性避免重复点击 * * @type {Boolean} */ closing: false, /** * 按钮loading * * @type {Boolean} */ buttonLoading: false, /** * 使用spain * * @type {Boolean} */ spinLoading: false, }); }, created() { _instance = getCurrentInstance(); }, methods: { // 点击取消的回调 handleCancel() { // 关闭有动画,期间使用此属性避免重复点击 if (this.closing) { return; } // 关闭弹窗 this.$refs.modal.data.visible = false; // 取消loading this.setLoading(false); // 点击取消的回调 this.onCancel(); // 删除实例 this.remove(); }, // 点击确认 handleConfirm() { // 关闭有动画,期间使用此属性避免重复点击 if (this.closing) { return; } // 确定按钮是否显示 loading 状态 if (this.loading) { this.setLoading(true); } // 点击隐藏 else { this.$refs.modal.data.visible = false; // 销毁实例 this.remove(); } // 点击确定的回调 this.onConfirm(); }, // 设置loading setLoading(value: string) { // spin if (this.loadingType === 'spin') { this.spinLoading = value; } // button if (this.loadingType === 'button') { this.buttonLoading = value; } }, // 销毁实例 remove() { this.closing = true; setTimeout(() => { this.closing = false; this.destroy(); }, 300); }, // 销毁实例 destroy() { Instance.unmount(); container && document.body.removeChild(container); this.onRemove(); }, // 点击确认 onConfirm() {}, // 点击取消的回调 onCancel() {}, // 删除实例 onRemove() {}, }, render() { // 渲染头部 let headRender; // 标题 if (this.title) { headRender = h( 'div', { class: `${prefixCls}--head`, }, [ h( IvueIcon, { class: [ `${prefixCls}--head__icon`, `${prefixCls}--head__${this.iconType}`, ], }, { default: () => this.iconName, } ), h('div', { class: `${prefixCls}--head__title`, innerHTML: this.title, }), ] ); } // 渲染body let bodyRender; // 有渲染函数 if (this.render) { bodyRender = h( 'div', { class: `${prefixCls}--body ${prefixCls}--body__render`, }, [this.render(h)] ); } // 普通渲染 else { bodyRender = h( 'div', { class: `${prefixCls}--body`, }, [ h('div', { innerHTML: this.content, }), ] ); } // 渲染底部 const footerRender = []; // 取消按钮 if (this.showCancel) { footerRender.push( h( IvueButton, { class: 'ivue-modal-footer--button', outline: true, color: '#dcdfe6', onClick: this.handleCancel, }, () => this.cancelText ) ); } // 确认按钮 footerRender.push( h( IvueButton, { class: 'ivue-modal-footer--button', status: 'primary', depressed: true, loading: this.buttonLoading, onClick: this.handleConfirm, }, () => this.confirmText ) ); return h( Modal, { ..._props, // 对话框宽度 width: this.width, // 页面是否可以滚动 scrollable: this.scrollable, // 是否显示关闭按钮 closable: this.closable, // modelValue modelValue: this.visible, // 更新modelValue 'onUpdate:modelValue': (status: boolean) => { this.visible = status; }, // 点击取消的回调 'onOn-cancel': this.handleCancel, // ref ref: 'modal', }, () => h( 'div', { class: prefixCls, }, [ headRender, bodyRender, h( 'div', { class: `${prefixCls}--footer`, }, footerRender ), this.loadingType === 'spin' && h(IvueSpin, { class: 'ivue-modal-spin', fix: true, show: this.spinLoading, }), ] ) ); }, }); Instance.mount(container); const modal: any = _instance.refs.modal; return { show(props: Props) { // 显示取消按钮 modal.$parent.showCancel = props.showCancel; // 图标类型 modal.$parent.iconType = props.icon; switch (props.icon) { case 'info': modal.$parent.iconName = 'info'; break; case 'success': modal.$parent.iconName = 'check_circle'; break; case 'warning': modal.$parent.iconName = 'warning'; break; case 'error': modal.$parent.iconName = 'error'; break; case 'confirm': modal.$parent.iconName = 'help'; break; } // loading类型 if ('loadingType' in props) { modal.$parent.loadingType = props.loadingType; } // 对话框宽度 if ('width' in props) { modal.$parent.width = props.width; } // 是否显示关闭按钮 if ('closable' in props) { modal.$parent.closable = props.closable; } // 标题 if ('title' in props) { modal.$parent.title = props.title; } // 内容 if ('content' in props) { modal.$parent.content = props.content; } // 确定按钮文字 if ('confirmText' in props) { modal.$parent.confirmText = props.confirmText; } // 关闭文案 if ('cancelText' in props) { modal.$parent.cancelText = props.cancelText; } // 点击取消的回调 if ('onCancel' in props) { modal.$parent.onCancel = props.onCancel; } // 点击确认 if ('onConfirm' in props) { modal.$parent.onConfirm = props.onConfirm; } // 异步加载 触发 确认 if ('loading' in props) { modal.$parent.loading = props.loading; } // 页面是否可以滚动 if ('scrollable' in props) { modal.$parent.scrollable = props.scrollable; } // 当组件销毁时通知 modal.$parent.onRemove = props.onRemove; // 显示 modal.data.visible = true; }, remove() { modal.data.visible = false; // 取消loading modal.$parent.setLoading(); modal.$parent.remove(); }, component: modal, }; }; export default Modal;