Vue3-Paket-Tischhaken

Kapselung von Tischhaken in Vue3

Vorwort

Bei der Entwicklung des Verwaltungs-Backends werden Sie auf jeden Fall auf viele Seiten zum Hinzufügen, Löschen, Ändern und Abfragen stoßen, und die meisten Logiken dieser Seiten sind gleich, z. B. grundlegende Funktionen wie das Abrufen von Listendaten, Paging usw Filterfunktionen. Der Unterschied besteht in den dargestellten Datenelementen. Es gibt auch einige Aktionsschaltflächen.

Fügen Sie hier eine Bildbeschreibung ein

Wenn zu Beginn nur 1 oder 2 Seiten vorhanden sind, kopieren die meisten Entwickler möglicherweise direkt den vorherigen Seitencode. Mit fortschreitendem Projekt kann die Anzahl ähnlicher Seiten immer größer werden, was direkt dazu führt, dass die Codekopplung im Projekt immer höher wird und höher.

Dies ist auch einer der Hauptgründe, warum einige wiederverwendbare Funktionen oder Komponenten aus dem Projekt extrahiert werden sollten.

Im Folgenden fassen wir eine useListallgemeine Listenseite zusammen, die für die meisten Hinzufügungen, Löschungen, Änderungen und Suchvorgänge geeignet ist und es Ihnen ermöglicht, Aufgaben schneller und effizienter zu erledigen und pünktlich mit der Arbeit fertig zu werden~

vorausgesetzte Kenntnisse

  • Vue
  • Vue Composition API

Verkapselung

Wir müssen einige allgemeine Parameter und Funktionen extrahieren und sie in einem universellen Paket zusammenfassen hook. Es wird einfacher und bequemer sein, dieselben Funktionen später auf anderen Seiten wiederzuverwenden.

Definieren Sie wesentliche Paging-Daten für Listenseiten
export default function useList() {
    
    
  // 加载态
  const loading = ref(false);
  // 当前页
  const curPage = ref(1);
  // 总数量
  const total = ref(0);
  // 分页大小
  const pageSize = ref(10);
}
So erhalten Sie Listendaten

Wenn Sie darüber nachdenken, lassen Sie useListdie Funktion einen Parameter akzeptieren listRequestFn, der die Daten in der Liste anfordert.

Definieren Sie eine listVariable zum Speichern des von der Netzwerkanforderung zurückgegebenen Dateninhalts. Da der Listendatentyp intern nicht direkt bestimmt werden kann, wird der Listendatentyp extern über Generika bereitgestellt.

export default function useList<ItemType extends Object>(
  listRequestFn: Function
) {
    
    
  // 忽略其他代码
  const list = ref<ItemType[]>([]);
}

useListErstellen Sie eine Funktion , um loadDatadie Funktion „Daten abrufen“ aufzurufen, die einen Parameter empfängt, um die angegebene Anzahl von Datenseiten abzurufen (optional, standardmäßig ist curPageder Wert).

  • Umsetzungsprozess
  1. Ladestatus festlegen
  2. Rufen Sie die von außen übergebene Funktion auf und weisen Sie die erhaltenen Daten der listSumme zutotal
  3. Ladezustand schließen

Hier wird die Async/Await-Syntax verwendet. Wenn ein Anforderungsfehler oder ein Dekonstruktionsfehler vorliegt, wird der Catch-Code-Block verwendet und dann wird der Ladezustand geschlossen.

Hierbei ist zu beachten, dass die Anzahl und Art der von der übergebenen listRequestFn-Funktion empfangenen Parameter entsprechend der tatsächlichen Situation angepasst werden sollte.

export default function useList<ItemType extends Object>(
  listRequestFn: Function
) {
    
    
  // 忽略其他代码
  // 数据
  const list = ref<ItemType[]>([]);
  // 过滤数据
  // 获取列表数据
  const loadData = async (page = curPage.value) => {
    
    
    // 设置加载中
    loading.value = true;
    try {
    
    
      const {
    
    
        data,
        meta: {
    
     total: count },
      } = await listRequestFn(pageSize.value, page);
      list.value = data;
      total.value = count;
    } catch (error) {
    
    
      console.log("请求出错了", "error");
    } finally {
    
    
      // 关闭加载中
      loading.value = false;
    }
  };
}

Vergessen Sie nicht, dass es immer noch um den Seitenwechsel geht

Verwenden Sie watchdie Funktion, um Daten zu überwachen. Wenn sich der Wert von ändert, rufen Sie die Funktion auf curPage, um neue Daten abzurufen.pageSizeloadData

export default function useList<ItemType extends Object>(
  listRequestFn: Function
) {
    
    
  // 忽略其他代码
  // 监听分页数据改变
  watch([curPage, pageSize], () => {
    
    
    loadData(curPage.value);
  });
}

Die Erfassung grundlegender Listendaten ist jetzt implementiert

Implementieren Sie Datenfilter

In einer riesigen Datenliste ist die Datenfilterung eine wesentliche Funktion

Normalerweise würde ich die Filterfelder in einem definieren refund sie einfach in die Anfragefunktion werfen, wenn ich eine Anfrage stelle ref.

In der Funktion useList empfängt der zweite Parameter ein filterOptionObjekt, das dem Filterfeld in der Liste entspricht.

Passen Sie die Funktion an und übergeben Sie das Objekt loadDatain der AnforderungsfunktionfilterOption

Beachten Sie, dass die Anzahl und Art der von der eingehenden listRequestFn-Funktion empfangenen Parameter entsprechend der tatsächlichen Situation angepasst werden sollte.

export default function useList<
  ItemType extends Object,
  FilterOption extends Object
>(listRequestFn: Function, filterOption: Ref<Object>) {
    
    
  const loadData = async (page = curPage.value) => {
    
    
    // 设置加载中
    loading.value = true;
    try {
    
    
      const {
    
    
        data,
        meta: {
    
     total: count },
      } = await listRequestFn(pageSize.value, page, filterOption.value);
      list.value = data;
      total.value = count;
    } catch (error) {
    
    
      console.log("请求出错了", "error");
    } finally {
    
    
      // 关闭加载中
      loading.value = false;
    }
  };
}

Beachten Sie, dass der Parametertyp filterOption hier ein Ref-Typ sein muss, da sonst die Reaktionsfähigkeit verloren geht und nicht ordnungsgemäß funktioniert.

Filterfelder löschen

Auf der Seite gibt es eine Schaltfläche zum Zurücksetzen, um die Filterbedingungen zu löschen. Diese wiederholte Aktion kann durch die Reset-Funktion verarbeitet werden.

Setzen Sie alle Werte auf die Verwendung von Reflect undefinedund fordern Sie die Daten dann erneut an.

Was ist Reflect? Schauen Sie sich diesen Artikel „Mapping-Objekte reflektieren“ an

export default function useList<
  ItemType extends Object,
  FilterOption extends Object
>(listRequestFn: Function, filterOption: Ref<Object>) {
    
    
  const reset = () => {
    
    
    if (!filterOption.value) return;
    const keys = Reflect.ownKeys(filterOption.value);
    filterOption.value = {
    
    } as FilterOption;
    keys.forEach((key) => {
    
    
      Reflect.set(filterOption.value!, key, undefined);
    });
    loadData();
  };
}

Exportfunktion

Zusätzlich zum Anzeigen von Daten müssen einige Schnittstellen auch über die Funktion zum Exportieren von Daten verfügen (z. B. das Exportieren von CSV- und Excel-Dateien), und wir haben auch die Exportfunktion darin geschrieben useList.

Normalerweise besteht die Exportfunktion darin, den vom Backend bereitgestellten Export aufzurufen, Apium eine Datei-Download-Adresse zu erhalten. loadDataSie ähnelt der Funktion. Sie ruft die Funktion von außen ab exportRequestFnund ruft sie auf.Api

Fügen Sie innerhalb der Funktion eine neue exportFileFunktion hinzu, um sie aufzurufen.

export default function useList<
  ItemType extends Object,
  FilterOption extends Object
>(
  listRequestFn: Function,
  filterOption: Ref<Object>,
  exportRequestFn?: Function
) {
    
    
  // 忽略其他代码
  const exportFile = async () => {
    
    
    if (!exportRequestFn) {
    
    
      throw new Error("当前没有提供exportRequestFn函数");
    }
    if (typeof exportRequestFn !== "function") {
    
    
      throw new Error("exportRequestFn必须是一个函数");
    }
    try {
    
    
      const {
    
    
        data: {
    
     link },
      } = await exportRequestFn(filterOption.value);
      window.open(link);
    } catch (error) {
    
    
      console.log("导出失败", "error");
    }
  };
}

Beachten Sie, dass die Anzahl und Art der von der eingehenden exportRequestFn-Funktion empfangenen Parameter entsprechend der tatsächlichen Situation angepasst werden sollten.

Optimierung

useListJetzt wurden alle Anforderungen der Seite erfüllt, mit den Funktionen Daten abrufen, Daten filtern, Daten exportieren und Paging.

Es gibt auch einige Details. Die Codeausschnitte in allen oben genannten Codes try..catchwurden catchin keiner Weise verarbeitet, console.logsie sind einfach einfach.

Haken bereitstellen

Fügen Sie useListeinen Optionsobjektparameter hinzu, der verwendet wird, um die angegebene Hook-Funktion auszuführen und den Nachrichteninhalt auszugeben, wenn die Funktion erfolgreich ist oder fehlschlägt.

Definieren Sie den Optionstyp
export interface MessageType {
    
    
  GET_DATA_IF_FAILED?: string;
  GET_DATA_IF_SUCCEED?: string;
  EXPORT_DATA_IF_FAILED?: string;
  EXPORT_DATA_IF_SUCCEED?: string;
}
export interface OptionsType {
    
    
  requestError?: () => void;
  requestSuccess?: () => void;
  message: MessageType;
}

export default function useList<
  ItemType extends Object,
  FilterOption extends Object
>(
  listRequestFn: Function,
  filterOption: Ref<Object>,
  exportRequestFn?: Function,
  options? :OptionsType
) {
    
    
  // ...
}
OptionsStandardwert festlegen
const DEFAULT_MESSAGE = {
    
    
  GET_DATA_IF_FAILED: "获取列表数据失败",
  EXPORT_DATA_IF_FAILED: "导出数据失败",
};

const DEFAULT_OPTIONS: OptionsType = {
    
    
  message: DEFAULT_MESSAGE,
};

export default function useList<
  ItemType extends Object,
  FilterOption extends Object
>(
  listRequestFn: Function,
  filterOption: Ref<Object>,
  exportRequestFn?: Function,
  options = DEFAULT_OPTIONS
) {
    
    
  // ...
}

Für den Fall, dass kein Hook übergeben wird, wird empfohlen, die Standardmeldungsanzeige bei Fehler festzulegen.

Optimierung loadData, exportFileFunktion

Kapselungsnachrichtenmethode basierend auf Elementui

import {
    
     ElMessage, MessageOptions } from "element-plus";

export function message(message: string, option?: MessageOptions) {
    
    
  ElMessage({
    
     message, ...option });
}
export function warningMessage(message: string, option?: MessageOptions) {
    
    
  ElMessage({
    
     message, ...option, type: "warning" });
}
export function errorMessage(message: string, option?: MessageOptions) {
    
    
  ElMessage({
    
     message, ...option, type: "error" });
}
export function infoMessage(message: string, option?: MessageOptions) {
    
    
  ElMessage({
    
     message, ...option, type: "info" });
}
LoadData-Funktion
const loadData = async (page = curPage.value) => {
    
    
  loading.value = true;
  try {
    
    
    const {
    
    
      data,
      meta: {
    
     total: count },
    } = await listRequestFn(pageSize.value, page, filterOption.value);
    list.value = data;
    total.value = count;
    // 执行成功钩子
    options?.message?.GET_DATA_IF_SUCCEED &&
      message(options.message.GET_DATA_IF_SUCCEED);
    options?.requestSuccess?.();
  } catch (error) {
    
    
    options?.message?.GET_DATA_IF_FAILED &&
      errorMessage(options.message.GET_DATA_IF_FAILED);
    // 执行失败钩子
    options?.requestError?.();
  } finally {
    
    
    loading.value = false;
  }
};
exportFile-Funktion
const exportFile = async () => {
    
    
  if (!exportRequestFn) {
    
    
    throw new Error("当前没有提供exportRequestFn函数");
  }
  if (typeof exportRequestFn !== "function") {
    
    
    throw new Error("exportRequestFn必须是一个函数");
  }
  try {
    
    
    const {
    
    
      data: {
    
     link },
    } = await exportRequestFn(filterOption.value);
    window.open(link);
    // 显示信息
    options?.message?.EXPORT_DATA_IF_SUCCEED &&
      message(options.message.EXPORT_DATA_IF_SUCCEED);
    // 执行成功钩子
    options?.exportSuccess?.();
  } catch (error) {
    
    
    // 显示信息
    options?.message?.EXPORT_DATA_IF_FAILED &&
      errorMessage(options.message.EXPORT_DATA_IF_FAILED);
    // 执行失败钩子
    options?.exportError?.();
  }
};

useList-Nutzung


<template>
  <el-collapse class="mb-6">
    <el-collapse-item title="筛选条件" name="1">
      <el-form label-position="left" label-width="90px" :model="filterOption">
        <el-row :gutter="20">
          <el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="8">
            <el-form-item label="用户名">
              <el-input
                v-model="filterOption.name"
                placeholder="筛选指定签名名称"
              />
            </el-form-item>
          </el-col>
          <el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="8">
            <el-form-item label="注册时间">
              <el-date-picker
                v-model="filterOption.timeRange"
                type="daterange"
                unlink-panels
                range-separator="到"
                start-placeholder="开始时间"
                end-placeholder="结束时间"
                format="YYYY-MM-DD HH:mm"
                value-format="YYYY-MM-DD HH:mm"
              />
            </el-form-item>
          </el-col>
          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
            <el-row class="flex mt-4">
              <el-button type="primary" @click="filter">筛选</el-button>
              <el-button type="primary" @click="reset">重置</el-button>
            </el-row>
          </el-col>
        </el-row>
      </el-form>
    </el-collapse-item>
  </el-collapse>
  <el-table v-loading="loading" :data="list" border style="width: 100%">
    <el-table-column label="用户名" min-width="110px">
      <template #default="scope">
        {
   
   { scope.row.name }}
      </template>
    </el-table-column>
    <el-table-column label="手机号码" min-width="130px">
      <template #default="scope">
        {
   
   { scope.row.mobile || "未绑定手机号码" }}
      </template>
    </el-table-column>
    <el-table-column label="邮箱地址" min-width="130px">
      <template #default="scope">
        {
   
   { scope.row.email || "未绑定邮箱地址" }}
      </template>
    </el-table-column>
    <el-table-column prop="createAt" label="注册时间" min-width="220px" />
    <el-table-column width="200px" fixed="right" label="操作">
      <template #default="scope">
        <el-button type="primary" link @click="detail(scope.row)"
          >详情</el-button
        >
      </template>
    </el-table-column>
  </el-table>
  <div v-if="total > 0" class="flex justify-end mt-4">
    <el-pagination
      v-model:current-page="curPage"
      v-model:page-size="pageSize"
      background
      layout="sizes, prev, pager, next"
      :total="total"
      :page-sizes="[10, 30, 50]"
    />
  </div>
</template>
<script setup lang="ts">
import { UserInfoApi } from "@/network/api/User";
import useList from "@/lib/hooks/useList/index";
const filterOption = ref<UserInfoApi.FilterOptionType>({});
const {
  list,
  loading,
  reset,
  filter,
  curPage,
  pageSize,
  reload,
  total,
  loadData,
} = useList<UserInfoApi.UserInfo[], UserInfoApi.FilterOptionType>(
  UserInfoApi.list,
  filterOption
);
</script>
/>

Supongo que te gusta

Origin blog.csdn.net/dfc_dfc/article/details/133200824
Recomendado
Clasificación