基于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 interfac  e 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);  

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

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

 <  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<FormInstance>  ();  //  表单引用  //  表单属性定义 
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 = 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(
"操作失败" );
}
}
})

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

 

系列文章:

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

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

《基于SqlSugar的开发框架循序渐进介绍(13)-- 基于ElementPlus的上传组件进行封装,便于项目使用》

《基于SqlSugar的开发框架循序渐进介绍(14)-- 基于Vue3+TypeScript的全局对象的注入和使用》

 《基于SqlSugar的开发框架循序渐进介绍(15)-- 整合代码生成工具进行前端界面的生成》

《基于SqlSugar的开发框架循序渐进介绍(16)-- 工作流模块的功能介绍》

《基于SqlSugar的开发框架循序渐进介绍(17)-- 基于CSRedis实现缓存的处理》

 《基于SqlSugar的开发框架循序渐进介绍(18)-- 基于代码生成工具Database2Sharp,快速生成Vue3+TypeScript的前端界面和Winform端界面》

标签: Javascript

添加新评论