• 基于SqlSugar的开发框架循序渐进介绍(12)-- 拆分页面模块内容为组件,实现分而治之的处理


    在早期的随笔就介绍过,把常规页面的内容拆分为几个不同的组件,如普通的页面,包括列表查询、详细资料查看、新增资料、编辑资料、导入资料等页面场景,这些内容相对比较独立,而有一定的代码量,本篇随笔介绍基于Vue3+Typescript+Setup语法方式,来拆分页面模块内容为组件,实现分而治之的处理。

    1、页面模块组件的划分

    我们先来了解下常规页面的内容的整体界面布局,它包含常规的列表界面,新增、编辑、查看、导入等界面,除了列表页面,其他内容以弹出层对话框的方式进行处理,如下界面示意图所示。

    这些页面也可以放在一个大页面里面进行处理,逻辑代码也可以整合一起进行管理,大致的页面布局如下所示。

    我们看到,如果这样放置页面的模块内容,如果界面控件比较多的话,页面代码会急剧增加,而且由于代码太多,管理起来也非常不方便,最好的方式,还是拆分进行组件化的管理比较好 。

    我们以一个测试用户的页面为例来介绍,测试用户列表界面如下所示。

     其中也包括了查看、编辑、新增、导入等界面,我们后面逐一介绍。

     

    2、页面组件的开发

     我们前面介绍到,整个页面包含了列表界面,新增、编辑、查看、导入等界面,除了列表页面,其他内容以弹出层对话框的方式进行处理。

    我们分别创建index.vue代表主列表页面内容,view代表查看页面、edit代表新增或者编辑页面(两个页面类似,因此整合一起更精简),import代表导入页面,一起放在一个testuser页面目录中,作为一个模块页面。

     我们先以view.vue查看页面为例进行介绍,它是一个查看明细的界面,因此也是一个弹出对话框页面,我们把它的代码处理如下所示。

    复制代码
    <template>
      <el-dialog title="查看信息" v-model="isVisible" v-if="isVisible" append-to-body @close="closeDialog(viewRef)">
        <el-form ref="viewRef" :model="viewForm" label-width="80px">
          <el-tabs type="border-card">
            <el-tab-pane label="基本信息">
              <el-row>
                <el-col :span="12">
                  <el-form-item label="姓名">
                    <el-input v-model="viewForm.name" disabled />
                  el-form-item>
                el-col>
                <el-col :span="12">
                  <el-form-item label="性别">
                    <el-input v-model="viewForm.sex" disabled />
                  el-form-item>
                el-col>
    
                .................//省略代码
    
            el-tab-pane>
          el-tabs>
        el-form>
        <template #footer>
          <span class="dialog-footer">
            <el-button @click="closeDialog(viewRef)">关闭el-button>
          span>
        template>
      el-dialog>
    template>
    复制代码

    其他的js代码采用tyepscript语法,我们把它放在

    <script setup lang="ts">
    //逻辑代码
    script>

    为了把组件的方法公开,我们先定义一个接口类型,便于引用的时候,代码进行约束提示。

    复制代码
    <script setup lang="ts">
    //组件的接口类型
    export interface ExposeViewType {
      show(id?: string | number): Function;
    }
    
    ............
    
    //显示窗口
    const show = (id: string | number) => {
       //处理代码
    
    };
    
    //暴露组件属性和方法
    defineExpose({
      show
    });
    
    script>
    复制代码

    这样我们在父页面中使用子模块组件的时候,就可以通过公开的方法进行调用了。

    复制代码
    //父页面index.vue
    
        
        <view-data ref="viewRef" />
        
        <edit-data ref="editRef" @submit="saveEdit" />
        
        <import-data ref="importRef" @finish="finishImport" />
      div>
    template>
    
    <script setup lang="ts">
    ........
    
    import ViewData, { ExposeViewType } from "./view.vue";
    import EditData from "./edit.vue";
    import ImportData from "./import.vue";
    
    ......
    
    // 显示查看对话框处理
    const viewRef = ref<ExposeViewType | null>(); //查看表单引用
    //const viewRef = ref>();
    function showView(id) {
      if (isEmpty(id)) {
        warnMessage("请选择编辑的记录!");
        return;
      }
      viewRef.value.show(id);
    }
    复制代码

    我们通过const viewRef = ref();  就可以获得组件类型的引用,然后调用组件的接口方法即可。

    viewRef.value.show(id);

    在查看页面的组件定义模板中,我们大致代码如下所示。

    声明了对应的引用,以及表单对象,以及提供相应的方法进行处理,这些内容对父页面封装了细节。

    复制代码
    <script setup lang="ts">
    //组件的接口类型
    export interface ExposeViewType {
      show(id?: string | number): Function;
    }
    
    import { reactive, ref, onMounted, watch, computed, nextTick } from "vue";
    import { FormInstance} from "element-plus";
    
    defineOptions({ name: "ViewData" }); //定义组件名称
    
    //声明Props的接口类型
    interface Props {
      visible?: boolean; // 是否显示
      id?: string | number; // 接受外部v-model传入的id值
    }
    //使用默认值定义Props
    const props = withDefaults(defineProps<Props>(), {
      visible: false,
      value: null
    });
    
    //声明组件事件
    interface Emits {
      (e: "update:id", id: string | number): void;
      (e: "update:visible", visible: boolean): void;
      (e: "close"): void;
      //(e: "submit"): void;
    }
    //定义组件事件
    const emit = defineEmits<Emits>();
    复制代码

    我们定义了组件名称、组件的Props属性、以及Emit事件,Emit事件如果想简单化一点,也可以直接使用名称即可。

    例如,有时候我们会直接声明名称进行定义Emit,如下所示。

    //定义触发事件
    const emit = defineEmits(["error", "success", "remove", "change"]);

    显示页面的方法,是公开给父页面进行调用的,因此接收一个id参数,并根据id值,利用axios访问远端API接口获取数据,进行赋值显示即可。

    复制代码
    //显示窗口
    const show = (id: string | number) => {
      if (!isNullOrUnDef(id)) {
        testuser.Get(id).then(data => {
          // console.log(data);
          Object.assign(viewForm, data);
    
          isVisible.value = true; //显示对话框
        });
      }
    };
    复制代码

    关于axios访问远端API接口的类实现,可以参考随笔《基于SqlSugar的开发框架循序渐进介绍(10)-- 利用axios组件的封装,实现对后端API数据的访问和基类的统一封装处理》进行了解。

    这里的TestUser的APi类,继承自基类BaseApi,因此拥有常规的处理方法。

    最后,查看明细的窗口关闭后,需要设置一下窗口的相关标记。

    复制代码
    let isVisible = ref(false); //是否显示查看对话框
    function closeDialog(formEl: FormInstance | undefined) {
      // 关闭常规 添加、编辑、查看、导入等窗口处理
      isVisible.value = false;
    
      if (!formEl) {
        formEl.resetFields();
      }
      emit("close"); //关闭
    }
    复制代码

    由于窗口内部的显示标记和Prop属性的关系,我们需要处理一下,对他们进行Watch监控,并处理值的变化。

    复制代码
    //监控某些值的变化,进行处理
    watch(
      () => props.visible,
      newValue => {
        isVisible.value = newValue;
        emit("update:visible", newValue);
      }
    );
    watch(
      () => isVisible,
      newValue => {
        // console.log(newValue);
        emit("update:visible", newValue.value);
      }
    );
    复制代码

    表单的form对象,我们根据后端数据结构进行生成即可。

    复制代码
    const viewRef = ref(); //表单引用
    // 表单属性定义
    let viewForm = reactive({
      id: "",
      name: "",
      sex: "",
      birthDate: "",
      nationality: "",
      education: "",
      marriage: "",
      star: "",
      height: "",
      weight: "",
    
    .................
    
      createTime: "",
      extensionData: "" // 扩展数据
    });
    复制代码

    有了这些处理,我们查看详细的页面弹出和关闭就正常了。页面效果如下所示。

     新建、编辑页面也是类似,只是在保存数据后触发相关的事件,让父页面进行更新显示即可。

    复制代码
        
        <view-data ref="viewRef" />
        
        <edit-data ref="editRef" @submit="saveEdit" />
        
        <import-data ref="importRef" @finish="finishImport" />
    复制代码

    如编辑、新增页面的父组件页面,也是只需关注他的打开和完成处理即可。

    复制代码
    //新增、编辑表单引用
    const editRef = refnull>();
    //显示新增对话框
    function showAdd() {
      editRef.value.show();
    }
    // 显示编辑对话框
    function showEdit(id) {
      if (isEmpty(id)) {
        warnMessage("请选择编辑的记录!");
        return;
      }
      editRef.value.show(id);
    }
    //新增/更新后刷新
    function saveEdit() {
      getlist();
    }
    复制代码

    而在编辑信息的组件页面内部,就需要判断是更新还是插入记录的处理,完成后再抛出事件即可。

    复制代码
    // 保存数据处理
    async function submitData() {
      var formEl = editRef.value;
      if (!formEl) return;
    
      // console.log(editForm);
      await formEl.validate(async valid => {
        if (valid) {
          //验证成功,执行下面方法
          var result = false;
          if (isAdd.value) {
            result = await testuser.Create(editForm); //新增保存
          } else {
            result = await testuser.Update(editForm); //编辑保存
          }
    
          if (result) {
            successMessage("操作成功!"); // 提示信息
            emit("submit"); // 提示刷新数据
            closeDialog(formEl); // 重置窗口状态
          } else {
            errorMessage("操作失败");
          }
        }
      })
    复制代码

     导入数据页面,大体也是类似,不过由于涉及到更多的是对导入处理的规则处理,需要封装一下相关的组件功能,因此后面再独立介绍细节实现。

     

    系列文章:

    基于SqlSugar的开发框架的循序渐进介绍(1)--框架基础类的设计和使用

    基于SqlSugar的开发框架循序渐进介绍(2)-- 基于中间表的查询处理

    基于SqlSugar的开发框架循序渐进介绍(3)-- 实现代码生成工具Database2Sharp的整合开发

    基于SqlSugar的开发框架循序渐进介绍(4)-- 在数据访问基类中对GUID主键进行自动赋值处理 

    基于SqlSugar的开发框架循序渐进介绍(5)-- 在服务层使用接口注入方式实现IOC控制反转

    基于SqlSugar的开发框架循序渐进介绍(6)-- 在基类接口中注入用户身份信息接口 

    基于SqlSugar的开发框架循序渐进介绍(7)-- 在文件上传模块中采用选项模式【Options】处理常规上传和FTP文件上传

     《基于SqlSugar的开发框架循序渐进介绍(8)-- 在基类函数封装实现用户操作日志记录

    基于SqlSugar的开发框架循序渐进介绍(9)-- 结合Winform控件实现字段的权限控制

    基于SqlSugar的开发框架循序渐进介绍(10)-- 利用axios组件的封装,实现对后端API数据的访问和基类的统一封装处理

    基于SqlSugar的开发框架循序渐进介绍(11)-- 使用TypeScript和Vue3的Setup语法糖编写页面和组件的总结

  • 相关阅读:
    Golang 规则引擎原理及实战
    工作十多年后反思自己为什么没有成为牛逼程序员
    【Servlet】这一文详细的讲述了Servlet的知识,呕心沥血,终于文成。
    LeetCode 92. Reverse Linked List II【链表,头插法】中等
    dup dup2 不仅仅是int那么简单
    Google Earth Engine(GEE)——两种线性回归计算(单变量linefit和多变量linearRegression)
    如何管理oralce口令文件和参数文件
    自学网络编程第一天- HTTP基础:基础原理、Request请求、Response应答
    实景三维技术在应急管理与防灾减灾领域的应用
    nginx —— win下搭建nginx - hls服务,使用FFmpeg进行rtmp/http/m3u8推拉流
  • 原文地址:https://www.cnblogs.com/wuhuacong/p/16501436.html