前端开发还不知道Alova?

23 阅读5分钟

Alova 深入指南

什么是 Alova?

Alova 是一个轻量级、面向前端的请求策略库,旨在简化 API 调用、优化性能并提升开发效率。它通过声明式的 Method 实例管理请求,将复杂的请求逻辑(如参数、缓存、状态管理)高度抽象,号称将传统 7 步请求流程简化为“一步到位”。Alova 与 Vue 3 的 Composition API 深度集成,提供了响应式状态管理、丰富的业务场景策略以及强大的扩展性,特别适合现代前端开发。

核心特点

  • 声明式请求:通过 Method 实例封装请求信息,减少手动编码。
  • 响应式状态管理:与 Vue 3 的响应式系统无缝绑定,自动更新视图。
  • 内置策略:支持分页、表单提交、文件上传等 20+ 种业务场景,简化复杂逻辑。
  • 高性能:通过请求共享、缓存和预加载机制,减少网络请求,提升用户体验。
  • TypeScript 支持:提供完整的类型推导,增强代码健壮性。
  • 跨框架兼容:虽以 Vue 3 为例,但也支持 React、Svelte 等。

Alova 的设计理念是将 API 调用的配置、状态和行为集中到一个 Method 实例中,开发者只需关注业务逻辑,无需处理繁琐的请求细节。


Alova 的工作原理

Alova 的核心机制包括 方法代理设计状态代理设计请求策略中间件,以下详细解析。

方法代理设计

每个 API 请求都被封装为一个 Method 实例,包含 URL、请求方法、参数、头信息、缓存策略等。开发者通过 alovaInstance.GetPost 等方法创建 Method 实例,调用时无需手动拼接请求逻辑。例如:

const todoListGetter = alovaInstance.Get('/todos', {
  params: { page: 1, size: 10 },
  cacheFor: 1000 * 60, // 缓存 1 分钟
  transformData: (rawData) => rawData.list
});

Method 实例不仅定义了请求,还支持复用、链式调用和动态修改,适合复杂项目中的 API 管理。

状态代理设计

Alova 通过 statesHook 与 Vue 3 的响应式系统(如 refreactive)深度集成。使用 useRequestuseWatcher 等 Hook,请求状态(如 loadingdataerror)会自动变为响应式,状态变化直接触发视图更新。例如:

const { loading, data, error } = useRequest(todoListGetter);

当请求完成或失败时,dataerror 会自动更新,Vue 3 会同步刷新视图。

请求策略中间件

Alova 提供了中间件机制,允许开发者在请求前后插入自定义逻辑。例如,自动添加认证头:

const alovaInstance = createAlova({
  beforeRequest(method) {
    method.config.headers.Authorization = `Bearer ${localStorage.getItem('token')}`;
  }
});

此外,Alova 内置了 20+ 种策略(如分页、表单提交),通过中间件实现,极大简化了业务逻辑。


在 Vue 3 中使用 Alova

以下以 Vue 3 的 Composition API 和 <script setup> 为主,展示 Alova 在多种场景下的使用方式。

1. 环境搭建

安装
npm install alova alova/vue alova/fetch
创建 Alova 实例

在项目根目录创建一个 alova.js 文件:

import { createAlova } from 'alova';
import adapterFetch from 'alova/fetch';
import VueHook from 'alova/vue';

export const alovaInstance = createAlova({
  baseURL: 'https://api.example.com',
  statesHook: VueHook, // Vue 3 响应式 Hook
  requestAdapter: adapterFetch(), // 使用 fetch 适配器
  responded: response => response.json(), // 响应数据处理
  beforeRequest(method) {
    // 添加认证头
    method.config.headers.Authorization = `Bearer ${localStorage.getItem('token')}`;
  },
  errorHandler(error) {
    console.error('Request failed:', error);
    return Promise.reject(error);
  }
});
配置 TypeScript(可选)

为确保类型安全,添加类型定义:

import { Alova } from 'alova';

declare module '@vue/runtime-core' {
  interface ComponentCustomProperties {
    $alova: Alova;
  }
}

2. 基本请求:使用 useRequest

useRequest 是最常用的 Hook,用于发送请求并管理状态。以下是一个获取待办事项列表的示例:

<script setup>
import { useRequest } from 'alova/vue';
import { alovaInstance } from './alova';

// 定义 Method 实例
const todoListGetter = alovaInstance.Get('/todos', {
  params: { page: 1, size: 10 },
  cacheFor: 1000 * 60, // 缓存 1 分钟
  transformData: (rawData) => rawData.list
});

// 使用 useRequest
const { loading, data, error, send } = useRequest(todoListGetter, {
  initialData: [], // 初始数据
  immediate: true // 立即发送请求
});

// 手动触发请求
const handleRefresh = () => send();
</script>

<template>
  <div>
    <div v-if="loading">加载中...</div>
    <div v-else-if="error">{{ error.message }}</div>
    <div v-else>
      <ul>
        <li v-for="todo in data" :key="todo.id">{{ todo.title }}</li>
      </ul>
      <button @click="handleRefresh">刷新</button>
    </div>
  </div>
</template>

说明

  • loadingdataerror 是响应式对象,自动触发视图更新。
  • send 用于手动触发请求,适合需要用户交互的场景。
  • cacheFor 设置缓存时间,减少重复请求。

3. 动态请求:使用 useWatcher

当请求依赖动态参数(如分页、搜索条件)时,使用 useWatcher 监听参数变化并自动触发请求。

<script setup>
import { ref } from 'vue';
import { useWatcher } from 'alova/vue';
import { alovaInstance } from './alova';

const page = ref(1);
const size = ref(10);
const search = ref('');

// 定义分页请求
const todoListGetter = () => alovaInstance.Get('/todos', {
  params: { page: page.value, size: size.value, search: search.value },
  cacheFor: 1000 * 60,
  transformData: (rawData) => rawData.list
});

// 使用 useWatcher
const { loading, data } = useWatcher(todoListGetter, [page, size, search], {
  initialData: [],
  immediate: true
});

// 分页控制
const nextPage = () => page.value++;
const prevPage = () => page.value > 1 && page.value--;
</script>

<template>
  <div>
    <input v-model="search" placeholder="搜索待办事项" />
    <div v-if="loading">加载中...</div>
    <div v-else>
      <ul>
        <li v-for="todo in data" :key="todo.id">{{ todo.title }}</li>
      </ul>
      <button @click="prevPage" :disabled="page === 1">上一页</button>
      <button @click="nextPage">下一页</button>
    </div>
  </div>
</template>

说明

  • useWatcher 监听 pagesizesearch,任何变化都会触发请求。
  • 适用于分页、搜索、过滤等动态场景。

4. 表单提交

Alova 的表单策略支持草稿保存、验证和多页表单。以下是一个提交表单的示例:

<script setup>
import { ref } from 'vue';
import { useRequest } from 'alova/vue';
import { alovaInstance } from './alova';

const form = ref({ name: '', email: '' });

// 定义表单提交请求
const submitForm = alovaInstance.Post('/form', form, {
  transformData: (rawData) => rawData.result
});

const { loading, send, onSuccess } = useRequest(submitForm, { immediate: false });

// 监听提交成功
onSuccess(({ data }) => {
  alert('提交成功: ' + JSON.stringify(data));
});

// 提交表单
const handleSubmit = async () => {
  if (!form.value.name || !form.value.email) {
    alert('请填写完整信息');
    return;
  }
  await send();
};
</script>

<template>
  <div>
    <input v-model="form.name" placeholder="姓名" />
    <input v-model="form.email" placeholder="邮箱" />
    <button :disabled="loading" @click="handleSubmit">
      {{ loading ? '提交中...' : '提交' }}
    </button>
  </div>
</template>

说明

  • useRequestimmediate: false 确保请求手动触发。
  • onSuccess 用于处理提交成功后的逻辑。

5. 文件上传

Alova 支持文件上传,自动处理 FormData 和进度监控。

<script setup>
import { ref } from 'vue';
import { useRequest } from 'alova/vue';
import { alovaInstance } from './alova';

const file = ref(null);

// 定义文件上传请求
const uploadFile = (fileData) => alovaInstance.Post('/upload', { file: fileData }, {
  headers: { 'Content-Type': 'multipart/form-data' }
});

const { loading, send, onProgress } = useRequest(uploadFile, { immediate: false });
const progress = ref(0);

// 监听上传进度
onProgress(({ loaded, total }) => {
  progress.value = Math.round((loaded / total) * 100);
});

// 处理文件选择
const handleFileChange = (event) => {
  file.value = event.target.files[0];
};

// 触发上传
const handleUpload = async () => {
  if (file.value) {
    await send(file.value);
    alert('上传成功');
  }
};
</script>

<template>
  <div>
    <input type="file" @change="handleFileChange" />
    <button :disabled="loading" @click="handleUpload">
      {{ loading ? `上传中 (${progress}%)` : '上传' }}
    </button>
  </div>
</template>

说明

  • onProgress 提供上传进度反馈。
  • FormData 自动处理文件数据。

6. 请求拦截与错误处理

通过 Alova 的中间件,可以拦截请求和响应,统一处理认证、错误等逻辑。

<script setup>
import { useRequest } from 'alova/vue';
import { alovaInstance } from './alova';

// 定义请求
const todoGetter = alovaInstance.Get('/todos/1', {
  cacheFor: 0,
  transformData: (rawData) => rawData.data
});

const { loading, data, error, onError } = useRequest(todoGetter);

// 错误处理
onError(({ error }) => {
  if (error.status === 401) {
    alert('未授权,请登录');
  }
});
</script>

<template>
  <div>
    <div v-if="loading">加载中...</div>
    <div v-else-if="error">{{ error.message }}</div>
    <div v-else>{{ JSON.stringify(data) }}</div>
  </div>
</template>

说明

  • onError 用于处理特定错误,如 401 未授权。
  • 全局错误处理已在 alovaInstance 中配置。

7. 高级场景:请求队列与防抖

Alova 支持请求队列和防抖,优化高频请求场景。例如,搜索输入防抖:

<script setup>
import { ref } from 'vue';
import { useDebounce } from 'alova/client';
import { alovaInstance } from './alova';

const search = ref('');

// 定义搜索请求
const searchTodos = () => alovaInstance.Get('/todos', {
  params: { search: search.value },
  cacheFor: 0
});

// 使用防抖
const { loading, data } = useDebounce(searchTodos, [search], {
  debounce: 500, // 500ms 防抖
  initialData: []
});
</script>

<template>
  <div>
    <input v-model="search" placeholder="搜索待办事项" />
    <div v-if="loading">加载中...</div>
    <ul v-else>
      <li v-for="todo in data" :key="todo.id">{{ todo.title }}</li>
    </ul>
  </div>
</template>

说明

  • useDebounce 确保高频输入(如搜索)不会频繁触发请求。

Alova 的优势与适用场景

与其他库的对比

相比于 @tanstack/vue-queryswr

  • 更集中的 API 管理:通过 Method 实例统一管理请求,减少代码分散。
  • 内置业务策略:支持分页、表单、文件上传等场景,开箱即用。
  • 与 Vue 3 的深度集成:响应式状态与 Composition API 完美结合。
  • 轻量级:核心库体积小,性能开销低。

适用场景

  • 复杂前端应用:如管理系统、电商平台,需管理大量 API。
  • 动态交互场景:分页、搜索、表单提交等,Alova 的策略可大幅减少代码量。
  • 性能敏感项目:通过缓存和请求共享,优化网络性能。
  • 团队协作:统一的 Method 实例便于多人维护和 API 文档对接。

进阶技巧

1. 自定义请求策略

通过 useHookToSend 自定义 Hook,支持复杂业务逻辑。例如,创建一个带重试的请求:

import { useHookToSend } from 'alova/vue';

const useRetryRequest = (method, maxRetries = 3) => {
  const { loading, data, error, send } = useHookToSend(method);
  let retries = 0;

  const retrySend = async () => {
    try {
      return await send();
    } catch (err) {
      if (retries < maxRetries) {
        retries++;
        return retrySend();
      }
      throw err;
    }
  };

  return { loading, data, error, send: retrySend };
};

使用:

<script setup>
import { alovaInstance } from './alova';

const todoGetter = alovaInstance.Get('/todos/1');
const { loading, data, send } = useRetryRequest(todoGetter);
</script>

2. 状态持久化

Alova 支持将状态持久化到本地存储(如 localStorage),适合离线场景:

const todoListGetter = alovaInstance.Get('/todos', {
  localCache: {
    mode: 'storage',
    expire: 1000 * 60 * 60 // 缓存 1 小时
  }
});

3. 结合 DevTools

Alova 提供 DevTools 插件,可在浏览器中查看请求详情、缓存状态和 API 文档。安装方式:

npm install @alova/devtools

alova.js 中启用:

import { installAlovaDevtools } from '@alova/devtools';
installAlovaDevtools(alovaInstance);

开始使用 Alova

学习资源

  • 官方文档:访问 alova.js.org 获取详细教程。
  • GitHub:查看 alova 源码和示例。
  • 社区:加入 GitHub Discussions 或 Discord,与开发者交流。

总结

Alova 通过声明式请求、响应式状态管理和内置策略,极大简化了 Vue 3 项目中的 API 交互。无论是简单的数据获取,还是复杂的分页、表单提交和文件上传,Alova 都能提供高效、优雅的解决方案。它的轻量级设计和 TypeScript 支持使其在现代前端开发中独具优势。