10

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

 2 years ago
source link: https://www.cnblogs.com/wuhuacong/p/16501436.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

1、页面模块组件的划分

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

8867-20200602162838705-1715400949.png

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

8867-20220721104045499-1584158207.png

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

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

8867-20220721110404838-1276075243.png

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

2、页面组件的开发

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

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

8867-20220721110755933-387746199.png

 我们先以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<InstanceType<typeof ViewData>>();
function showView(id) {
  if (isEmpty(id)) {
    warnMessage("请选择编辑的记录!");
    return;
  }
  viewRef.value.show(id);
}

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

viewRef.value.show(id);

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

8867-20220721112044055-270977156.png

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

<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,因此拥有常规的处理方法。

8867-20220721113733059-567703695.png

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

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<FormInstance>(); //表单引用
// 表单属性定义
let viewForm = reactive({
  id: "",
  name: "",
  sex: "",
  birthDate: "",
  nationality: "",
  education: "",
  marriage: "",
  star: "",
  height: "",
  weight: "",

.................

  createTime: "",
  extensionData: "" // 扩展数据
});

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

8867-20220721114332733-987277685.png

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

    <!--查看详细组件界面-->
    <view-data ref="viewRef" />
    <!--新增、编辑组件界面-->
    <edit-data ref="editRef" @submit="saveEdit" />
    <!--模板导入信息-->
    <import-data ref="importRef" @finish="finishImport" />

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

//新增、编辑表单引用
const editRef = ref<ExposeViewType | null>();
//显示新增对话框
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("操作失败");
      }
    }
  })
8867-20220721114850768-1756030188.png

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

系列文章:

基于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语法糖编写页面和组件的总结


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK