ChatGPT解决这个技术问题 Extra ChatGPT

Vue.js: define a service

I'm looking at Vue.js as an alternative to Angular and I really like it so far. To get a feeling for it, I'm refactoring an existing Angular project to a Vue project. I'm just at the point where I need to communicate with my REST API.

In Angular I used to define a service for that, that was injected into every controller that needed it. Vue doesn't seem to know the "service" construct as I understand. How can this be achieved in Vue?

I considered vue-resource, but it's only for http functionalities as far as I understand. As I use jQuery too, this is obsolete.

Example:

I have vueComponent1 and vueComponent2. Both need access to the same REST resource. To handle this I want a central service, which both of the components can use for requests to the REST resource. Angular has the 'service' component, which exactly does that. Vue hasn't.

Provide a concrete example of what you need. http is sufficient to communicate with REST
Have a look at vue-resource: github.com/vuejs/vue-resource

M
Marc

From the Vue.js documentation.

Vue.js itself is not a full-blown framework - it is focused on the view layer only.

As a library focusing on the V out of MVC it does not provide things like services.

Are you using some kind of module loader like Browserify or Webpack? Then you can leverage the module system of ES6 to create a service all by yourself. All you have to do is to create a plain JavaScript class which is being exported by this new module.

An example could look like this:

export default class RestResource {

  sendRequest() {
    // Use vue-resource or any other http library to send your request
  }

}

Inside your vue component 1 and 2 you can use this service by importing the class.

import RestResource from './services/RestResource';

const restResourceService = new RestResource();

restResourceService.sendRequest();

Thanks for the quote. This means there is no structure or anything beneath view and model. If I want to have a service, I need to build my own one e.g. using pure JS.
I'm getting movieslist.vue?1be4:38Uncaught TypeError: _resource.Resource is not a constructor when I use this...
You are missing one significant difference to what you'd expect with an Angular background. The "service" is instantiated multiple times in this case, while in shared service injection, only one instance is passed
Yeah, you get multiple instances of the same service in this way. That's not a problem when it just does an Ajax request (merely inefficient), but when you use the service for your data model, you need to instantiate it where you declare the service, and only export the instance.
If you want an 'Angular style' singleton service, you can simply create an instance of this class somewhere in your app, and export it: export const restResourceService = new RestResource(); and then import it wherever you wish. However, this is really creating a solution to a problem that we have created for ourselves - why not just use a function? export function sendRequest() { // Make the request } Finally, note that you do not necessarily even need a library for making a http request - depending on your project requirements you could simply use the JavaScript fetch API.
M
Max Oriola

You can export the instance of a class for your service:

export default new class {
   ...
}

In your component, or any other place, you can import the instance and you will always get the same one. This way it behaves similar to an injected Angular service, but without using this.

import myService from '../services/myservice';

Vue.component('my-component', {
  ...
  created: function() {
    myService.oneFunction();
  }
  ...
})

C
Community

From the Vue.js documentation on Building Large-Scale Apps.

The community has contributed the vue-resource plugin, which provides an easy way to work with RESTful APIs. You can also use any Ajax library you like, e.g. $.ajax or SuperAgent.

Vue doesn't require you to follow a specific architecture, since it only refers to the View layer in an MVC or MVVM architecture. As @Marc already said in his answer, a good practice is to use a module loader like Browserify or Webpack so you can create your "services" in separate files, importing they where you need. It's very easy to structure your app with a module loader using vue-cli.

Indeed, I personaly really like the Flux architecture for component based apps, then I recommend you to take a look at Vuex, a Flux-inspired application architecture that is designed specifically for managing state inside Vue.js apps.

This way, you can create Actions that use vue-resource to request your API, then you can dispatch Mutations when the data arrives, with all components that need that data already bound to the global State, reacting automatically. In other words, your components itself don't need to call the services, they just react to State changes dispatched by Mutations.


Just a note that vue-resource is no longer offically recommended. source
Check out the details: Retiring vue-resource written by Evan You
Axios is currently the recommended plugin to use instead of vue-resource.
A
Alexander

You have some very good answers to it in this question What's the equivalent of Angular Service in VueJS?

As @Otabek Kholikov says there - you have 4 options:

Stateless service: then you should use mixins Statefull service: use Vuex Export service and import from a vue code any javascript global object

In my projects I prefer (4). It gives me the maximum flexibility and has only the implementations I need (I don't bring for example Vuex and shouldn't be strict to its rules and there is no "magic" - all code is mine). You have an example of implementation in the Question I mentioned above.


t
tony19

If you're not using a module loader, you can define a custom plugin. Some example code:

var myPlugin = {
        install: function (Vue, options) {
            //private
            var myPrivateProperty = 'Private property';

            //instance properties and methods
            Vue.prototype.$myPublicProperty = 'Public Property';

            Vue.prototype.$myAddedMethod = function () {
                return myPrivateProperty;
            };
            Vue.prototype._getData = function (url) {
                return url;
            };

            //static properties and methods
            Vue.myStaticProperty = 'My static prop';
            Vue.myStaticMethod = function () {
                console.log('in');
            }
        }
    };

    Vue.use(myPlugin);

    new Vue({
        el: '#app',
        created: function () {
            //using instance
            console.log(this.$myAddedMethod());
            console.log('my get data: ' + this._getData('some url'));
            console.log(this.$myPublicProperty);

            //using static
            console.log(Vue.myStaticProperty);
            Vue.myStaticMethod();
        }
    });

You can also plug in other libraries, this post shows how to plug in axios.js


Do note that this will make your service accessible from any component, and by that logic, if you are using Vue router, especially on a static site generator, it will be accessible from every page. In rare edge cases, you may not want a service to be instantiated just yet, so you will have to figure out a different way to manage such a service. Reason for this is if your service holds any objects and your template references such objects in code, those objects need to be instantiated even before the "created" lifecycle method (you could control that with v-if on a root element).
@OzzyTheGiant What he said, surely. Haven't dealt with Vue since Blazor came out. (Not a sponsored comment :P )
W
Wallace Maxters

You can configure vue resource globally as

Vue.http.options.root = "your base url"

and now on every http call you can simply call by the name of resource -

this.$http.get('');
this.$http.get('users')

w
wolframhempel

You can specify Vue-Instance specific services upon creating the Vue instance

new Vue({
    el: '#app-container',
    myService: new MyService()
})

and access them from within your components as

this.$root.$options.myService.doStuff()

P
Pascal R.

Answer for 2022

For stateful services use the built-in Vue state management: https://vuejs.org/guide/scaling-up/state-management.html

Or Pinia (formerly Vuex) for advanced use cases: https://pinia.vuejs.org/