ivue-material-plus
Version:
A high quality UI components Library with Vue.js
461 lines (416 loc) • 10.7 kB
text/typescript
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;