Service(服务)是一个在整个应用程序生命周期中存在的 Ember 对象,可以在应用程序的不同部分中使用。
服务对于需要共享状态或持久连接的功能非常有用。服务的应用示例可能包括:
- 用户/会话身份验证。
- 地理定位。
- WebSockets。
- 服务器推送事件或通知。
- 不适合 EmberData 的服务器后端 API 调用。
- 第三方 API。
- 日志记录。
定义服务
可以使用 Ember CLI 的 service 生成器来创建服务。例如,以下命令将创建 ShoppingCart 服务:
ember generate service shopping-cart
服务必须继承 Service 基类。
app/services/shopping-cart.js
import Service from '@ember/service';
export default class ShoppingCartService extends Service {
}
与任何 Ember 对象一样,服务会被初始化,并可以拥有自己的属性和方法。下面,购物车服务管理一个数组,该数组表示购物车中当前包含的项目。
app/services/shopping-cart.js
import Service from '@ember/service';
import { trackedArray } from '@ember/reactive/collections';
export default class ShoppingCartService extends Service {
items = trackedArray([]);
add(item) {
this.items.push(item);
}
remove(item)
this.items.splice(this.items.indexOf(item), 1);
}
empty() {
this.items.splice(0, this.items.length);
}
}
访问服务
要访问服务,可以使用 @ember/service 模块中的 service 装饰器将其注入到任何容器解析的对象中,例如组件或其他服务。有两种使用此装饰器的方法:您可以不带参数调用它,也可以向其传递服务的注册名称。当不传递参数时,服务将根据被装饰属性的名称进行加载。您可以像下面这样不带参数加载购物车服务。
app/components/cart-contents.gjs
import Component from '@glimmer/component';
import { service } from '@ember/service';
export default class CartContentsComponent extends Component {
// Will load the service defined in: app/services/shopping-cart.js
@service shoppingCart;
<template>
<h2>Shopping Cart</h2>
</template>
}
这会将购物车服务注入到组件中,并使其作为 shoppingCart 属性可用。
注入服务的另一种方法是将服务的名称作为参数传递给装饰器。
app/components/cart-contents.gjs
import Component from '@glimmer/component';
import { service } from '@ember/service';
export default class CartContentsComponent extends Component {
// Will load the service defined in: app/services/shopping-cart.js
@service('shopping-cart') cart;
<template>
<h2>Shopping Cart</h2>
</template>
}
这会将购物车服务注入到组件中,并使其作为 cart 属性可用。
有时服务可能存在也可能不存在,例如当初始化器有条件地注册服务时。由于正常的注入在服务不存在时会抛出错误,因此您必须改用 Ember 的 getOwner 来查找该服务。
app/components/cart-contents.gjs
import Component from '@glimmer/component';
import { getOwner } from '@ember/application';
export default class CartContentsComponent extends Component {
// Will load the service defined in: app/services/shopping-cart.js
get cart() {
return getOwner(this).lookup('service:shopping-cart');
}
<template>
<h2>Shopping Cart</h2>
</template>
}
注入的属性是懒加载的;这意味着除非显式调用该属性,否则不会实例化该服务。
一旦加载,服务将一直持续到应用程序退出。
注入到组件后,服务也可以在模板中使用。
下面我们为 cart-contents 组件添加一个删除操作。
app/components/cart-contents.gjs
import Component from '@glimmer/component';
import { service } from '@ember/service';
import { on } from '@ember/modifier';
import { fn } from '@ember/helper';
export default class CartContentsComponent extends Component {
@service('shopping-cart') cart;
remove = (item) => {
this.cart.remove(item);
};
<template>
<h2>Shopping Cart</h2>
<ul>
{{#each this.cart.items as |item|}}
<li>
{{item.name}}
<button type="button" {{on "click" (fn this.remove item)}}>Remove</button>
</li>
{{/each}}
</ul>
</template>
}