index.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. <script setup lang="tsx">
  2. import { useRouter } from "vue-router";
  3. import { h, createVNode, ref } from "vue";
  4. import { message } from "@/utils/message";
  5. import { cloneDeep } from "@pureadmin/utils";
  6. import forms, { type FormProps } from "./form.vue";
  7. import { addDialog, closeDialog, closeAllDialog } from "@/components/ReDialog";
  8. defineOptions({
  9. name: "Dialog"
  10. });
  11. const router = useRouter();
  12. function onBaseClick() {
  13. addDialog({
  14. title: "基本使用",
  15. contentRenderer: () => <p>弹框内容-基本使用</p> // jsx 语法 (注意在.vue文件启用jsx语法,需要在script开启lang="tsx")
  16. });
  17. }
  18. function onDraggableClick() {
  19. addDialog({
  20. title: "可拖拽",
  21. draggable: true,
  22. contentRenderer: () => h("p", "弹框内容-可拖拽") // h 渲染函数 https://cn.vuejs.org/api/render-function.html#h
  23. });
  24. }
  25. function onFullscreenClick() {
  26. addDialog({
  27. title: "全屏",
  28. fullscreen: true,
  29. contentRenderer: () => createVNode("p", null, "弹框内容-全屏") // createVNode 渲染函数 https://cn.vuejs.org/guide/extras/render-function.html#creating-vnodes
  30. });
  31. }
  32. function onFullscreenIconClick() {
  33. addDialog({
  34. title: "全屏按钮",
  35. fullscreenIcon: true,
  36. contentRenderer: () => <p>弹框内容-全屏按钮</p>
  37. });
  38. }
  39. function onModalClick() {
  40. addDialog({
  41. title: "无背景遮罩层",
  42. modal: false,
  43. contentRenderer: () => <p>弹框内容-无背景遮罩层</p>
  44. });
  45. }
  46. function onStyleClick() {
  47. addDialog({
  48. title: "自定义弹出位置",
  49. top: "60vh",
  50. style: { marginRight: "20px" },
  51. contentRenderer: () => <p>弹框内容-自定义弹出位置</p>
  52. });
  53. }
  54. function onoOpenDelayClick() {
  55. addDialog({
  56. title: "延时2秒打开弹框",
  57. openDelay: 2000,
  58. contentRenderer: () => <p>弹框内容-延时2秒打开弹框</p>
  59. });
  60. }
  61. function onCloseDelayClick() {
  62. addDialog({
  63. title: "延时2秒关闭弹框",
  64. closeDelay: 2000,
  65. contentRenderer: () => <p>弹框内容-延时2秒关闭弹框</p>
  66. });
  67. }
  68. function onShowCloseClick() {
  69. addDialog({
  70. title: "不显示右上角关闭按钮图标",
  71. showClose: false,
  72. contentRenderer: () => <p>弹框内容-不显示右上角关闭按钮图标</p>
  73. });
  74. }
  75. function onBeforeCloseClick() {
  76. addDialog({
  77. title: "禁止通过键盘ESC关闭",
  78. closeOnPressEscape: false,
  79. contentRenderer: () => <p>弹框内容-禁止通过键盘ESC关闭</p>
  80. });
  81. }
  82. function onCloseOnClickModalClick() {
  83. addDialog({
  84. title: "禁止通过点击modal关闭",
  85. closeOnClickModal: false,
  86. contentRenderer: () => <p>弹框内容-禁止通过点击modal关闭</p>
  87. });
  88. }
  89. function onHideFooterClick() {
  90. addDialog({
  91. title: "隐藏底部取消、确定按钮",
  92. hideFooter: true,
  93. contentRenderer: () => <p>弹框内容-隐藏底部取消、确定按钮</p>
  94. });
  95. }
  96. function onHeaderRendererClick() {
  97. addDialog({
  98. title: "自定义头部",
  99. showClose: false,
  100. headerRenderer: ({ close, titleId, titleClass }) => (
  101. // jsx 语法
  102. <div class="flex flex-row justify-between">
  103. <h4 id={titleId} class={titleClass}>
  104. 自定义头部
  105. </h4>
  106. <el-button type="danger" onClick={close}>
  107. 关闭
  108. </el-button>
  109. </div>
  110. ),
  111. contentRenderer: () => <p>弹框内容-自定义头部</p>
  112. });
  113. }
  114. function onFooterRendererClick() {
  115. addDialog({
  116. title: "自定义底部",
  117. footerRenderer: ({ options, index }) => (
  118. <el-button onClick={() => closeDialog(options, index)}>
  119. {options.title}-{index}
  120. </el-button>
  121. ),
  122. contentRenderer: () => <p>弹框内容-自定义底部</p>
  123. });
  124. }
  125. function onFooterButtonsClick() {
  126. addDialog({
  127. title: "自定义底部按钮",
  128. footerButtons: [
  129. {
  130. label: "按钮1",
  131. size: "small",
  132. type: "success",
  133. btnClick: ({ dialog: { options, index }, button }) => {
  134. console.log(options, index, button);
  135. closeDialog(options, index);
  136. }
  137. },
  138. {
  139. label: "按钮2",
  140. text: true,
  141. bg: true,
  142. btnClick: ({ dialog: { options, index }, button }) => {
  143. console.log(options, index, button);
  144. closeDialog(options, index);
  145. }
  146. },
  147. {
  148. label: "按钮3",
  149. size: "large",
  150. type: "warning",
  151. btnClick: ({ dialog: { options, index }, button }) => {
  152. console.log(options, index, button);
  153. closeDialog(options, index);
  154. }
  155. }
  156. ],
  157. contentRenderer: () => <p>弹框内容-自定义底部按钮</p>
  158. });
  159. }
  160. function onOpenClick() {
  161. addDialog({
  162. title: "打开后的回调",
  163. open: ({ options, index }) => message({ options, index } as any),
  164. contentRenderer: () => <p>弹框内容-打开后的回调</p>
  165. });
  166. }
  167. function onCloseCallBackClick() {
  168. addDialog({
  169. title: "关闭后的回调",
  170. closeCallBack: ({ options, index, args }) => {
  171. console.log(options, index, args);
  172. let text = "";
  173. if (args?.command === "cancel") {
  174. text = "您点击了取消按钮";
  175. } else if (args?.command === "sure") {
  176. text = "您点击了确定按钮";
  177. } else {
  178. text = "您点击了右上角关闭按钮或者空白页";
  179. }
  180. message(text);
  181. },
  182. contentRenderer: () => <p>弹框内容-关闭后的回调</p>
  183. });
  184. }
  185. // 这里为了演示方便,使用了嵌套写法,实际情况下最好把 addDialog 函数抽出来 套娃不可取
  186. function onNestingClick() {
  187. addDialog({
  188. title: "嵌套的弹框",
  189. contentRenderer: ({ index }) => (
  190. <el-button
  191. onClick={() =>
  192. addDialog({
  193. title: `第${index + 1}个子弹框`,
  194. width: "40%",
  195. contentRenderer: ({ index }) => (
  196. <el-button
  197. onClick={() =>
  198. addDialog({
  199. title: `第${index + 1}个子弹框`,
  200. width: "30%",
  201. contentRenderer: () => (
  202. <>
  203. <el-button round onClick={() => closeAllDialog()}>
  204. 哎呦,你干嘛,赶快关闭所有弹框
  205. </el-button>
  206. </>
  207. )
  208. })
  209. }
  210. >
  211. 点击打开第{index + 1}个子弹框
  212. </el-button>
  213. )
  214. })
  215. }
  216. >
  217. 点击打开第{index + 1}个子弹框
  218. </el-button>
  219. )
  220. });
  221. }
  222. // 结合Form表单(第一种方式,弹框关闭立刻恢复初始值)通过 props 属性接收子组件的 prop 并赋值
  223. function onFormOneClick() {
  224. addDialog({
  225. width: "30%",
  226. title: "结合Form表单(第一种方式)",
  227. contentRenderer: () => forms,
  228. props: {
  229. // 赋默认值
  230. formInline: {
  231. user: "菜虚鲲",
  232. region: "浙江"
  233. }
  234. },
  235. closeCallBack: ({ options, args }) => {
  236. // options.props 是响应式的
  237. const { formInline } = options.props as FormProps;
  238. const text = `姓名:${formInline.user} 城市:${formInline.region}`;
  239. if (args?.command === "cancel") {
  240. // 您点击了取消按钮
  241. message(`您点击了取消按钮,当前表单数据为 ${text}`);
  242. } else if (args?.command === "sure") {
  243. message(`您点击了确定按钮,当前表单数据为 ${text}`);
  244. } else {
  245. message(`您点击了右上角关闭按钮或者空白页,当前表单数据为 ${text}`);
  246. }
  247. }
  248. });
  249. }
  250. // 结合Form表单(第二种方式)h 渲染函数 https://cn.vuejs.org/api/render-function.html#h
  251. const formInline = ref({
  252. user: "菜虚鲲",
  253. region: "浙江"
  254. });
  255. const resetFormInline = cloneDeep(formInline.value);
  256. function onFormTwoClick() {
  257. addDialog({
  258. width: "30%",
  259. title: "结合Form表单(第二种方式)",
  260. contentRenderer: () => h(forms, { formInline: formInline.value }),
  261. closeCallBack: () => {
  262. message(
  263. `当前表单数据为 姓名:${formInline.value.user} 城市:${formInline.value.region}`
  264. );
  265. // 重置表单数据
  266. formInline.value = cloneDeep(resetFormInline);
  267. }
  268. });
  269. }
  270. // 结合Form表单(第三种方式)createVNode 渲染函数 https://cn.vuejs.org/guide/extras/render-function.html#creating-vnodes
  271. const formThreeInline = ref({
  272. user: "菜虚鲲",
  273. region: "浙江"
  274. });
  275. const resetFormThreeInline = cloneDeep(formThreeInline.value);
  276. function onFormThreeClick() {
  277. addDialog({
  278. width: "30%",
  279. title: "结合Form表单(第三种方式)",
  280. contentRenderer: () =>
  281. createVNode(forms, { formInline: formThreeInline.value }),
  282. closeCallBack: () => {
  283. message(
  284. `当前表单数据为 姓名:${formThreeInline.value.user} 城市:${formThreeInline.value.region}`
  285. );
  286. // 重置表单数据
  287. formThreeInline.value = cloneDeep(resetFormThreeInline);
  288. }
  289. });
  290. }
  291. // 结合Form表单(第四种方式)使用jsx语法
  292. // 需要注意的是如果 forms 没注册,这里 forms 注册了是因为上面 contentRenderer: () => forms、h(forms) 、createVNode(createVNode) 间接给注册了
  293. // 如果只使用了jsx语法,如下 `contentRenderer: () => <forms formInline={formFourInline.value} />` 是不会给 forms 组件进行注册的,需要在 `script` 中任意位置(最好是末尾)写上 forms 即可
  294. // 同理如果在 tsx 文件中,这么使用 `contentRenderer: () => <forms formInline={formFourInline.value} />`,也是不会给 forms 组件进行注册,需要在 return 中写上 forms
  295. const formFourInline = ref({
  296. user: "菜虚鲲",
  297. region: "浙江"
  298. });
  299. const resetFormFourInline = cloneDeep(formFourInline.value);
  300. function onFormFourClick() {
  301. addDialog({
  302. width: "30%",
  303. title: "结合Form表单(第四种方式)",
  304. contentRenderer: () => <forms formInline={formFourInline.value} />,
  305. closeCallBack: () => {
  306. message(
  307. `当前表单数据为 姓名:${formFourInline.value.user} 城市:${formFourInline.value.region}`
  308. );
  309. // 重置表单数据
  310. formFourInline.value = cloneDeep(resetFormFourInline);
  311. }
  312. });
  313. }
  314. function onBeforeCancelClick() {
  315. addDialog({
  316. title: "点击底部取消按钮的回调",
  317. contentRenderer: () => (
  318. <p>弹框内容-点击底部取消按钮的回调(会暂停弹框的关闭)</p>
  319. ),
  320. beforeCancel: (done, { options, index }) => {
  321. console.log(
  322. "%coptions, index===>>>: ",
  323. "color: MidnightBlue; background: Aquamarine; font-size: 20px;",
  324. options,
  325. index
  326. );
  327. // done(); // 需要关闭把注释解开即可
  328. }
  329. });
  330. }
  331. function onBeforeSureClick() {
  332. addDialog({
  333. title: "点击底部确定按钮的回调",
  334. contentRenderer: () => (
  335. <p>
  336. 弹框内容-点击底部确定按钮的回调(会暂停弹框的关闭,经常用于新增、编辑弹框内容后调用接口)
  337. </p>
  338. ),
  339. beforeSure: (done, { options, index }) => {
  340. console.log(
  341. "%coptions, index===>>>: ",
  342. "color: MidnightBlue; background: Aquamarine; font-size: 20px;",
  343. options,
  344. index
  345. );
  346. // done(); // 需要关闭把注释解开即可
  347. }
  348. });
  349. }
  350. </script>
  351. <template>
  352. <el-card shadow="never">
  353. <template #header>
  354. <div class="card-header">
  355. <span class="font-medium">
  356. 二次封装 element-plus 的
  357. <el-link
  358. href="https://element-plus.org/zh-CN/component/dialog.html"
  359. target="_blank"
  360. style="margin: 0 4px 5px; font-size: 16px"
  361. >
  362. Dialog
  363. </el-link>
  364. ,采用函数式调用弹框组件(更多操作实例请参考
  365. <span
  366. class="cursor-pointer text-primary"
  367. @click="router.push({ name: 'Dept' })"
  368. >系统管理页面</span
  369. >
  370. </span>
  371. </div>
  372. </template>
  373. <el-space wrap>
  374. <el-button @click="onBaseClick"> 基本使用 </el-button>
  375. <el-button @click="onDraggableClick"> 可拖拽 </el-button>
  376. <el-button @click="onFullscreenClick"> 全屏 </el-button>
  377. <el-button @click="onFullscreenIconClick"> 全屏按钮 </el-button>
  378. <el-button @click="onModalClick"> 无背景遮罩层 </el-button>
  379. <el-button @click="onStyleClick"> 自定义弹出位置 </el-button>
  380. <el-button @click="onoOpenDelayClick"> 延时2秒打开弹框 </el-button>
  381. <el-button @click="onCloseDelayClick"> 延时2秒关闭弹框 </el-button>
  382. <el-button @click="onShowCloseClick">
  383. 不显示右上角关闭按钮图标
  384. </el-button>
  385. <el-button @click="onBeforeCloseClick"> 禁止通过键盘ESC关闭 </el-button>
  386. <el-button @click="onCloseOnClickModalClick">
  387. 禁止通过点击modal关闭
  388. </el-button>
  389. <el-button @click="onHideFooterClick"> 隐藏底部取消、确定按钮 </el-button>
  390. <el-button @click="onHeaderRendererClick"> 自定义头部 </el-button>
  391. <el-button @click="onFooterRendererClick"> 自定义底部 </el-button>
  392. <el-button @click="onFooterButtonsClick"> 自定义底部按钮 </el-button>
  393. <el-button @click="onOpenClick"> 打开后的回调 </el-button>
  394. <el-button @click="onCloseCallBackClick"> 关闭后的回调 </el-button>
  395. <el-button @click="onNestingClick"> 嵌套的弹框 </el-button>
  396. </el-space>
  397. <el-divider />
  398. <el-space wrap>
  399. <el-button @click="onFormOneClick">
  400. 结合Form表单(第一种方式)
  401. </el-button>
  402. <el-button @click="onFormTwoClick">
  403. 结合Form表单(第二种方式)
  404. </el-button>
  405. <el-button @click="onFormThreeClick">
  406. 结合Form表单(第三种方式)
  407. </el-button>
  408. <el-button @click="onFormFourClick">
  409. 结合Form表单(第四种方式)
  410. </el-button>
  411. </el-space>
  412. <el-divider />
  413. <el-space wrap>
  414. <el-button @click="onBeforeCancelClick">
  415. 点击底部取消按钮的回调(会暂停弹框的关闭)
  416. </el-button>
  417. <el-button @click="onBeforeSureClick">
  418. 点击底部确定按钮的回调(会暂停弹框的关闭,经常用于新增、编辑弹框内容后调用接口)
  419. </el-button>
  420. </el-space>
  421. </el-card>
  422. </template>