基於SqlSugar的開發框架循序漸進介紹(12)-- 拆分頁面模組內容為元件,實現分而治之的處理

2022-07-21 12:00: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語法糖編寫頁面和元件的總結