освещенное свойство элемента, передающее тоже другую функцию / класс - PullRequest
1 голос
/ 11 января 2020

В настоящее время я изучаю, как использовать lit-elements, и я также совершенно новичок в веб-разработке. Я пытаюсь создать пользовательский элемент Bluetooth, который меняет текст и цвет кнопки в зависимости от того, подключено устройство Bluetooth или нет.

В своем документе я создаю еще один класс с именем BTLE, в котором обрабатываются все функции Bluetooth. Но я понятия не имею, как передать свойство litelement этому классу BTLE. Я хочу, чтобы моя кнопка была перерисована, когда класс BTLE замечает соединение или дискотеку nnet. Если я передаю свойство через класс BTLE через конструктор и изменяю свойство, кнопка не перерисовывается. Если я изменю свойства внутри класса litelement, он будет перерисован.

Ответы [ 2 ]

1 голос
/ 13 января 2020

Идиоматический c способ решить эту проблему с помощью LitElement - заставить объект BTLE генерировать события при изменении его состояния, а другие объекты (например, пользовательские элементы), которым важно его состояние, прослушивать эти события.

Самый простой способ сделать это в веб-приложении - сделать класс BTLE расширенным EventTarget , что даст ему addEventListener, dispatchEvent и т. Д. c. методы. Затем вместо передачи функций обратного вызова в конструктор BTLE ваш пользовательский элемент будет вызывать addEventListener, чтобы начать прослушивание. Когда состояние объекта BTLE изменяется, вместо вызова this.callbackFunction(...) он будет вызывать this.dispatchEvent(new Event('state-change')) (например).

Чтобы выполнить sh, ваш пользовательский элемент должен будет определить собственный метод получения и установки, так он знает, когда его свойство bluetoothGatt изменяется, потому что ему нужно будет вызвать addEventListener на новом BTLE. Это самая сложная часть, поэтому я настоятельно рекомендую прочитать раздел «Настройка средств доступа к свойствам» в документации по LitElement.

В следующем фрагменте вы можете увидеть рабочий пример того, как это может посмотрите на практике:

const { LitElement, html } = litElement;

const BluetoothGattState = { Disconnected: 0, Connected: 1 };

// A simple app to test our custom element
class MyApp extends LitElement {
  render() {
    // Pass the BTLE object to `<bt-indicator>` as a property
    return html`
      <bt-indicator .bluetoothGatt=${new BTLE()}></bt-indicator>
    `;
  }
}
customElements.define('my-app', MyApp);

// Our <bt-indicator> custom element
class BtIndicator extends LitElement {
  static get properties() {
    return {
      bluetoothGatt: { type: Object },
      btState: { type: Number },
    };
  }

  constructor() {
    super();
    this._bluetoothGatt = null;
    this._handleBtGattStateChange = this._handleBtGattStateChange.bind(this);
  }

  render() {
    return html`Bluetooth status: ${
      this.btState === BluetoothGattState.Connected ? '✅' : '?'
    }`;
  }

  // A custom setter that calls addEventListener whenever the bluetoothGatt
  // property changes
  set bluetoothGatt(obj) {
    const oldObj = this._bluetoothGatt;

    if (oldObj) {
      // Remove event listener from old BTLE
      oldObj.removeEventListener('state-change', this._handleBtGattStateChange);
    }

    if (obj) {
      this._bluetoothGatt = obj;
      this.btState = obj.state;
      // Add event listener to new BTLE
      obj.addEventListener('state-change', this._handleBtGattStateChange);
    } else {
      this._bluetoothGatt = null;
    }

    // Tell LitElement the property changed so it can re-render
    this.requestUpdate('bluetoothGatt', oldObj);
  }
  
  get bluetoothGatt() {
    return this._bluetoothGatt;
  }
  
  _handleBtGattStateChange(evt) {
    // update this.btState when the BTLE's stage changes
    this.btState = evt.target.state;
  }
}
customElements.define('bt-indicator', BtIndicator);


// BTLE as a simple EventTarget -- connects/disconnects every 1000ms and
// dispatches 'state-change'
class BTLE extends EventTarget {
  constructor() {
    super();
    this.setState(BluetoothGattState.Disconnected);
    
    setInterval(() => {
      this.setState(this.state === BluetoothGattState.Disconnected ? BluetoothGattState.Connected : BluetoothGattState.Disconnected);
    }, 1000);
  }
  
  setState(val) {
    this.state = val;
    this.dispatchEvent(new Event('state-change'));
  }
}
<script src="https://bundle.run/lit-element@2.2.1"></script>

<my-app><my-app>
0 голосов
/ 12 января 2020

Я сделал функцию обратного вызова в своем классе litelement в качестве обходного пути. Таким образом, класс Bluetooth создается следующим образом:

this.bluetoothGatt = new BTLEclass(this.bluetoothDevice, this, this.bluetoothCallback);

, а затем в классе Bluetooth конструктор выглядит следующим образом:

constructor(bluetoothDevice: any, callingClass: any, callbackfunction: any) {
        this.bluetoothDevice = bluetoothDevice;
        this.state = BluetoothGattState.Disconnected;
        this.callback  = callingClass;
        this.callbackfunction = callbackfunction;
    }

обратный вызов вызывается так:

this.callbackfunction.call(this.callback,this.connectionStr);

И обратный вызов внутри litelement:

bluetoothCallback(constr:string)
  {
     this.connectedStr = constr;
  }

свойство внутри litelement:

 @property() connectedStr: string = 'connect';

Это работает, но очень уродливо! Есть ли способ, которым я могу сделать класс BTLE другом класса litelement (как в C ++), чтобы я мог изменить его непосредственно внутри класса BTLE (и кнопка будет перерисована)

Или есть ли лучший способ сделать это в javascript / litelement / webcomponents? я должен использовать MobX для чего-то подобного?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...