首页 > 解决方案 > lit 元素属性也传递了另一个函数/类

问题描述

我目前正在学习如何使用 lit-elements,而且我对 Web 开发也很陌生。我正在尝试制作一个蓝牙自定义元素,根据蓝牙设备是否连接来更改按钮文本和颜色。

在我的 litelement 中,我创建了另一个名为 BTLE 的类,其中处理了所有蓝牙。但我不知道如何将 litelement 属性传递给这个 BTLE 类。我希望当 BTLE 类注意到连接或断开连接时重新渲染我的按钮。如果我通过构造函数通过 BTLE 类传递属性并更改属性,则不会重新渲染按钮。如果我更改 litelement 类中的属性,它会被重新渲染。

标签: javascriptclasspropertieslit-element

解决方案


使用 LitElement 解决此问题的惯用方法是使 BTLE 对象在其状态更改时发出事件,并让关心其状态的其他对象(如自定义元素)监听这些事件。

在 Web 应用程序中执行此操作的最简单方法是使 BTLE 类扩展EventTarget,这将为它提供addEventListenerdispatchEvent等方法。然后,您的自定义元素将调用addEventListener它以开始侦听,而不是将回调函数传递给 BTLE 构造函数。当 BTLE 对象的状态发生变化时,this.callbackFunction(...)它会调用而不是调用this.dispatchEvent(new Event('state-change'))(例如)。

为此,您的自定义元素将需要定义自定义 getter 和 setter,以便知道其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>


推荐阅读