ホームページ >ウェブフロントエンド >Vue.js >Vue3 はパフォーマンスを向上させ、効率を高めるためにこのようにリスト ページを作成します。

Vue3 はパフォーマンスを向上させ、効率を高めるためにこのようにリスト ページを作成します。

青灯夜游
青灯夜游オリジナル
2022-12-23 19:23:592193ブラウズ

管理バックエンドの開発プロセスでは、必ず多くの追加、削除、変更、クエリ ページに遭遇することになりますが、これらのページのロジックのほとんどは同じです。これにより、コードの結合度が増加します。再利用可能なデータはフックに抽出されるため、結合の問題が解決されるだけでなく、作業効率も向上します。

Vue3 はパフォーマンスを向上させ、効率を高めるためにこのようにリスト ページを作成します。

管理バックエンドの開発プロセスでは、多くの追加、削除、変更、クエリ ページに遭遇することになりますが、これらのページのロジックはほとんど同じです。 、リストデータの取得などの基本的な機能、ページングやフィルタリング機能など。違いは、表示されるデータ項目です。いくつかのアクションボタンもあります。 [関連する推奨事項: vuejs ビデオ チュートリアル Web フロントエンド開発 ]

Vue3 はパフォーマンスを向上させ、効率を高めるためにこのようにリスト ページを作成します。

ページが 1 つまたは 2 つしかない場合ほとんどの開発者は、前のページのコードを直接コピーして追加のコピーを作成しますが、プロジェクトが進行するにつれて、同様のページの数が増加する可能性があり、それはプロジェクト コードの結合度の増加に直接つながります。

これは、いくつかの再利用可能な関数またはコンポーネントをプロジェクトから抽出する必要がある主な理由の 1 つでもあります。

以下では、ほとんどのリストに適合する一般的な useList をカプセル化します。追加、削除、変更、クエリのページが表示されるため、タスクをより迅速かつ効率的に完了し、定時で仕事を終えることができます~

Vue3 はパフォーマンスを向上させ、効率を高めるためにこのようにリスト ページを作成します。

前提条件の知識

  • Vue
  • #Vue Comboposition Api
カプセル化

いくつかの共通パラメータと関数を抽出してカプセル化する必要があります共通の

hook に追加すると、後で他のページで同じ関数を再利用するのが簡単で便利になります。

リスト ページに必要なページング データを定義する

export default function useList() {
  // 加载态
  const loading = ref(false);
  // 当前页
  const curPage = ref(1);
  // 总数量
  const total = ref(0);
  // 分页大小
  const pageSize = ref(10);
}

リスト データの取得方法

よく考えて、

useList 関数に listRequestFn パラメーター。リスト内のデータを要求するために使用されます。

ネットワーク リクエストによって返されたデータ コンテンツを保存する

list 変数を定義します。リスト データ型は内部で直接決定できないため、ジェネリックを通じて外部から提供されます。

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

#useList

loadData 関数を作成し、データ取得関数を呼び出します。この関数は、指定されたページ数のデータを取得するためのパラメーターを受け取ります (オプション、デフォルト) curPageの値に)。

実行処理
読み込み状態の設定
  1. 外部関数を呼び出し、取得したデータを
  2. リストに代入
  3. total読み込み状態を閉じます
ここでは、リクエスト エラーまたは分解エラーが発生することを想定して、async/await 構文が使用されています。コード ブロックをキャッチして、読み込み状態を閉じます。

ここでは、受信 listRequestFn 関数によって受け取られるパラメータの数と型が適切に対応しているかどうかに注意する必要があります。 実際の状況に応じて調整してください

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;
    }
  };
}

忘れないでください。処理するページングの切り替えもあります。

watch

関数を使用してデータを監視します。 when curPagepageSize の値が変更されると、loadData 関数を呼び出して新しいデータを取得します。 <pre class="brush:js;toolbar:false;">export default function useList&lt;ItemType extends Object&gt;( listRequestFn: Function ) { // 忽略其他代码 // 监听分页数据改变 watch([curPage, pageSize], () =&gt; { loadData(curPage.value); }); }</pre>基本的なリスト データ取得が実装されました

データ フィルターの実装

巨大なデータ リストでは、データ フィルターは必須の機能です

通常、私は

ref

でフィルター条件フィールドを定義し、リクエスト時に ref をリクエスト関数にスローするだけです。 useList 関数では、2 番目のパラメーターは、リスト内のフィルター条件フィールドに対応する

filterOption

オブジェクトを受け取ります。

loadData

関数を調整し、リクエスト関数の filterOption オブジェクトに渡します。

受信 listRequestFn 関数は、通常、パラメータの数とタイプは互いに対応します 実際の状況に応じて調整してください。

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;
    }
  };
}

ここでの filterOption パラメータのタイプは ref タイプである必要があることに注意してください。そうしないと、応答性が失われ、適切に動作しなくなります。

フィルターをクリアする Filter フィールド

ページには、フィルター条件をクリアするためのリセット ボタンがあります。この繰り返し動作はリセット機能で対応できます。

Reflect を使用してすべての値を

unknown

に設定し、再度データをリクエストします。 <blockquote><p>什么是 Reflect?看看这一篇文章<a href="https://www.php.cn/link/ea87c8c0013f91fe48edd914c7203107" target="_blank" title="https://www.php.cn/link/ea87c8c0013f91fe48edd914c7203107">Reflect 映射对象</a></p></blockquote><pre class="brush:js;toolbar:false;">export default function useList&lt; ItemType extends Object, FilterOption extends Object &gt;(listRequestFn: Function, filterOption: Ref&lt;Object&gt;) { const reset = () =&gt; { if (!filterOption.value) return; const keys = Reflect.ownKeys(filterOption.value); filterOption.value = {} as FilterOption; keys.forEach((key) =&gt; { Reflect.set(filterOption.value!, key, undefined); }); loadData(); }; }</pre><h2 data-id="heading-7">导出功能</h2> <p>除了对数据的查看,有些界面还需要有导出数据功能(例如导出 csv,excel 文件),我们也把导出功能写到<code>useList

通常,导出功能是调用后端提供的导出Api获取一个文件下载地址,和loadData函数类似,从外部获取exportRequestFn函数来调用Api

在函数中,新增一个exportFile函数调用它。

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");
    }
  };
}

注意,传入的 exportRequestFn 函数接收的参数数量和类型是否正常对应上 请根据实际情况进行调整

优化

现在,整个useList已经满足了页面上的需求了,拥有了获取数据,筛选数据,导出数据,分页功能

还有一些细节方面,在上面所有代码中的try..catch中的catch代码片段并没有做任何的处理,只是简单的console.log一下

提供钩子

useList新增一个 Options 对象参数,用于函数成功、失败时执行指定钩子函数与输出消息内容。

定义 Options 类型

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
) {
  // ...
}

设置Options默认值

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
) {
  // ...
}

在没有传递钩子的情况霞,推荐设置默认的失败时信息显示

优化loadDataexportFile函数

基于 elementui 封装 message 方法

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 函数

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 函数

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 使用方法

<template>
  <el-collapse>
    <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>
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>

本文useList的完整代码在 github.com/QC2168/snip…

(学习视频分享:vuejs入门教程编程基础视频

以上がVue3 はパフォーマンスを向上させ、効率を高めるためにこのようにリスト ページを作成します。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。