Skip to content

Декоратор @watch

Andrey Kobets edited this page Jul 4, 2019 · 12 revisions

Декоратор @watch декларирует привязку метода или свойства к определенным событиям компонента. Если он применяется к методу, то можно задать список событий (или отслеживаемых свойств) при которых данный метод будет вызываться, а если декоратор применяется к отслеживаемому свойству, то можно указать название метода (или функцию), который будет вызываться при изменении этого свойства.

import iBlock, { component, field, watch } from 'super/i-block/i-block';
export * from 'super/i-block/i-block';

@component()
export default class bExample extends iBlock {
  @field()
  i?: number;

  // Функция будет вызываться каждый раз при изменении параметра i
  @watch('i')
  logI(value, oldValue) {
    console.log(`this.i was changed: ${value} (old value: ${oldValue})`);
  }

  // Каждые пол секунды увеличиваем значение i
  created() {
    super.created();
    this.async.setInterval(() => this.i++, 500);
  }
}

По умолчанию, вызываемый метод будет получать параметры события, т. е. при изменении наблюдаемого свойства будет передано новое и старое значение и т. д. Если декоратор добавлен к свойству и в качестве параметра передана функция, то первым параметром она будет принимать ссылку на сам компонент.

import iBlock, { component, field, watch } from 'super/i-block/i-block';
export * from 'super/i-block/i-block';

@component()
export default class bExample extends iBlock {
  // Если указать строку, то это будет названием вызываемого метода
  @watch('logI')
  @field()
  i?: number;

  // Или можно задать функцию
  @watch((o, value, oldValue) => {
    console.log(`this.j was changed: ${value} (old value: ${oldValue})`);
  })

  @field()
  j?: number;

  logI(value, oldValue) {
    console.log(`this.i was changed: ${value} (old value: ${oldValue})`);
  }

  created() {
    super.created();
    this.async.setInterval(() => {
      this.i++; 
      this.j++;
    }, 500);
  }
}

Наблюдение событий

Помимо изменений свойств декоратор @watch позволяет привязываться к различными событиям, например,

import iBlock, { component, field, watch } from 'super/i-block/i-block';
export * from 'super/i-block/i-block';

@component()
export default class bExample extends iBlock {
  // Метод будет вызываться каждый раз,
  // когда компонент будет испускать событие success
  @watch(':success')
  onSuccess(component, e) {
    console.log('Success!', e.status);
  }

  // Метод будет вызываться по клику на узел компонента:
  // символ ? в начале события означает, что событие должно быть добавлено,
  // когда компонент получает хук mounted
  @watch('?$el:click')
  onClick() {
    this.emit('success', {status: 200});
  }
}

Синтаксис имени события такой: [хук][источник]: событие. По умолчанию источник событий — это сам компонент, т. е. слушаются события, которые испускаются через emit. Хук, на котором добавляются обработчики, по умолчанию равен created (как правило это именно то, что нужно), но если в начале добавить символ:

  • ! — событие будет добавлено на beforeCreate;
  • ? — событие будет добавлено на mounted.

В качестве источника можно использоваться любые свойства компонента, например, rootEvent или parentEvent (можно использовать путь к свойству через точку foo.bla.baz). Также допускается использовать глобальные идентификаторы, например, document или window.

import iBlock, { component, field, watch } from 'super/i-block/i-block';
export * from 'super/i-block/i-block';

@component()
export default class bExample extends iBlock {
  @watch('!document:click')
  onClick() {
    this.emit('Click!');
  }
}

Дополнительные параметры

Декоратор @watch может принимать объект с параметрами наблюдения:

{
  // Имя наблюдаемого свойства или событие
  field: string;

  // Название вызываемого метода или функция
  // (только для случаев, когда декоратор добавляется к свойству)
  fn?: string | ((ctx: this, value: unknown, oldValue: unknown) => void);

  // Если true, то обработчик будет также вызван при первичной инициализации свойства
  // (только для наблюдаемых свойств)
  immediate?: boolean;

  // Если true, то наблюдение будет также идти за внутренней структурой объекта
  // (только для наблюдаемых свойств)
  deep?: boolean;

  // Если false, то функции обработчику не будут передаваться аргументы
  provideArgs?: boolean;

  // Если true, то событие или изменение свойства будет обработано только один раз
  single?: boolean;

  // Функция обертка
  wrapper?: (ctx: this, fn: Function) => Function;

  // Параметры Async
  group?: string;
  label?: string | symbol;
  join: boolean | 'replace';
}
import iBlock, { component, field, watch } from 'super/i-block/i-block';
export * from 'super/i-block/i-block';

@component()
export default class bExample extends iBlock {
  // Клик будет обработан только один раз
  @watch({field: 'document:click', single: true})
  onClick() {
    this.emit('Click!');
  }
}

Делегирование событий DOM

Параметр wrapper удобно использовать для делегирования DOM событий, например,

import iBlock, { component, field, watch } from 'super/i-block/i-block';
export * from 'super/i-block/i-block';

@component()
export default class bExample extends iBlock {
  // Делегируем клик по документу элементу button
  @watch({
    field: 'document:click', 
    wrapper: (o, fn) => o.dom.delegateElement('button', fn)
  })

  onClick() {
    this.emit('Click!');
  }
}
Clone this wiki locally