Bläddra i källkod

feat: 函数式弹框组件添加结合`Form`的`demo`示例

xiaoxian521 2 år sedan
förälder
incheckning
7957dc2c18

+ 3 - 3
src/components/ReDialog/type.ts

@@ -128,7 +128,7 @@ interface DialogOptions extends DialogProps {
     close: Function;
     titleId: string;
     titleClass: string;
-  }) => VNode;
+  }) => VNode | Component;
   /** 自定义内容渲染器 */
   contentRenderer?: ({
     options,
@@ -136,7 +136,7 @@ interface DialogOptions extends DialogProps {
   }: {
     options: DialogOptions;
     index: number;
-  }) => VNode;
+  }) => VNode | Component;
   /** 自定义按钮操作区的内容渲染器,会覆盖`footerButtons`以及默认的 `取消` 和 `确定` 按钮 */
   footerRenderer?: ({
     options,
@@ -144,7 +144,7 @@ interface DialogOptions extends DialogProps {
   }: {
     options: DialogOptions;
     index: number;
-  }) => VNode;
+  }) => VNode | Component;
   /** 自定义底部按钮操作 */
   footerButtons?: Array<ButtonProps>;
   /** `Dialog` 打开后的回调 */

+ 45 - 0
src/views/components/dialog/form.vue

@@ -0,0 +1,45 @@
+<script setup lang="ts">
+import { ref } from "vue";
+
+// 声明 props 类型
+export interface FormProps {
+  formInline: {
+    user: string;
+    region: string;
+  };
+}
+
+// 声明 props 默认值
+// 推荐阅读:https://cn.vuejs.org/guide/typescript/composition-api.html#typing-component-props
+const props = withDefaults(defineProps<FormProps>(), {
+  formInline: () => ({ user: "", region: "" })
+});
+
+// vue 规定所有的 prop 都遵循着单向绑定原则,不能在子组件中更改 prop 值,该 form.vue 文件为子组件
+// 如果需要拿到初始化的 prop 值并使得组件变量可修改,则需要在子组件定义一个新的变量接受这个子组件的 prop
+// 推荐阅读:https://cn.vuejs.org/guide/components/props.html#one-way-data-flow
+const newFormInline = ref(props.formInline);
+</script>
+
+<template>
+  <el-form :model="newFormInline">
+    <el-form-item label="姓名">
+      <el-input
+        class="!w-[220px]"
+        v-model="newFormInline.user"
+        placeholder="请输入姓名"
+      />
+    </el-form-item>
+    <el-form-item label="城市">
+      <el-select
+        class="!w-[220px]"
+        v-model="newFormInline.region"
+        placeholder="请选择城市"
+      >
+        <el-option label="上海" value="上海" />
+        <el-option label="浙江" value="浙江" />
+        <el-option label="深圳" value="深圳" />
+      </el-select>
+    </el-form-item>
+  </el-form>
+</template>

+ 114 - 1
src/views/components/dialog/index.vue

@@ -1,6 +1,8 @@
 <script setup lang="tsx">
-import { h, createVNode } from "vue";
+import { h, createVNode, ref } from "vue";
 import { message } from "@/utils/message";
+import { cloneDeep } from "@pureadmin/utils";
+import forms, { type FormProps } from "./form.vue";
 import { addDialog, closeDialog, closeAllDialog } from "@/components/ReDialog";
 
 defineOptions({
@@ -225,6 +227,102 @@ function onNestingClick() {
     )
   });
 }
+
+// 结合Form表单(第一种方式,弹框关闭立刻恢复初始值)通过 props 属性接收子组件的 prop 并赋值
+function onFormOneClick() {
+  addDialog({
+    width: "30%",
+    title: "结合Form表单(第一种方式)",
+    contentRenderer: () => forms,
+    props: {
+      // 赋默认值
+      formInline: {
+        user: "菜虚鲲",
+        region: "浙江"
+      }
+    },
+    closeCallBack: ({ options, args }) => {
+      // options.props 是响应式的
+      const { formInline } = options.props as FormProps;
+      const text = `姓名:${formInline.user} 城市:${formInline.region}`;
+      if (args?.command === "cancel") {
+        // 您点击了取消按钮
+        message(`您点击了取消按钮,当前表单数据为 ${text}`);
+      } else if (args?.command === "sure") {
+        message(`您点击了确定按钮,当前表单数据为 ${text}`);
+      } else {
+        message(`您点击了右上角关闭按钮或者空白页,当前表单数据为 ${text}`);
+      }
+    }
+  });
+}
+
+// 结合Form表单(第二种方式)h 渲染函数 https://cn.vuejs.org/api/render-function.html#h
+const formInline = ref({
+  user: "菜虚鲲",
+  region: "浙江"
+});
+const resetFormInline = cloneDeep(formInline.value);
+function onFormTwoClick() {
+  addDialog({
+    width: "30%",
+    title: "结合Form表单(第二种方式)",
+    contentRenderer: () => h(forms, { formInline: formInline.value }),
+    closeCallBack: () => {
+      message(
+        `当前表单数据为 姓名:${formInline.value.user} 城市:${formInline.value.region}`
+      );
+      // 重置表单数据
+      formInline.value = cloneDeep(resetFormInline);
+    }
+  });
+}
+
+// 结合Form表单(第三种方式)createVNode 渲染函数 https://cn.vuejs.org/guide/extras/render-function.html#creating-vnodes
+const formThreeInline = ref({
+  user: "菜虚鲲",
+  region: "浙江"
+});
+const resetFormThreeInline = cloneDeep(formThreeInline.value);
+function onFormThreeClick() {
+  addDialog({
+    width: "30%",
+    title: "结合Form表单(第三种方式)",
+    contentRenderer: () =>
+      createVNode(forms, { formInline: formThreeInline.value }),
+    closeCallBack: () => {
+      message(
+        `当前表单数据为 姓名:${formThreeInline.value.user} 城市:${formThreeInline.value.region}`
+      );
+      // 重置表单数据
+      formThreeInline.value = cloneDeep(resetFormThreeInline);
+    }
+  });
+}
+
+// 结合Form表单(第四种方式)使用jsx语法
+// 需要注意的是如果 forms 没注册,这里 forms 注册了是因为上面 contentRenderer: () => forms、h(forms) 、createVNode(createVNode) 间接给注册了
+// 如果只使用了jsx语法,如下 `contentRenderer: () => <forms formInline={formFourInline.value} />` 是不会给 forms 组件进行注册的,需要在 `script` 中任意位置(最好是末尾)写上 forms 即可
+// 同理如果在 tsx 文件中,这么使用 `contentRenderer: () => <forms formInline={formFourInline.value} />`,也是不会给 forms 组件进行注册,需要在 return 中写上 forms
+const formFourInline = ref({
+  user: "菜虚鲲",
+  region: "浙江"
+});
+const resetFormFourInline = cloneDeep(formFourInline.value);
+function onFormFourClick() {
+  addDialog({
+    width: "30%",
+    title: "结合Form表单(第四种方式)",
+    contentRenderer: () => <forms formInline={formFourInline.value} />,
+    closeCallBack: () => {
+      message(
+        `当前表单数据为 姓名:${formFourInline.value.user} 城市:${formFourInline.value.region}`
+      );
+      // 重置表单数据
+      formFourInline.value = cloneDeep(resetFormFourInline);
+    }
+  });
+}
 </script>
 
 <template>
@@ -267,5 +365,20 @@ function onNestingClick() {
       <el-button @click="onCloseCallBackClick"> 关闭后的回调 </el-button>
       <el-button @click="onNestingClick"> 嵌套的弹框 </el-button>
     </el-space>
+    <el-divider />
+    <el-space wrap>
+      <el-button @click="onFormOneClick">
+        结合Form表单(第一种方式)
+      </el-button>
+      <el-button @click="onFormTwoClick">
+        结合Form表单(第二种方式)
+      </el-button>
+      <el-button @click="onFormThreeClick">
+        结合Form表单(第三种方式)
+      </el-button>
+      <el-button @click="onFormFourClick">
+        结合Form表单(第四种方式)
+      </el-button>
+    </el-space>
   </el-card>
 </template>