Skip to content

ModelessDialog 非模态对话框

基于Panel构建的非模态对话框,支持最大化,最小化,收起,展开,拖拽改变大小等功能,常用于预览文件,视频,音频等常驻页面操作。

基础用法

可以通过声明组件的形式,实例化该组件。在点击关闭或者路由切换以后,该组件自动销毁

可以在style中设置left/top覆盖默认的弹出位置
vue
<template>
  <el-button @click="show">{{ visible ? 'Hide' : 'Show' }}</el-button>
  <epp-modeless-dialog v-model="visible" title="非模态对话框示例" resize @resize="resizeCB">
    <p>非模态对话框示例</p>
  </epp-modeless-dialog>
</template>
<script lang="ts" setup>
import { ref } from 'vue';

const visible = ref(false);

const show = () => {
  visible.value = !visible.value;
};
const resizeCB = () => {
  console.log('resizing...');
};
</script>

拖动范围

可以通过 boundings 属性限定可拖拽范围,boundings为四个数值的数组,分别为左上角坐标(x,y)与右下角坐标(x,y)

范围:左上角(0,0) / 右下角(1000,600)
Range: Top-left (0, 0) / Bottom-right (1000, 600)
示例代码
vue
<template>
  <el-button @click="show">{{ visible ? 'Hide' : 'Show' }}</el-button>
  <div class="m-t-md">范围:左上角(0,0) / 右下角(1000,600)</div>
  <div class="m-t-md">Range: Top-left (0, 0) / Bottom-right (1000, 600)</div>
  <epp-modeless-dialog v-model="visible" width="400px" title="非模态对话框示例" :boundings="[0, 0, 1000, 600]">
    <p>非模态对话框示例</p>
  </epp-modeless-dialog>
</template>
<script lang="ts" setup>
import { ref } from 'vue';

const visible = ref(false);

const show = () => {
  visible.value = !visible.value;
};
</script>

使用ModelessDialogManager

通过调用 ModelessDialogManager API的 show 方法创建对话框,此对话框可以在页面切换以后保持不被销毁。

id属性需要唯一固定值
vue
<template>
  <el-space size="large">
    <el-button @click="create">创建(Create)</el-button>
    <el-button @click="close">手动关闭(Close Manually)</el-button>
  </el-space>
</template>
<script lang="ts" setup>
import { h } from 'vue';
import { ElEmpty } from 'element-plus';
import { ModelessDialogManager } from 'element-plus-plus';

const close = () => {
  ModelessDialogManager.get('my-modelesss-dialog').close();
};

const create = () => {
  ModelessDialogManager.show({
    id: 'my-modelesss-dialog',
    title: '测试Manager',
    body: h(ElEmpty, { description: '空内容' }),
    resize: true,
    onResize: (dlg: HTMLDivElement) => {
      console.log('resize', dlg);
    },
    onOpen: () => {
      console.log('open');
    },
    onOpened: () => {
      console.log('opened');
    },
    onClose: () => {
      console.log('close');
    },
    onClosed: () => {
      console.log('closed');
    },
    onDestroy: () => {
      console.log('destroy');
    },
    onCollapse: (value: boolean) => {
      console.log('collapse', value);
    },
    onMaximize: (value: boolean) => {
      console.log('maximize', value);
    },
  });
};
</script>

ModelessDialogManager API示例

状态(Status):隐藏(Hide)




headerbodyfooter 必须为VNode实例,否则不进行处理
vue
<template>
  <el-space size="large">
    <el-button @click="create">创建(Create)</el-button>
    <el-tag>状态(Status):{{ visible ? '显示(Show)' : '隐藏(Hide)' }}</el-tag>
  </el-space>
  <br /><br />
  <el-space size="large">
    <el-button @click="max">最大化(Max)</el-button>
    <el-button @click="collapse">折叠(Collapse)</el-button>
    <el-button @click="show">显示/隐藏(Show/Hide)</el-button>
    <el-button @click="close">手工关闭(Close Manually)</el-button>
  </el-space>
  <hr />
  <el-space size="large" class="m-t-lg">
    <el-button @click="create2">创建多个对话框(Create Dialogs)</el-button>
  </el-space>
  <br />
  <el-space size="large" class="m-t-lg">
    <el-button @click="collaseAll">折叠所有(Collapse All)</el-button>
    <el-button @click="closeAll">关闭所有(Close All)</el-button>
    <el-button @click="hideAll">隐藏所有(Hide All)</el-button>
    <el-button @click="showAll">显示所有(Show All)</el-button>
  </el-space>
</template>
<script lang="ts" setup>
import { ref, h } from 'vue';
import { ElButton } from 'element-plus';
import { ModelessDialogManager } from 'element-plus-plus';

const inputVal = ref('');
const visible = ref(false);

const create = () => {
  ModelessDialogManager.show({
    id: 'my-modelesss-dialog2',
    title: '测试Manager,固定ID',
    body: h('input', {
      value: inputVal.value,
      style: 'border: 1px solid #efefef',
      onInput: (e: InputEvent) => {
        inputVal.value = (e.target as HTMLInputElement).value;
      },
    }),
    footer: h('div', null, [
      h(ElButton, { type: 'primary', class: 'm-r-md' }, { default: () => '确定' }),
      h(ElButton, null, { default: () => '取消' }),
    ]),
  });
  visible.value = ModelessDialogManager.get('my-modelesss-dialog2').isShown();
};

const show = () => {
  ModelessDialogManager.get('my-modelesss-dialog2').toggleShow();
  visible.value = ModelessDialogManager.get('my-modelesss-dialog2').isShown();
};
const max = () => {
  ModelessDialogManager.get('my-modelesss-dialog2').toggleMaximize();
};
const collapse = () => {
  ModelessDialogManager.get('my-modelesss-dialog2').toggleCollapse();
};
const close = () => {
  ModelessDialogManager.get('my-modelesss-dialog2').close();
};

const create2 = () => {
  ModelessDialogManager.show({
    title: '测试Manager',
  });
};

const collaseAll = () => {
  ModelessDialogManager.collapseAll();
};
const closeAll = () => {
  ModelessDialogManager.closeAll();
};
const showAll = () => {
  ModelessDialogManager.showAll();
};
const hideAll = () => {
  ModelessDialogManager.hideAll();
};
</script>

ModelessDialogManager API响应式示例

如果需要动态修改对话框,可以使用 reactive 包装所有属性。



示例代码
vue
<template>
  <el-space size="large">
    <el-button @click="create">创建(Create)</el-button>
    <el-button @click="modifyProp">修改对话框属性(Modify properties)</el-button>
  </el-space>
  <br /><br />
  <el-space size="large">
    <el-button @click="modifySlot">修改Slot(Modify slot)</el-button>
    <el-button @click="modifyPanel">修改Panel属性(Modify panel properties)</el-button>
  </el-space>
</template>
<script lang="ts" setup>
import { ref, reactive, h } from 'vue';
import { ElButton } from 'element-plus';
import { ModelessDialogManager } from 'element-plus-plus';

const inputVal = ref('');
const dialogProps = reactive({
  id: 'my-modelesss-dialog3',
  borderless: true,
  bodyPadding: 'var(--lg)',
  title: '测试Manager',
  body: h('input', {
    value: inputVal.value,
    onInput: (e: InputEvent) => {
      inputVal.value = (e.target as HTMLInputElement).value;
    },
  }),
  footer: h('div', null, [
    h(ElButton, { type: 'primary', class: 'm-r-md' }, { default: () => '确定' }),
    h(ElButton, null, { default: () => '取消' }),
  ]),
});

const create = () => {
  ModelessDialogManager.show(dialogProps);
};
const modifyProp = () => {
  dialogProps.title = '修改对话框标题';
};
const modifySlot = () => {
  dialogProps.footer = h('div', { innerHTML: '修改Footer Slot内容' });
};
const modifyPanel = () => {
  dialogProps.borderless = false;
  dialogProps.bodyPadding = '8px';
};
</script>

图片/视频/文档预览示例

  • 可以拖拽右下角改变大小
  • 可以最大化,最小化
  • 可以切换路由,保持浮窗不关闭
示例代码
vue
<template>
  <el-space size="large">
    <el-button @click="create1">图片(Image)</el-button>
    <el-button @click="create2">多张图(2x2 Image)</el-button>
    <el-button @click="create3">PDF预览(Preview)</el-button>
  </el-space>
</template>
<script lang="ts" setup>
import { h } from 'vue';
import { withBase } from 'vitepress';
import { ModelessDialogManager } from 'element-plus-plus';

const create1 = () => {
  ModelessDialogManager.show({
    customClass: 'example-modeless',
    title: '图片预览',
    width: '40vw',
    height: '30vh',
    body: h('div', { class: 'image-example', innerHTML: `<img src="${withBase('/zen.jpg')}" />` }),
    resize: true,
    onResize: (dlg: HTMLDivElement) => {
      console.log('resize', dlg);
    },
  });
};

const create2 = () => {
  ModelessDialogManager.show({
    customClass: 'example-modeless2',
    title: '图片预览',
    width: '40vw',
    height: '30vh',
    body: h('div', {
      class: 'image-example2',
      innerHTML: `
<img src="${withBase('/zen.jpg')}" />
<img src="${withBase('/zen.jpg')}" />
<img src="${withBase('/zen.jpg')}" />
<img src="${withBase('/zen.jpg')}" />
`,
    }),
    resize: true,
    onResize: (dlg: HTMLDivElement) => {
      console.log('resize', dlg);
    },
  });
};

const create3 = () => {
  ModelessDialogManager.show({
    customClass: 'example-modeless3',
    title: 'PDF预览',
    width: '40vw',
    height: '50vh',
    body: h('iframe', { class: 'pdf-example', src: `${withBase('/example.pdf')}` }),
    resize: true,
  });
};
</script>
<style lang="scss">
.example-modeless,
.example-modeless2 {
  .panel-body {
    height: calc(100% - var(--panel-header-height));
  }
}
.example-modeless3 {
  .panel-body {
    padding: 0;
    height: calc(100% - var(--panel-header-height));
  }
}
.image-example {
  width: 100%;
  height: 100%;
  img {
    width: 100%;
    height: 100%;
    object-fit: contain;
  }
}
.image-example2 {
  width: 100%;
  height: 100%;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  img {
    width: calc(50% - 20px / 2);
    height: calc(50% - 20px / 2);
    object-fit: cover;
  }
}
.pdf-example {
  width: 100%;
  height: 100%;
}
</style>

配合DockContainer使用

请参见DockContainer组件文档。

Attributes

参数说明类型可选值默认值
model-value / v-model是否显示对话框boolean
width对话框的宽度string-
height对话框的高度string-
top对话框 CSS 中的 top 值string-
resize右下角是否可拖拽改变大小booleanfalse
drag是否可拖拽booleantrue
boundings可拖拽范围array-
custom-class对话框的自定义类名string
open-delay对话框打开的延时时间,单位毫秒number0
close-delay对话框关闭的延时时间,单位毫秒number0
show-close是否显示关闭按钮booleantrue
show-maximize是否显示最大化按钮booleantrue
show-collapse是否显示折叠按钮booleantrue
before-close关闭前的回调,会暂停对话框的关闭function(done),done 用于关闭 Dialog
animation-name对话框动画类型string--
title对话框标题,优先级低于header slotstring--
z-index自定义层级number--
id对话框根节点idstring--
use-dock是否配合DockContainer使用。如果设置为true,折叠时会把对话框收纳到DockContainer中去boolean-false
snapshot配合DockContainer使用时,需要展示的形式boolean / string / object { type: string, url: string }-false
Panel组件属性对话框基于Panel组件构建,自动支持使用Panel组件所有属性---

Slots

名称说明
default自定义内容
header自定义头部
footer自定义底部

Events

事件名称说明回调参数
open对话框打开的回调
opened对话框打开动画结束时的回调
close对话框关闭的回调
closed对话框关闭动画结束时的回调
resize对话框拖拽改变大小回调对话框DOM根节点
maximize对话框最大化/最小化回调是否最大化
collapse对话框收起/展开回调是否收起

ModelessDialogManager Methods

方法名说明参数
show显示对话框,会自定检查指定id的对话框是否存在,如果存在将直接返回已存在对话框实例对话框所支持属性 & { header: VNode, body: VNode, footer: VNode }
get获取对话框实例对话框id
has检查对话框是否已经存在对话框id
closeAll关闭所有对话框-
showAll显示所有对话框-
hideAll隐藏所有对话框-
collapseAll折叠多有对话框-
expandAll展开所有对话框-

ModelessDialog Instance Methods

方法名说明参数
close关闭对话框-
toggleShow显示/隐藏对话框shown: boolean,手动设置显示或者隐藏
toggleCollapse折叠/展开对话框collapsable: boolean,手动设置折叠或者展开
toggleMaximize最大化/还原对话框maximizable: boolean,手动设置最大化
isShown对话框已经显示-
isClosed对话框是否已经关闭-
isCollapsed对话框是否已经折叠-
isMaximized对话框是否已经最大化-