基於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<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語法糖編寫頁面和組件的總結

Tags: