ChatGPT解决这个技术问题 Extra ChatGPT

What's the equivalent of Angular Service in VueJS?

I want to put all my functions that talk to the server and fetch data into a single reusable file in VueJS.

Plugins don't seem to be the best alternative. Template less components..?


M
Mirco Widmer

In total there are 4 ways:

Stateless service: then you should use mixins

Stateful service: use Vuex

Export service and import from a vue code

any javascript global object


It seems very awkward to try and adhere to the Vuex oddities of calling methods with string literals for services when you could make a TypeScript/JS class that contains the state and logic for it? How can you use a stateful class as a service within Vue?
VueX is not a good solution to frontends that require a context other than a component/to be shared with multiple components. The Angular (2.x+) Service is a perfect example of how to accomplish this without needless complexities and over-engineering.
t
tony19

I am using axios as HTTP client for making api calls, I have created a gateways folder in my src folder and I have put files for each backend, creating axios instances, like following

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'
  }
})

Now in your component, You can have a function which will fetch data from the api like following:

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

As I assume you want to re-use this method in multiple components, you can use mixins of vue.js:

Mixins are a flexible way to distribute reusable functionalities for Vue components. A mixin object can contain any component options. When a component uses a mixin, all options in the mixin will be “mixed” into the component’s own options.

So you can add a method in mixin and it will be available in all the components, where mixin will be mixed. See following example:

// 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')
  }
})

how will you update X-Auth-Token of myApi.js when user will login
usually this is not a static value
This does not answer the OP's question. Im surprised it's been upvoted so much. The correct answer is the one by Otabek Kholikov
B
Belmin Bedak

I'm using Vue Resource mostly.

1.I create new file where I do connection to API endpoint using Vue.http.xxx.So let's say we have endpoint that output the posts.Create new directory in your project, I call it services, and then create file called PostsService.js - content looks like this:

import Vue from 'vue'

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

Then I go to component where I want use this service, and import it

import PostsService from '../services/PostsService'

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

For more info about this approach, feel free to check my repo on GitHub https://github.com/bedakb/vuewp/tree/master/public/app/themes/vuewp/app


According to Evan You, Vue-Resource will be retiring and recommends Axios instead. Read his article I really like your approach which feels more like angular 2
@noypee VueResource still works.But never mind use what you want, it would be exactly same approach with Axios.
Yes, Vue2 will continue to accommodate vue-resource as well per his article
This is very nice but how to test such a component with mock-PostsService?
@noypee, vue-resource is not being retired -- Evan stated that he is merely "retiring it from official recommendation status". He further clarified why his team concluded that there was no longer a need for an official AJAX library. The linked article explains it well. And it should be noted that vue-resource is still actively maintained and a perfectly viable option.
t
techiedod

I suggest creating an API Provider that you can access from anywhere in your app.

Simply create a src/utils folder and inside of it a file called api.js.

In it, export your wrapper that knows how to communicate with your API as an object or a ES6 static class (I prefer how the latter looks and works if you're not afraid of classes). This provider can use any HTTP request library that you like and you can easily swap it later by changing a single file (this one) instead of hunting down the whole codebase. Here's an example of using axios, assuming we have a REST API available at api.example.com/v1 that uses SSL:

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
})

Next, in your main.js file or wherever else you bootstrap the Vue app, do the following:

import api from '@/src/utils/api'

Vue.$api = api

Object.defineProperty(Vue.prototype, '$api', {
  get () {
    return api
  }
})

Now you can access it anywhere in your Vue app as well as anywhere you import Vue itself:

<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>

or:

// 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
}

Hope this helps.


FYI for the .$api part, in TS you'll need to do (Vue.prototype as any).$api = yourobject;. Also, v2 docs about that functionality are here: vuejs.org/v2/cookbook/adding-instance-properties.html
I must say this model is quite elegant in situation where you want global access of a service.
how do you assign to http when it is a const?
S
Sourabh Ranka

I think for your simple question the answer could be any ES6 module containing functions (equivalent to methods in class in ANgular) and directly importing them in components using ES6 imports and exports. There are no such services that could be injected in components.


s
slfan

You can make your own service where you can place all your HTTP server calls and then import that to the components where you want to use them.

Best is to make use of Vuex for complex state management applications because in Vuex you are able to handle all async calls via actions which always run asynchronously and then commit the mutation once you have the result.Mutation will directly interact with the state and will update it in an immutable manner (which is preferred). This is stateful approach.

There are other approaches as well. But these are the ones which I follow in my code.