# @kaokei/use-vue-service > Lightweight Vue 3 state management with dependency injection, inspired by Angular services. 本库基于 [@kaokei/di](https://github.com/kaokei/di) 开发,通过依赖注入实现面向服务编程和领域驱动开发,可以代替 vuex/pinia。 - 版本:4.0.5 - 许可证:MIT - GitHub:https://github.com/kaokei/use-vue-service - npm:https://www.npmjs.com/package/@kaokei/use-vue-service - 文档站点:https://use-vue-service.kaokei.com ## 安装 ```sh npm install @kaokei/di @kaokei/use-vue-service ``` 不依赖 reflect-metadata。使用 TC39 Stage 3 标准装饰器语法,TypeScript 5.0+ 默认支持,无需配置 experimentalDecorators。 ## 核心概念 本库将 Angular 的"服务 + 依赖注入"模式引入 Vue 3。通过类来声明服务,利用 Vue 的 provide/inject 机制在组件树中传递 DI 容器,实现服务的声明、注入和共享。 服务实例会自动被 `reactive()` 包裹,天然具备 Vue 响应式能力。本库采用 opt-out 响应式策略:所有属性默认响应式,只有需要排除的属性才使用 `@Raw` 标记。 ## 三组核心 API 三组 API 背后的容器存在继承关系:**根容器 → App 容器 → 组件容器**。 ### 组件级:useService / declareProviders - `declareProviders(providers)` — 在当前组件创建子容器,组件卸载时自动销毁 - `useService(token)` — 从当前组件或最近祖先组件的容器中获取服务实例,最终可回退到 App 容器,再回退到根容器 ### 全局根级:useRootService / declareRootProviders - `declareRootProviders(providers)` — 在全局根容器上声明服务,全局共享 - `useRootService(token)` — 只从全局根容器中获取服务实例,不查找其他容器 ### App 级:useAppService / declareAppProviders / declareAppProvidersPlugin - `declareAppProviders(providers, app)` — 在指定 App 实例上声明服务 - `useAppService(token, app)` — 从 App 容器获取服务,可回退到根容器,不查找组件容器 - `declareAppProvidersPlugin(providers)` — 返回 Vue 插件,用于 `app.use()` **注意**:`declareAppProviders` 和 `useAppService` 都需要显式传入 `app` 实例作为第二个参数,实践中几乎没有场景会把 `app` 传递到组件内部,因此这两个 API 基本不会在组件 setup 中使用。需要声明 App 级服务时,推荐在 `main.ts` 中使用 `declareAppProvidersPlugin` 插件形式。 ## 常见误用 **误用一:在组件 setup 中使用 `declareAppProviders` 或 `useAppService`** 这两个 API 需要 `app` 参数,组件 setup 内通常没有 `app` 对象。正确做法:在 `main.ts` 中通过 `app.use(declareAppProvidersPlugin([...]))` 声明,然后在组件内通过 `useService` 获取。 **误用二:在组件内用 `useRootService` 获取根容器服务** `useRootService` 并非 `declareRootProviders` 在组件内的专属配对 API。`useService` 的查找链最终也会回退到根容器,**组件内应统一使用 `useService`**,无需区分服务是通过哪组 `declare*` 声明的。 只有极少数情况才需要在组件内使用 `useRootService`:同一个 token 被多组 `declare*` 重复绑定,`useService` 因就近原则无法取到根容器中的实例时,才需要明确指定从根容器获取。 ## 装饰器 ### @Computed 将 getter 属性转换为 Vue computed 响应式计算属性。支持 `@Computed` 和 `@Computed()` 两种用法。采用懒创建策略,如果存在同名 setter 则自动创建 writable computed。 ### @Raw 标记属性或整个类不参与 Vue 响应式追踪,自动调用 markRaw。支持两种调用形式(`@Raw` 和 `@Raw()`)和三种装饰目标: - field 装饰器:`@Raw public chart = {}` — 初始值和后续赋值均自动 markRaw - accessor 装饰器:`@Raw accessor chart = {}` — 读写均经由原始对象(toRaw) - class 装饰器:`@Raw class RawService {}` — 整个实例不被 `reactive()` 包裹 ### @RunInScope 在 EffectScope 中运行方法,自动管理副作用生命周期。返回 Child_Scope 供手动停止。注意:**不会自动调用**被装饰的方法,需用户主动调用才会生效。 ### @autobind 方法装饰器,将方法绑定到 `reactive(this)`(Vue 响应式兼容版),确保解构/`setTimeout`/`Promise.then` 等场景下 `this` 始终指向 reactive proxy。仅支持无括号调用(`@autobind`),兼容 `@Raw` 装饰器。 ## Token 常量 这两个 Token 用于在**子孙容器树**中查找指定 token 对应的服务实例,查找方向与 `useService` 相反。注意:查找基于容器树而非组件树,查找起点是调用方实际拿到的容器所在节点(可能是祖先组件的容器)。 - `FIND_CHILD_SERVICE` — 查找子孙容器树中绑定了指定 token 的第一个服务实例(Token) - `FIND_CHILDREN_SERVICES` — 查找子孙容器树中绑定了指定 token 的所有服务实例(Token) ## 从 @kaokei/di 重新导出的 API 本库通过 `export * from '@kaokei/di'` 重新导出了 @kaokei/di 的所有 API,包括: - `@Inject` — 属性注入装饰器 - `@PostConstruct` — 实例化后自动执行的生命周期方法装饰器 - `Token` — 创建自定义 token - `LazyToken` — 延迟解析 token,用于解决循环依赖 - `Container` — DI 容器类 ## 详细文档 - [快速开始](https://github.com/kaokei/use-vue-service/blob/main/docs/guide/index.md) - [API 文档](https://github.com/kaokei/use-vue-service/blob/main/docs/api/index.md) - [完整 LLM 文档](https://use-vue-service.kaokei.com/llms-full.txt)