0

参考以下帖子StackOverflow 问题我有一个完全不同的场景,我想知道 Aurelia 是否有解决方案。

设想:

我有一个用户模型:

export class User{
    @bindable name: string;
    @bindable address: Address

如您所见,“地址”是一个子模型。

我有一个主视图模型“注册”。在这个视图模型中,我有一个模型“用户”:

export class RegistrationView{
    @bindable user: User

    public attached(){
        this.user = userService.fetchUserFromApi();
    }

除此之外,我还有一个自定义元素“用户地址”,其中我有一个“用户地址”模型(因为我想要专门封装的自定义元素)。

export class userAddress{
    @bindable userAddress: Address

现在我只想从 API 请求用户模型一次并将用户地址发送到自定义元素:

<template>
  <require from="user-address"></require>

  <user-address user.address.bind="${dj.address}"></user-address>

最后,如果用户已经加载,我将(拥有可以在任何地方使用的专用封装自定义元素)检查附加方法,如果没有,则自定义元素将加载所有需要的数据:

export class userAddress{
    @bindable userId: string
    @bindable address: Address

    public attached(){
        if(!(typeof this.address === "undefined")){
             this.address = this.addressAPIService.getAddressByUserId(id)
        }
    }
  1. 问题 1:我知道,上面提到的模板dj.address.bind不起作用。但现在我的问题是,我该如何处理这种情况?
  2. 问题 2:我如何保证用户对象只被请求一次?
  3. 我的概念有意义吗?这是否是 Aurelia 的想法?
4

1 回答 1

2

如果我正确理解您的问题,您只需要某种形式的客户端持久性。

如果即使在用户关闭浏览器后仍需要这种持久性,您将需要使用其中的一个localStorage或一些封装。有许多不错的插件可用,例如localForageLokiJS和最近开发的(仍处于测试阶段)aurelia 插件aurelia-store

您可能希望以UserService某种方式封装对用户的检索。这不是 Aurelia 特有的,只是一般情况下您希望在大多数类型的应用程序中执行此操作的方式。

例子

所以在你的视图模型中你可能有这样的东西(为了简洁,跳过一些实现细节,比如检查参数,配置路由器等):

@autoinject()
export class UserViewModel {
  public user: User;

  constructor(private userService: UserService){}

  // happens before bind or attached, so your child views will always have the user in time
  public async activate(params: any): Promise<void> {
    this.user = await this.userService.getUserById(params.id);
  }
}

在您的用户服务中:

// singleton will ensure this service lives as long as the app lives
@singleton() 
export class UserService {
  // create a simple cache object to store users
  private cache: any = Object.create(null); 

  constructor(private client: HttpClient) {}

  public async getUserById(id: number): Promise<User> {
    let user = this.cache[id];
    if (user === undefined) {
      // immediately store the user in cache
      user = this.cache[id] = await this.client.fetch(...);
    }
    return user;
  }
}

让您的视图模型变得愚蠢并在需要加载用户时调用 UserService,并让您的服务变得聪明并且仅在尚未缓存时从 API 中获取它。

我还想指出,这attached()不是您想要获取数据的时候。attached()是当你做 DOM 的事情(添加/删除元素、样式、其他装饰性的东西)的时候。bind()最好仅限于抓取/操作客户端上已有的数据。

那么什么时候获取数据呢?

在路由生命周期中的路由视图模型中。那将是configureRouter, canActivate,activate和。这些将在任何参与之前递归解决。canDeactivatedeactivateDOM

不在您的自定义元素中。或者你很快就会发现自己处于维护地狱中,通知机制和额外的绑定只是为了让组件可以让彼此知道“现在渲染是安全的,因为我有我的数据”。

如果您的自定义元素可以假设它们的数据一旦bind()出现,那么一切都会变得容易管理。

那么用户调用的 API 调用呢?

比您想象的更常见的是,您可以让操作成为路线而不是直接方法。您可以无限嵌套router-views 并且它们实际上不需要是页面,它们可以像您喜欢的那样细化。

当可以通过特定路径直接访问小的子视图时,它增加了很多可访问性。它为您提供了额外的钩子来处理授权、未保存更改的警告和排序,它为用户提供后退/前进导航等。

对于所有其他情况:

像往常一样从事件触发的方法调用服务activate(),除了通常路由器延迟页面加载直到数据存在,现在你必须为那个元素自己做。

最简单的方法是使用if.bind="someEntityThatCanBeUndefined". 该元素仅在该对象具有值时才会呈现。它不需要处理获取数据的基础设施。

于 2018-03-09T01:15:34.117 回答