Vue 3是否支持实现类似Angular-Services的服务机制?
Vue3 原生支持实现这类跨组件共享的响应式服务,不需要额外hack手段,核心是利用独立于组件树的响应式单例实现状态共享,任意组件修改状态后,所有引用该状态的组件视图都会自动同步更新。
实现方案
轻量场景:独立响应式单例(零依赖)
你只需要把要共享的对象/数组用reactive包裹,在单独的文件中导出为单例,所有组件引入同一份实例即可,修改时所有引用的组件视图会自动同步,和AngularJS服务的行为完全一致。
- 先创建独立的服务文件,比如
src/services/todoService.ts:
import { reactive } from 'vue' // 全局单例响应式数组,所有引入的组件共享同一份状态 export const todoList = reactive<Array<{id: number, content: string, done: boolean}>>([ {id: 1, content: '迁移AngularJS旧服务', done: false} ]) // 封装状态操作方法,和AngularJS服务的方法逻辑完全对齐 export function addTodo(content: string) { todoList.push({ id: Date.now(), content, done: false }) } export function toggleTodo(id: number) { const target = todoList.find(item => item.id === id) if (target) target.done = !target.done } export function deleteTodo(id: number) { const idx = todoList.findIndex(item => item.id === id) if (idx > -1) todoList.splice(idx, 1) }
- 任意组件直接引入使用即可,比如组件A负责新增数据:
<!-- 组件A:新增待办 --> <script setup lang="ts"> import { ref } from 'vue' import { addTodo } from '@/services/todoService' const inputVal = ref('') const handleAdd = () => { if (!inputVal.value.trim()) return addTodo(inputVal.value) inputVal.value = '' } </script> <template> <div> <input v-model="inputVal" placeholder="输入待办内容" /> <button @click="handleAdd">添加</button> </div> </template>
组件B负责展示、操作列表:
<!-- 组件B:展示待办列表 --> <script setup lang="ts"> import { todoList, toggleTodo, deleteTodo } from '@/services/todoService' </script> <template> <ul> <li v-for="item in todoList" :key="item.id"> <input type="checkbox" :checked="item.done" @change="toggleTodo(item.id)" /> <span :style="{textDecoration: item.done ? 'line-through' : 'none'}">{{ item.content }}</span> <button @click="deleteTodo(item.id)">删除</button> </li> </ul> </template>
这种方案的特点:
- 零额外依赖,代码量极小
- 支持所有响应式操作:数组的
push/splice等变更方法、数组内对象的属性修改、深层嵌套属性修改都能自动触发视图更新 - 逻辑可以完全按照你之前AngularJS服务的组织方式编写,迁移成本极低
中大型项目:Pinia状态管理
如果你的共享状态逻辑复杂,需要状态变更追踪、持久化、模块化拆分、权限控制等能力,直接用Vue官方推荐的Pinia即可,它本质就是基于Vue响应式系统封装的全局状态方案,完全匹配你的需求。
- 安装依赖后在入口文件注册:
import { createApp } from 'vue' import { createPinia } from 'pinia' import App from './App.vue' const app = createApp(App) app.use(createPinia()) app.mount('#app')
- 创建对应服务的状态模块:
// src/stores/todo.ts import { defineStore } from 'pinia' export const useTodoStore = defineStore('todo', { state: () => ({ list: [] as Array<{id: number, content: string, done: boolean}> }), actions: { addTodo(content: string) { this.list.push({id: Date.now(), content, done: false}) }, toggleTodo(id: number) { const target = this.list.find(item => item.id === id) if (target) target.done = !target.done }, deleteTodo(id: number) { this.list = this.list.filter(item => item.id !== id) } } })
组件中引入调用即可,所有状态修改会全局同步,同时支持在Vue Devtools中追踪每一次状态变更,调试效率更高。
注意:如果需要在组件中解构共享的响应式状态,请用
toRefs包裹后再解构,否则会丢失响应性。

内容的提问来源于stack exchange,提问作者mmyta
相关产品推荐
相关产品推荐

