簡體   English   中英

Vue 3 是否支持 Angular-Services 之類的東西?

[英]Does Vue 3 support something like Angular-Services?

我正在將一個項目從 AngularJs 移植到 Vue3。 在 Angular 中,我們有一個服務組件,它為組件創建和提供對象。 如果在組件的綁定中使用這些對象,它們會自動響應。 如果組件 A 更改了一個對象,組件 B 的視圖會立即顯示狀態的更改。

AngularJs 中的組件和對象

有沒有辦法在 Vue3 中完成這樣的服務? 目標是,維護一個對象數組,並且對數組的每一次更改都會反映在不同組件的視圖中。

區別:Vue VS AngularJS

Vue 是一個 UI 框架,它沒有專門的服務實體,由開發人員來實現它們。 同樣與 Angular 不同的是,Vue 不提供依賴注入(DI) 功能。

Vue 中的可組合作為服務

在 Vue 中,可重用的組件代碼應該由可組合可組合函數提供,它們的反應性是通過組合 API 實現的:

// Usage: service = useLocalService()
const useLocalService = () => {
  const someState = reactive({});
  const someAction = () => /* change state */;
  return { someState, someAction }
};
  

在 Vue 中提供/注入來共享服務(比較 DI)

對於 Angular 中固有的全局單例服務,服務狀態在模塊中定義並評估一次,因此它在應用程序中共享:

// Usage: import * as service from '...';
export const someGlobalState = reactive({});
export const someGlobalAction = () => /* change state */;

將其包裝在可組合函數中以保持一致性是否有益取決於以下情況:

// Usage: service = useGlobalService()
const someGlobalState = reactive({});
const someGlobalAction = () => /* change state */;

const useGlobalService = () => {
  return { someGlobalState, someGlobalAction }
};

在 Angular 2 或更高版本中,DI 容器允許為每個組件層次結構提供服務實例。 在 Vue 中,這是通過provide / inject來完成的:

// Usage in a parent: setupRootOrNestedService()
const setupRootOrNestedService = () => {
  const someRootOrNestedState = reactive({});
  const someRootOrNestedAction = () => /* change state */;
  
  provide('rootOrNestedService', { someRootOrNestedState, someRootOrNestedState });
};

// Usage in a child: service = useRootOrNestedService()
const useRootOrNestedService = () => {
  return inject('rootOrNestedService');
};

這允許在任何級別通過令牌識別服務,並從使用 DI 模式中受益。

松樹

Pinia (一個 Vue 商店)庫提供受Flux 模式影響的輕量級狀態管理。 它依賴於組合 API 並允許多個商店。 結果與上面類似,增加了代碼約定、擴展的 Vue 開發工具、正確的 TypeScript 類型和插件層:

// Usage as local service: service = useLocalOrGlobalService()
// Usage as global service: export default useLocalOrGlobalService()
// And: import * as service from '...';
const useLocalOrGlobalService = () => {
  return defineStore('localOrGlobalService' + random(), {
    state: () => ({}),
    actions: {
      someAction() { /* change state */ }
    }
  })
};  

Pinia 不限制將 store 實例化並提供給組件的方式,因此它可以在必要時與provide / inject結合使用。

僅供記錄:這是我想出的,作為簡單的示例代碼。 首先我寫了一個小服務:

import { reactive } from "vue";
export const objectService = {
    objects: reactive([]), // reactive is important, otherwise it doesn't work
    start: function(){
        for (var i = 0; i < 10; i++)
            ((j)=>{
                setTimeout(()=> // I use setTimeout as example for an async operation
                    objectService.objects.push({value: j}), 1000);
            })(i);
    }
};

這里的重點是,服務在異步操作中操縱狀態(在真實的實時系統中,休息調用或對 indexedDb 的訪問等)。

現在有兩個組件在兩個獨立的 Vue 應用程序中運行。 它們在單獨的應用程序中運行的原因超出了這里的問題范圍。 應用程序1:

<template>
<!--App1.vue-->
<p>Here is App1</p>
<div v-for="obj,ix in objectService.objects" :key="ix">{{obj.value}}
    <input v-model="obj.value" />
</div>
</template>

<script>
import { defineComponent } from 'vue';
import { objectService } from '../services/object-service.js';

const App1 = defineComponent({
    setup() {
        return { objectService };
    },
})

export default App1;
</script>

應用 2:

<template>
<!--App2.vue-->
<p>Here is App2</p>
<div v-for="obj,ix in objectService.objects" :key="ix">{{obj.value}}
    <input v-model="obj.value" />
</div>
</template>

<script>
import { defineComponent } from 'vue';
import { objectService } from '../services/object-service.js';

const App2 = defineComponent({
    setup() {
        // const os = objectService;
        objectService.start();
        return { objectService };
    },
})

export default App2;
</script>

這兩個組件是相同的,但有一個例外:App2 調用服務的啟動方法。 結果顯示在兩個組件中。 並且每個組件都可以改變狀態,這會立即反映在另一個組件中。

整個解決方案的重點是在服務中使用 reactive({})。 我希望,這對某人有用。

再次感謝 Estus Flask 和 hc_dev 為我指明了正確的方向。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM