Юдзу API — это бесплатный API рыночных данных, который может поддерживать пользовательские интерфейсы любого размера: от огромных разрастающихся веб-приложений до вставных компонентов пользовательского интерфейса.

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

Пример живого значка

Если вы предпочитаете переходить к хорошей части, мой друг Стив создал GitHub Repo с нашим демонстрационным кодом. Вы можете перетащить его прямо на существующую страницу!


Поскольку мы хотим, чтобы этот компонент был полностью переносимым и независимым от фреймворка, мы будем использовать горит + Typescript для создания собственного веб-компонента. В этом руководстве предполагается, что у вас установлены следующие инструменты:

Для начала мы будем использовать пряжу, чтобы создать для нас проект.

$ yarn create vite yuzu-stock-price-badge --template lit-ts
$ cd yuzu-stock-price-badge
$ yarn install`
Войти в полноэкранный режим

Выйти из полноэкранного режима

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

Как только мы приступим к нашему новому проекту и запустим новый yarn installдавайте сделаем несколько вещей.

  1. Vite создал для нас один компонент на src/my-element.ts. Давайте переименуем его в yuzu-price-badge.ts.

  2. В src/yuzu-price-badge.tsдавайте заменим все вхождения my-element с yuzu-price-badge.

  3. В package.json, index.htmlа также vite.config.tsсделайте то же самое, заменив все варианты использования my-element с yuzu-price-badge.

  4. Бежать yarn build и убедитесь, что все выглядит хорошо!

Если это звучит как много работы, вы можете просто запустить эти команды в своем терминале:

mv src/my-element.ts src/yuzu-price-badge.ts
sed -i '' 's/my-element/yuzu-price-badge/g' vite.config.ts \
  src/yuzu-price-badge.ts \
  package.json \
  index.html
sed -i '' 's/MyElement/YuzuPriceBadge/g' src/yuzu-price-badge.ts
Войти в полноэкранный режим

Выйти из полноэкранного режима

Далее, давайте очистим весь шаблон от src/yuzu-stock-price-badge.ts

Файл должен выглядеть примерно так, когда вы закончите:

src/yuzu-price-badge.ts

import { html, css, LitElement } from 'lit'
import { customElement, property, state } from 'lit/decorators.js'

/**
 * Yuzu stock price badge
 */
@customElement('yuzu-price-badge')
export class YuzuPriceBadge extends LitElement {
  static styles = css`
    :host {
    }
  `

  render() {
    return html``
  }
}

declare global {
  interface HTMLElementTagNameMap {
    'yuzu-price-badge': YuzuPriceBadge
  }
}
Войти в полноэкранный режим

Выйти из полноэкранного режима

Хорошо, теперь, когда мы достигли хорошей базовой линии, давайте добавим некоторые свойства к нашему новому компоненту, чуть выше нашего render метод:

src/yuzu-price-badge.ts

  /**
   * Your Yuzu API key, exposed in HTML as "api-key"
   */
  @property({ type: String, attribute: "api-key" })
  apiKey = "";

  /**
   * The symbol to render
   * E.g. AAPL, MSFT, BRK.A
   */
  @property({ type: String })
  symbol = "";

  /**
   * Hold the last price of our stock
   */
  @state()
  private lastPrice: number = 0;
Войти в полноэкранный режим

Выйти из полноэкранного режима

Два наших новых объекта, apiKey а также symbol будет отображаться в HTML, чтобы изменить то, что отображается в этом значке. Третье свойство, lastPrice — это часть внутреннего состояния, которое будет содержать последнюю известную цену нашей акции. Пойдем index.html и обновите наш компонент.

index.html

 <body>
    <!-- Replace "demo" with your own API key -->
    <yuzu-price-badge api-key="demo" symbol="BYND">
    </yuzu-price-badge>
  </body>
Войти в полноэкранный режим

Выйти из полноэкранного режима

Большой! Теперь нам нужно получить последнюю цену нашей акции при загрузке компонента. Мы можем переопределить connectedCallbackфункция от LitElement сделать это. Давайте положим наш connectedCallback между нашими новыми объектами и renderметод.

src/yuzu-price-badge.ts

  async connectedCallback() {
    super.connectedCallback();
  }
Войти в полноэкранный режим

Выйти из полноэкранного режима

Далее мы собираемся сделать две вещи:

  • Сделайте запрос GraphQL, чтобы получить последнюю цену акции.
  • Подпишитесь на прямую трансляцию цен на наши акции и обновляйте наше внутреннее состояние при изменении цены.

Поскольку API-интерфейсы потоковой передачи Yuzu возвращают данные об акциях только в часы работы рынка, рекомендуется использовать API-интерфейс GraphQL для получения любых данных, необходимых для отображения пользовательского интерфейса, а затем подписаться на последующие обновления.

Добавим следующий код в наш connectedCallback чтобы сделать запрос GraphQL:

async connectedCallback() {
    super.connectedCallback();

    // Visit  to see docs on the whole graph
    const query = `query {
      securities(input: { symbols: ["${this.symbol}"] }) {
        lastTrade {
          price
        }
      }
    }`

    const graphQlResult = await fetch("", {
      method: "POST",
      body: JSON.stringify({
        query
      }),
      headers: {
        'Authorization': `Bearer ${this.apiKey}`,
        'Content-Type': "application/json",
      }
    });
    const { data } = await graphQlResult.json();

    this.lastPrice = parseFloat(data.securities[0].lastTrade.price);
  }
Войти в полноэкранный режим

Выйти из полноэкранного режима

Большой! Вот краткий обзор того, что происходит выше:

  1. Создайте тело нашего запроса GraphQL, запрашивая ценные бумаги, соответствующие нашему символу, и на этом объекте price поле последней сделки этой ценной бумаги.

  2. Использование Fetch API для выполнения запроса, анализа результата и присвоения значения this.lastPrice.

Последний шаг, прежде чем мы сможем увидеть плоды нашей работы: рендеринг lastPrice. Давайте изменим render() чтобы показать наш символ и сохраненную цену.

  render() {
    return html`
    <p>${this.symbol}</p>
    <p>$${this.lastPrice.toFixed(2)}</p>
    `
  }
Войти в полноэкранный режим

Выйти из полноэкранного режима

Теперь беги yarn dev в вашем терминале и откройте localhost:3000 в вашем браузере. Вы должны увидеть последнюю цену BYND.

Все, что нам нужно сделать сейчас, это добавить немного живости! К счастью, это тривиально при использовании потоков Yuzu и EventSource API. Давайте добавим следующий код в конец connectedCallback():

async connectedCallback() {
    /*
    ... Our GraphQL querying code
    */

    const stream = `S:T:${this.symbol}`;
    const url = `
    const tradeStream = new EventSource(url);
    tradeStream.addEventListener("message", (message) => {
      this.lastPrice = parseFloat(JSON.parse(message.data).price);
    });
  } 
Войти в полноэкранный режим

Выйти из полноэкранного режима

Это всего несколько строк кода, но за ними стоит большая сила. Вот что происходит:

  1. Мы создаем URL, указывающий на API событий, отправленных сервером Yuzuвключая наш токен API и имя потока S:T:BYNDкоторый запрашивает каждую сделку ценной бумаги BYND

  2. Добавьте прослушиватель событий в EventSource который анализирует каждое сообщение и присваивает значение price к нашему внутреннему состоянию, вызывая повторную визуализацию компонента.

Теперь, если вы вернетесь в свой браузер, вы увидите обновление цены в режиме реального времени, пока рынки открыты.

Теперь все, что осталось сделать, это добавить немного стиля!

static styles = css`
    :host {
      padding: 0.3rem 0.5rem;
      display: inline-flex;
      flex-direction: row;
      gap: 0.5rem;
      border: 2px solid black;
      border-radius: 99rem;
      background-color: gainsboro;

      font-family: sans-serif;
      font-weight: bold;
      font-size: 1rem;
    }

    p {
      margin: 0;
    }
  `
Войти в полноэкранный режим

Выйти из полноэкранного режима

И есть! Посмотрите наш пример репозитория для готовой версии вы можете перейти прямо на вашу существующую страницу.