ホームページ >ウェブフロントエンド >Vue.js >Vue3 はパフォーマンスを向上させ、効率を高めるためにこのようにリスト ページを作成します。
管理バックエンドの開発プロセスでは、必ず多くの追加、削除、変更、クエリ ページに遭遇することになりますが、これらのページのロジックのほとんどは同じです。これにより、コードの結合度が増加します。再利用可能なデータはフックに抽出されるため、結合の問題が解決されるだけでなく、作業効率も向上します。
管理バックエンドの開発プロセスでは、多くの追加、削除、変更、クエリ ページに遭遇することになりますが、これらのページのロジックはほとんど同じです。 、リストデータの取得などの基本的な機能、ページングやフィルタリング機能など。違いは、表示されるデータ項目です。いくつかのアクションボタンもあります。 [関連する推奨事項: vuejs ビデオ チュートリアル 、Web フロントエンド開発 ]
ページが 1 つまたは 2 つしかない場合ほとんどの開発者は、前のページのコードを直接コピーして追加のコピーを作成しますが、プロジェクトが進行するにつれて、同様のページの数が増加する可能性があり、それはプロジェクト コードの結合度の増加に直接つながります。
これは、いくつかの再利用可能な関数またはコンポーネントをプロジェクトから抽出する必要がある主な理由の 1 つでもあります。
以下では、ほとんどのリストに適合する一般的な useList
をカプセル化します。追加、削除、変更、クエリのページが表示されるため、タスクをより迅速かつ効率的に完了し、定時で仕事を終えることができます~
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
の値に)。
total
読み込み状態を閉じますここでは、受信 listRequestFn 関数によって受け取られるパラメータの数と型が適切に対応しているかどうかに注意する必要があります。 実際の状況に応じて調整してください
watchexport 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; } }; }忘れないでください。処理するページングの切り替えもあります。
関数を使用してデータを監視します。 when curPage
、pageSize
の値が変更されると、loadData
関数を呼び出して新しいデータを取得します。 <pre class="brush:js;toolbar:false;">export default function useList<ItemType extends Object>(
listRequestFn: Function
) {
// 忽略其他代码
// 监听分页数据改变
watch([curPage, pageSize], () => {
loadData(curPage.value);
});
}</pre>
基本的なリスト データ取得が実装されました
データ フィルターの実装
通常、私は
ref でフィルター条件フィールドを定義し、リクエスト時に ref
をリクエスト関数にスローするだけです。 useList 関数では、2 番目のパラメーターは、リスト内のフィルター条件フィールドに対応する
オブジェクトを受け取ります。
関数を調整し、リクエスト関数の filterOption
オブジェクトに渡します。
ここでの filterOption パラメータのタイプは ref タイプである必要があることに注意してください。そうしないと、応答性が失われ、適切に動作しなくなります。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; } }; }
フィルターをクリアする 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<
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();
};
}</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 对象参数,用于函数成功、失败时执行指定钩子函数与输出消息内容。
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 ) { // ... }
在没有传递钩子的情况霞,推荐设置默认的失败时信息显示
loadData
,exportFile
函数基于 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?.(); } };
<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…
以上がVue3 はパフォーマンスを向上させ、効率を高めるためにこのようにリスト ページを作成します。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。