【问题标题】:What's the equivalent of Angular Service in VueJS?VueJS 中的 Angular 服务等价物是什么?
【发布时间】:2017-05-01 02:03:55
【问题描述】:

我想将所有与服务器通信并获取数据的函数放入 VueJS 中的单个可重用文件中。

插件似乎不是最好的选择。无模板组件..?

【问题讨论】:

    标签: service vue.js vuejs2


    【解决方案1】:

    我使用axios 作为 HTTP 客户端进行 api 调用,我在我的 src 文件夹中创建了一个 gateways 文件夹,并且我为每个后端放置了文件,创建了 axios instances,如下所示

    myApi.js

    import axios from 'axios'
    export default axios.create({
      baseURL: 'http://localhost:3000/api/v1',
      timeout: 5000,
      headers: {
        'X-Auth-Token': 'f2b6637ddf355a476918940289c0be016a4fe99e3b69c83d',
        'Content-Type': 'application/json'
      }
    })
    

    现在在您的组件中,您可以拥有一个从 api 获取数据的函数,如下所示:

    methods: {
     getProducts () {
         myApi.get('products?id=' + prodId).then(response =>  this.product = response.data)
      }
    }
    

    我假设你想在多个组件中重复使用这个方法,你可以使用 vue.js 的mixins

    Mixins 是一种为 Vue 组件分配可重用功能的灵活方式。 mixin 对象可以包含任何组件选项。当组件使用 mixin 时,mixin 中的所有选项都会“混合”到组件自己的选项中。

    所以你可以在 mixin 中添加一个方法,它将在所有组件中都可用,其中 mixin 将被混合。请参见以下示例:

    // define a mixin object
    var myMixin = {
      methods: {
         getProducts () {
             myApi.get('products?id=' + prodId).then(response =>  this.product = response.data)
          }
      }
    }
    
    // define a component that uses this mixin
    var Component = Vue.extend({
      mixins: [myMixin]
    })
    
    // alternate way to have a mixin while initialising
    new Vue({
      mixins: [myMixin],
      created: function () {
        console.log('other code')
      }
    })
    

    【讨论】:

    • 用户登录时如何更新 myApi.js 的 X-Auth-Token
    • 通常这不是静态值
    • 这不能回答 OP 的问题。我很惊讶它得到了如此多的支持。正确答案是 Otabek Kholikov 的答案
    【解决方案2】:

    总共有4种方式:

    • 无状态服务:那么你应该使用 mixins
    • 有状态服务:使用 Vuex
    • 从 vue 代码导出服务和导入
    • 任何 javascript 全局对象

    【讨论】:

    • 当您可以创建一个包含状态和逻辑的 TypeScript/JS 类时,尝试并坚持使用字符串文字调用服务方法的 Vuex 古怪似乎很尴尬?如何在 Vue 中使用有状态类作为服务?
    • VueX 对于需要与组件以外的上下文/与多个组件共享的前端来说不是一个好的解决方案。 Angular (2.x+) 服务是一个完美的例子,说明如何在没有不必要的复杂性和过度设计的情况下实现这一目标。
    【解决方案3】:

    我主要使用 Vue 资源。

    1.我创建了一个新文件,我使用Vue.http.xxx连接到API端点。假设我们有输出帖子的端点。在你的项目中创建新目录,我称之为services,然后创建文件称为PostsService.js - 内容如下所示:

    import Vue from 'vue'
    
    export default {
      get() {
        return Vue.http.get('/api/posts)
      }
    }
    

    然后我去我想使用这个服务的组件,并导入它

    import PostsService from '../services/PostsService'
    
    export default {
      data() {
       return {
         items: []
       }
      },
      created() {
       this.fetchPosts()
      },
      methods: {
       fetchPosts() {
        return PostsService.get()
          .then(response => {
            this.items = response.data
          })
       }
      }
    }
    

    有关此方法的更多信息,请随时查看我在 GitHub 上的 repo https://github.com/bedakb/vuewp/tree/master/public/app/themes/vuewp/app

    【讨论】:

    • 根据 Evan You 的说法,Vue-Resource 将退休并推荐 Axios。 Read his article我真的很喜欢你的方法,感觉更像是 angular 2
    • @noypee VueResource 仍然有效。但没关系使用你想要的,它与 Axios 完全相同。
    • 是的,根据他的文章,Vue2 也将继续容纳 vue-resource
    • 这很好,但是如何使用 mock-PostsService 测试这样的组件?
    • @noypee,vue-resource 没有退休——Evan 说他只是 "retiring it from official recommendation status"。他进一步澄清了为什么他的团队得出结论认为不再需要官方 AJAX 库。链接的文章很好地解释了它。需要注意的是,vue-resource 仍在积极维护中,是一个完全可行的选择。
    【解决方案4】:

    我认为对于您的简单问题,答案可能是任何包含函数的 ES6 模块(相当于 Angular 中的类中的方法)并使用 ES6 导入和导出直接将它们导入到组件中。没有可以在组件中注入的此类服务。

    【讨论】:

      【解决方案5】:

      我建议创建一个 API Provider,您可以从应用中的任何位置访问它。

      只需创建一个src/utils 文件夹,并在其中创建一个名为api.js 的文件。

      在其中,将知道如何与 API 通信的包装器导出为对象或 ES6 静态类(如果您不害怕类,我更喜欢后者的外观和工作方式)。该提供程序可以使用您喜欢的任何 HTTP 请求库,并且您可以稍后通过更改单个文件(这个文件)轻松交换它,而不是寻找整个代码库。下面是一个使用 axios 的示例,假设我们在 api.example.com/v1 有一个使用 SSL 的 REST API:

      import axios from 'axios'
      
      import { isProduction, env } from '@/utils/env'
      
      const http = null // not possible to create a private property in JavaScript, so we move it outside of the class, so that it's only accessible within this module
      
      class APIProvider {
        constructor ({ url }) {
          http = axios.create({
            baseURL: url,
             headers: { 'Content-Type': 'application/json' }
          })
        }
      
        login (token) {
          http.defaults.headers.common.Authorization = `Bearer ${token}`
        }
      
        logout () {
          http.defaults.headers.common.Authorization = ''
        }
      
        // REST Methods
        find ({ resource, query }) {
          return http.get(resource, {
            params: query
          })
        }
      
        get ({ resource, id, query }) {
          return http.get(`${resource}/${id}`, {
            params: query
          })
        }
      
        create ({ resource, data, query }) {
          return http.post(resource, data, {
            params: query
          })
        }
      
        update ({ resource, id, data, query }) {
          return http.patch(`${resource}/${id}`, data, {
            params: query
          })
        }
      
        destroy ({ resource, id }) {
          return http.delete(`${resource}/${id}`)
        }
      }
      
      export default new APIProvider({
        url: env('API_URL')  // We assume 'https://api.example.com/v1' is set as the env variable
      })
      

      接下来,在您的 main.js 文件或您引导 Vue 应用程序的其他任何地方,执行以下操作:

      import api from '@/src/utils/api'
      
      Vue.$api = api
      
      Object.defineProperty(Vue.prototype, '$api', {
        get () {
          return api
        }
      })
      

      现在您可以在您的 Vue 应用程序中的任何位置以及您导入 Vue 本身的任何位置访问它:

      <template>
        <div class="my-component">My Component</div
      </template>
      
      <script>
      export default {
        name: 'MyComponent',
        data () {
          return {
            data: []
          }
        },
        async created () {
          const response = await this.$api.find({ resource: 'tasks', query: { page: 2 } })
      
          this.data = response.data
        }
      }
      </script>
      

      或:

      // actions.js from Vuex
      import Vue from 'vue'
      
      export async function fetchTasks ({ commit }) {
        const response = await Vue.$api.find({ resource: 'tasks', query: { page: 2 } })
      
        commit('SAVE_TASKS', response.data)
      
        return response
      }
      

      希望这会有所帮助。

      【讨论】:

      • 仅供参考 .$api 部分,在 TS 中您需要执行 (Vue.prototype as any).$api = yourobject;。此外,关于该功能的 v2 文档在这里:vuejs.org/v2/cookbook/adding-instance-properties.html
      • 我必须说这个模型在你想要全局访问服务的情况下非常优雅。
      • 当 http 是 const 时,你如何分配?
      【解决方案6】:

      您可以创建自己的服务,您可以在其中放置所有 HTTP 服务器调用,然后将其导入到您想要使用它们的组件中。

      最好将 Vuex 用于复杂的状态管理应用程序,因为在 Vuex 中,您可以通过始终异步运行的操作来处理所有异步调用,然后在获得结果后提交突变。突变将直接与状态交互并将以不可变的方式更新它(这是首选)。这是有状态的方法。

      还有其他方法。但这些是我在代码中遵循的。

      【讨论】:

        猜你喜欢
        • 2022-07-27
        • 2021-03-26
        • 2013-06-16
        • 1970-01-01
        • 2016-11-02
        • 2014-10-09
        • 2019-12-23
        • 2016-04-06
        • 2013-09-07
        相关资源
        最近更新 更多