jjzjj

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

wuhuacong(伍华聪)的专栏 2023-03-28 原文

在早期的随笔就介绍过,把常规页面的内容拆分为几个不同的组件,如普通的页面,包括列表查询、详细资料查看、新增资料、编辑资料、导入资料等页面场景,这些内容相对比较独立,而有一定的代码量,本篇随笔介绍基于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<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端界面

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

  1. 叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践 - 2

    导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵

  2. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  3. kvm虚拟机安装centos7基于ubuntu20.04系统 - 2

    需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc

  4. ruby - 在 ASP 页面上 Mechanize 中断 - 2

    require'mechanize'agent=Mechanize.newlogin=agent.get('http://www.schoolnet.ch/DE/HomeDE.htm')agent.clicklogin.link_withtext:/Login/然后我得到Mechanize::UnsupportedSchemeError。 最佳答案 Mechanize不支持javascript但您可以将搜索字段添加到表单并为其分配搜索词并使用mechanize提交表单form=page.forms.firstform.add_fie

  5. ruby-on-rails - prawnto 显示新页面时不会中断的表格 - 2

    我有可变数量的表格和可变数量的行,我想让它们一个接一个地显示,但如果表格不适合当前页面,请将其放在下一页,然后继续。我已将表格放入事务中,以便我可以回滚然后打印它(如果高度适合当前页面),但我如何获得表格高度?我现在有这段代码pdf.transactiondopdf.table@data,:font_size=>12,:border_style=>:grid,:horizontal_padding=>10,:vertical_padding=>3,:border_width=>2,:position=>:left,:row_colors=>["FFFFFF","DDDDDD"]pdf.

  6. ruby - 每个页面上的 Jekyll 分页 - 2

    据我们所知,Jekyll默认分页仅支持index.html,我想创建blog.html并在那里包含分页。有什么解决办法吗? 最佳答案 如果您创建一个名为/blog的目录并在其中放置一个index.html文件,那么您可以向_config.yml表示paginate_path:"blog/page:num"。不是使用根文件夹中的默认index.html作为分页器模板,而是使用/blog/index.html。分页器将根据需要生成类似/blog/page2/和/blog/page3/的页面。这将使您到达yourwebsite.com/b

  7. ruby-on-rails - (Ruby,Rails) 基于角色的身份验证和用户管理...? - 2

    我正在寻找用于Rails的优质管理插件。似乎大多数现有的插件/gem(例如“restful_authentication”、“acts_as_authenticated”)都围绕着self注册等展开。但是,我正在寻找一种功能齐全的基于管理/管理角色的解决方案——但不是简单地附加到另一个非基于角色的解决方案。如果我找不到,我想我会自己动手......只是不想重新发明轮子。 最佳答案 RyanBates最近做了两个关于授权的railscast(注意身份验证和授权之间的区别;身份验证检查用户是否如她所说的那样,授权检查用户是否有权访问资源

  8. ruby-on-rails - RoR && "coming soon"页面 - 2

    我正在寻找一种简单的方法来为我在RubyonRails上的项目实现简单的“即将推出”(预启动)页面。用户应该能够留下电子邮件以便在项目启动时收到通知。有没有这样的插件\gem?或者我应该自己做... 最佳答案 LaunchingSoon是一个Rails插件。它还集成了MailChimp或Campaignmonitor. 关于ruby-on-rails-RoR&&"comingsoon"页面,我们在StackOverflow上找到一个类似的问题: https:/

  9. ruby - 如何让 GitHub 页面使用 master 分支? - 2

    我有一个使用Jekyll托管在GitHub上的静态网站。问题是,我真的不需要master分支,因为存储库唯一包含的是网站。这样我就必须gitcheckoutgh-pages,然后gitmergemaster,然后gitpushorigingh-pages。有什么简单的方法可以摆脱gh-pages分支并直接从master推送? 最佳答案 Theproblemis,Idon'treallyneedthemasterbranch,astheonlythingtherepositorycontainsisthewebsite.Isthere

  10. ruby - 在 Rakefile 中动态生成 Rake 测试任务(基于现有的测试文件) - 2

    我正在根据Rakefile中的现有测试文件动态生成测试任务。假设您有各种以模式命名的单元测试文件test_.rb.所以我正在做的是创建一个以“测试”命名空间内的文件名命名的任务。使用下面的代码,我可以用raketest:调用所有测试require'rake/testtask'task:default=>'test:all'namespace:testdodesc"Runalltests"Rake::TestTask.new(:all)do|t|t.test_files=FileList['test_*.rb']endFileList['test_*.rb'].eachdo|task|n

随机推荐