Component 的状态和交互

Component 的 template 决定 UI 的静态模型,Component 的 JavaScript 可以为 UI 提供交互式操作(Event)和数据(State),联结二者的是 action:可以在 template 中使用的 JavaScript 方法, 形如:

<button type="button" {{on "click" this.increment}}>+1</button>

Component 的状态

状态就是 component 的属性,这些属性会随着 component 的变化而变化,有些属性会以 UI 的形式呈现给用户,也就是当属性发生变化时,UI 会及时变化反馈出阿里,这种通过跟踪属性状态改变 UI 的能力在 ember 中叫 autotrack ,实现 autotrack 能力的属性叫 tracked propertiy

app/components/counter.js


import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';

export default class CounterComponent extends Component {
  @tracked count = 0;
}

上述例子中的 count 中具有了 autotrack 的能力,当 autotrack 值发生改变时,对应 template 中的值也会发生变化,比如 count 的值发生改变时,template 中的值也会发生改变:

app/components/counter.hbs


<p>{{this.count}}</p>

<button type="button">+1</button>
<button type="button">-1</button>

Ember 通过 this 来区分属性是来自 component argument 还是 component 自身,属于 component 自身的属性通过 this 来获取。

改变 Component 的状态

State 提供了 component 静态的数据,action 提供了改变 state 的能力,想要在 template 中使用 action,就需要借助 HTML modifier:

app/components/counter.hbs

<p>{{this.count}}</p>
<button type="button" {{on "click" this.increment}}>+1</button>
<button type="button" {{on "click" this.decrement}}>-1</button>

on 是 ember 内建的一个 mofidier,用来把 event 绑定到 HTML tag。

app/components/counter.js


import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';


export default class CounterComponent extends Component {
  @tracked count = 0;

  @action
  increment() {
    this.count = this.count + 1;
  }

  @action
  decrement() {
    this.count = this.count - 1;
  }
}

而 action 就是很普通的用 action 装饰的 JavaScript 方法。

为 action 提供参数

有时候直接使用 action 并不能满足需要,还需要为 action 提供参数来实现更复杂的交互能力,ember 使用 fn modifier 来实现对 action 传递参数:

app/components/counter.js


import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';


export default class CounterComponent extends Component {
  @tracked count = 0;

  @action
  change(amount) {
    this.count = this.count + amount;
  }
}

app/components/counter.hbs

<p>{{this.count}}</p>
<button type="button" {{on "click" (fn this.change 1)}}>+1</button>
<button type="button" {{on "click" (fn this.change -1)}}>-1</button>

fn 的含义就是把参数和 action 重新再包装成一个函数来使用。

计算属性

Computed value 是 ember 提供的一种以声明式编程的方式动态计算属性的能力,通过这种能力,如果某个 state 的改变要依赖其他 state,只要被依赖的 state 具有 autotrack 能力,那么该 state 也会在被依赖的 state 发生变化时而改变,下面的例子中,total 这个属性依赖 count 和 multiple,通过 get 来实现根据 count 和 multiple 的依赖计算 total

app/components/counter.js


import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';


export default class CounterComponent extends Component {
  @tracked count = 0;
  @tracked multiple = 1;


  @action
  double() {
    this.multiple = this.multiple * 2;
  }


  get total() {
    return this.count * this.multiple;
  }


  @action
  change(amount) {
    this.count = this.count + amount;
  }
}

app/components/counter.hbs

<p>{{this.count}}</p>
<p>{{this.total}}</p>
<button type="button" {{on "click" (fn this.change 1)}}>+1</button>
<button type="button" {{on "click" (fn this.change -1)}}>-1</button>
<button type="button" {{on "click" double}}>double</button>

在 JavaScript 中使用 component arguments

在前文中,我们讲过在 template 中通过 @ 来获取 component arguments,同理 JavaScript 中也提供了通过 this.args 来获取 argument 的能力,这就意味着 component 之间有了相互沟通的能力。

app/components/double-it.js


import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';

export default class DoubleItComponent extends Component {
  @tracked multiple = 1;

  @action
  updateMultiple(newMultiple) {
    this.multiple = newMultiple;
  }
}

app/components/double-it.hbs

<Counter @multiple={{this.multiple}} @updateMultiple={{this.updateMultiple}} />

app/components/counter.js

import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';

export default class CounterComponent extends Component {
  @tracked count = 0;

  get total() {
    return this.count * this.args.multiple;
  }

  @action
  change(amount) {
    this.count = this.count + amount;
  }

  @action
  double() {
    this.args.updateMultiple(this.args.multiple * 2);
  }
}

`
© 三月沙 all right reserved,powered by GitbookUpdated at 2022-02-27 14:28:29

results matching ""

    No results matching ""