Перетаскивание все еще может играть так!

внешний интерфейс JavaScript
Перетаскивание все еще может играть так!

⚠️Эта статья является первой подписанной статьей сообщества Nuggets, и её перепечатка без разрешения запрещена.

Дизайнеры на большинстве платформ с низким кодом поддерживают перетаскивание компонентов, что значительно улучшает работу пользователя с дизайном. Другим распространенным сценарием перетаскивания является загрузка файлов. С помощью перетаскивания пользователи могут легко загружать файлы. На самом деле, используя функцию перетаскивания, мы также можемОбмен данными через границы браузера.

так какОбмен данными через границы браузераШерстяная ткань? В этой статье брат Абао представит проект Google с открытым исходным кодом——transmat, вышеуказанные функции могут быть достигнуты с помощью этого проекта. Мало того, этот проект также может помочь нам реализовать некоторые забавные функции, такие как разные ответы на разные высвобождаемые цели.

Давайте сначала почувствуем это через 4 анимации Gif, используйтеtransmatразвитиеВолшебный и веселыйфункция перетаскивания.

Рис. 1 (перетащите перетаскиваемый элемент в редактор форматированного текста)

Рисунок 2 (Перетащите перетаскиваемый элемент в браузер Chrome, другие браузеры также поддерживаются)

Рис. 3 (перетащите перетаскиваемый элемент в пользовательскую цель выпуска)

Рисунок 4 (перетащите перетаскиваемый элемент в Chrome DevTools)

Версия браузера, используемая в приведенном выше примере: Chrome 91.0.4472.114 (официальная версия) (x86_64)

из 4 картинок вышеВсе перетаскиваемые элементы являются одним и тем же элементом, которые имели разные эффекты при размещении на разных высвобождаемых целях. В то же время мы также перешли границы браузеров и реализовали обмен данными. Прочитав вышеприведенные 4 движущиеся картинки, вы не думаете, что это потрясающе.На самом деле, помимо перетаскивания, этот пример также поддерживает операции копирования и вставки.. Однако подробно, как использоватьtransmatПеред реализацией вышеперечисленных функций кратко представимtransmatэта библиотека.

1. Введение в Трансмат

Transmatэто окружениеDataTransferНебольшая библиотека API, которая используетdrag-dropа такжеcopy-pasteВзаимодействие упрощает процесс передачи и получения данных в веб-приложении.DataTransferAPI может передавать множество различных типов данных в другие приложения на устройстве пользователя. API поддерживает следующие распространенные типы данных:text/plain,text/htmlа такжеapplication/jsonЖдать.

(Источник изображения:Google.GitHub.IO/внезапно сообразил/)

пониматьtransmatПосле чего рассмотрим сценарии его применения:

  • Хотите интегрироваться с внешними приложениями удобным способом.
  • Хотите предоставить пользователям возможность обмениваться данными с другими приложениями, даже с теми, о которых вы не знаете.
  • Ожидайте, что внешние приложения будут глубоко интегрированы с вашим веб-приложением.
  • Хотите, чтобы ваше приложение лучше вписывалось в существующий рабочий процесс пользователя.

теперь ты правtransmatС определенным пониманием разберем, как использоватьtransmatРеализуйте функции, соответствующие вышеуказанным 4 анимациям Gif.

2. Трансмат бой

2.1 transmat-source

html

В следующем коде мыdiv#sourceэлемент добавленdraggableАтрибут, этот атрибут используется для определения того, разрешено ли перетаскивание элемента, его значение равноtrueилиfalse.

<script src="https://unpkg.com/transmat/lib/index.umd.js"></script>
<div id="source" draggable="true" tabindex="0">大家好,我是阿宝哥</div>

css

#source {
  background: #eef;
  border: solid 1px rgba(0, 0, 255, 0.2);
  border-radius: 8px;
  cursor: move;
  display: inline-block;
  margin: 1em;
  padding: 4em 5em;
}

js

const { Transmat, addListeners, TransmatObserver } = transmat;

const source = document.getElementById("source");

addListeners(source, "transmit", (event) => {
  const transmat = new Transmat(event);
  transmat.setData({
    "text/plain": "大家好,我是阿宝哥!",
    "text/html": `
       <h1>大家好,我是阿宝哥</h1>
       <p>聚焦全栈,专注分享 TS、Vue 3、前端架构等技术干货。
          <a href="https://juejin.cn/user/764915822103079">访问我的主页</a>!
       </p>
       <img src="https://sf3-ttcdn-tos.pstatp.com/img/user-avatar/
         075d8e781ba84bf64035ac251988fb93~300x300.image" border="1" />
     `,
     "text/uri-list": "https://juejin.cn/user/764915822103079",
     "application/json": {
        name: "阿宝哥",
        wechat: "semlinker",
      },
   });
 });

В приведенном выше коде мы используемtransmatпредоставляется этой библиотекойaddListenersФункцияdiv#sourceэлемент, добавленныйtransmitпрослушиватель событий. В соответствующем обработчике событий мы сначала создалиTransmatобъект, а затем вызватьsetDataНастройки метода разныеMIMEтип данных.

Кратко рассмотрим примеры, использованные вMIMEТипы:

  • text/plain: Указывает значение по умолчанию для текстовых файлов.Текстовый файл должен быть удобочитаемым и не содержать двоичных данных.
  • text/html: указывает тип файла HTML, некоторые редакторы форматированного текста имеют приоритет передdataTransferпопасть на объектtext/htmlТип данных, если он не существует, получить его сноваtext/plainтип данных.
  • text/uri-list: указывает тип ссылки URI. Большинство браузеров сначала считывают этот тип данных. Если найдена действительная ссылка URI, ссылка будет открыта напрямую. Если это недействительная ссылка URI, для Chrome она будет читатьсяtext/plainтип данных и использовать данные в качестве ключевого слова для поиска контента.
  • application/json:ВыражатьJSONТип, этот тип должен быть знаком фронтенд-разработчикам.

Введениеtransmat-sourceПосле этого давайте взглянем на код реализации пользовательской цели (transmat-target) на рисунке 3.

2.2 transmat-target

html

<script src="https://unpkg.com/transmat/lib/index.umd.js"></script>
<div id="target" tabindex="0">放这里哟!</div>

css

body {
  text-align: center;
  font: 1.2em Helvetia, Arial, sans-serif;
}
#target {
  border: dashed 1px rgba(0, 0, 0, 0.5);
  border-radius: 8px;
  margin: 1em;
  padding: 4em;
}
.drag-active {
   background: rgba(255, 255, 0, 0.1);
}
.drag-over {
   background: rgba(255, 255, 0, 0.5);
}

js

const { Transmat, addListeners, TransmatObserver } = transmat;

const target = document.getElementById("target");

addListeners(target, "receive", (event) => {
  const transmat = new Transmat(event);
  // 判断是否含有"application/json"类型的数据
  // 及事件类型是否为drop或paste事件
  if (transmat.hasType("application/json") 
    && transmat.accept()
  ) {
    const jsonString = transmat.getData("application/json");
    const data = JSON.parse(jsonString);
    target.textContent = jsonString;
  }
});

В приведенном выше коде мы используемtransmatпредоставляется этой библиотекойaddListenersФункцияdiv#targetэлемент, добавленныйreceiveпрослушиватель событий. Как следует из названия,receiveСобытие представляет получение сообщения. В соответствующем обработчике события мы передаемtransmatобъектhasTypeметод отфильтрованapplication/jsonсообщение, затем черезJSON.parseметод десериализации для получения соответствующих данных и одновременного преобразования соответствующихjsonStringсодержимое отображается вdiv#targetвнутри элемента.

На рис. 3, когда мы перетаскиваем перетаскиваемый элемент в настраиваемую цель выпуска, создается эффект выделения, как показано на следующем рисунке:

Этот эффект заключается в использованииtransmatпредоставляется этой библиотекойTransmatObserverЭтот класс может помочь нам реагировать на поведение пользователя при перетаскивании. Конкретное использование выглядит следующим образом:

const obs = new TransmatObserver((entries) => {
  for (const entry of entries) {
    const transmat = new Transmat(entry.event);
    if (transmat.hasType("application/json")) {
      entry.target.classList.toggle("drag-active", entry.isActive);
      entry.target.classList.toggle("drag-over", entry.isTarget);
    }
  }
});
obs.observe(target);

первый раз вижуTransmatObserverПосле этого Брат Абао сразу же подумал об этом.MutationObserverAPI, потому что они обанаблюдательи имеет аналогичный API. использоватьMutationObserver APIМы можем отслеживать изменения в DOM. О любых изменениях в DOM, таких как добавление узлов, сокращение, изменения атрибутов и изменения текстового содержимого, мы можем получать уведомления через этот API. Если вы заинтересованы в API, вы можете прочитатьКто переместил мой DOM?Эта статья.

Теперь мы знаемtransmatКак пользоваться этой библиотекой Далее брат Абао расскажет вам о принципе работы этой библиотеки.

Пример использования Transmat:Transmat Demo

gist.GitHub.com/Semelinker/От…

В-третьих, анализ исходного кода Transmat

существуетtransmatСсылка на анализ исходного кода, потому что в предыдущей собственно боевой части мы использовалиaddListeners,Transmat,TransmatObserverЭти три «функции» реализуют основные функции, поэтому мы сосредоточимся на них в следующем анализе исходного кода. Здесь мы сначала анализируемaddListenersфункция.

3.1 функция addListeners

addListenersФункция используется для установки слушателя,После вызова этой функции она вернет функцию для удаления прослушивателя событий.. При анализе функции Brother Abao привык сначала анализировать сигнатуру функции:

// src/transmat.ts
function addListeners<T extends Node>(
  target: T,
  type: TransferEventType,
  listener: (event: DataTransferEvent, target: T) => void,
  options = {dragDrop: true, copyPaste: true}
): () => void

Наблюдая за приведенной выше сигнатурой функции, мы можем интуитивно понять ввод и вывод функции. Функция поддерживает следующие 4 параметра:

  • target: Указывает цель мониторинга, ее типNodeТипы.
  • type: Указывает тип мониторинга, тип параметраTransferEventTypeявляется типом объединения --'transmit' | 'receive'.
  • listener: представляет прослушиватель событий, который поддерживает такие типы событий, какDataTransferEvent, который также является типом объединения --DragEvent | ClipboardEvent, который поддерживает события перетаскивания и события буфера обмена.
  • options: представляет объект конфигурации, который используется для разрешения операций перетаскивания, копирования и вставки.

существуетaddListenersТело функции в основном включает следующие три шага:

  • Шаг ①: СогласноisTransmitEventа такжеoptions.copyPasteЗначение для регистрации событий, связанных с буфером обмена.
  • Шаг ②: СогласноisTransmitEventа такжеoptions.dragDropЗначение , регистрирует события, связанные с перетаскиванием.
  • Шаг 3: Верните объект функции, чтобы удалить зарегистрированный прослушиватель событий.
// src/transmat.ts
export function addListeners<T extends Node>(
  target: T,
  type: TransferEventType, // 'transmit' | 'receive'
  listener: (event: DataTransferEvent, target: T) => void,
  options = {dragDrop: true, copyPaste: true}
): () => void {
  const isTransmitEvent = type === 'transmit';
  let unlistenCopyPaste: undefined | (() => void);
  let unlistenDragDrop: undefined | (() => void);

  if (options.copyPaste) {
    // ① 可拖拽源监听cut和copy事件,可释放目标监听paste事件
    const events = isTransmitEvent ? ['cut', 'copy'] : ['paste'];
    const parentElement = target.parentElement!;
    unlistenCopyPaste = addEventListeners(parentElement, events, event => {
      if (!target.contains(document.activeElement)) {
        return;
      }
      listener(event as DataTransferEvent, target);

      if (event.type === 'copy' || event.type === 'cut') {
        event.preventDefault();
      }
    });
  }

  if (options.dragDrop) {
    // ② 可拖拽源监听dragstart事件,可释放目标监听dragover和drop事件
    const events = isTransmitEvent ? ['dragstart'] : ['dragover', 'drop'];
    unlistenDragDrop = addEventListeners(target, events, event => {
      listener(event as DataTransferEvent, target);
    });
  }

  // ③ 返回函数对象,用于移除已注册的事件监听
  return () => {
    unlistenCopyPaste && unlistenCopyPaste();
    unlistenDragDrop && unlistenDragDrop();
  };
}

Мониторинг событий приведенного выше кода, наконец, выполняется путем вызоваaddEventListenersФункция для достижения, внутри функция будет вызываться циклическиaddEventListenerметод добавления прослушивателей событий. Взяв в качестве примера предыдущий пример использования Transmat, внутри соответствующей функции обратного вызова обработки событий мы будем использоватьeventОбъект события является параметром, вызовTransmat создание конструктораTransmat пример. Так что же делает этот экземпляр? Чтобы понять, что он делает, нам нужно понятьTransmatДобрый.

3.2 Класс трансмата

Класс Transmat определен вsrc/transmat.tsфайл, конструктор этого класса содержит типDataTransferEventпараметрыevent:

// src/transmat.ts
export class Transmat {
  public readonly event: DataTransferEvent;
  public readonly dataTransfer: DataTransfer;

  // type DataTransferEvent = DragEvent | ClipboardEvent;
  constructor(event: DataTransferEvent) {
    this.event = event;
    this.dataTransfer = getDataTransfer(event);
  }
}

существуетTransmatВнутри конструктор также пройдетgetDataTransferфункция, чтобы получитьDataTransferобъект и назначьте его внутреннемуdataTransferАтрибуты.DataTransferОбъекты используются для хранения данных во время перетаскивания. Он может содержать один или несколько элементов данных, которые могут относиться к одному или нескольким типам данных.

Давайте взглянемgetDataTransferКонкретная реализация функции:

// src/data_transfer.ts
export function getDataTransfer(event: DataTransferEvent): DataTransfer {
  const dataTransfer =
    (event as ClipboardEvent).clipboardData ??
    (event as DragEvent).dataTransfer;
  if (!dataTransfer) {
    throw new Error('No DataTransfer available at this event.');
  }
  return dataTransfer;
}

В приведенном выше коде используется нулевой оператор объединения.??. Особенности этого оператора:Когда левый операнд равен нулю или не определен, возвращается правый операнд, в противном случае возвращается левый операнд.. То есть сначала определите, является ли это событием буфера обмена, и если да, то оно начнется сclipboardDataприобретение собственностиDataTransferобъект. В противном случае изdataTransferприобретение имущества.

Для перетаскиваемых источников после созданияTransmatобъект, мы можем назватьsetDataМетод содержит один или несколько элементов данных. Например, в следующем коде мы устанавливаем разные типы нескольких элементов:

transmat.setData({
  "text/plain": "大家好,我是阿宝哥!",
  "text/html": `
    <h1>大家好,我是阿宝哥</h1>
		...
   `,
  "text/uri-list": "https://juejin.cn/user/764915822103079",
  "application/json": {
     name: "阿宝哥",
     wechat: "semlinker",
   },
});

пониматьsetDataПосле использования метода давайте посмотрим на его конкретную реализацию:

// src/transmat.ts
setData(
  typeOrEntries: string | {[type: string]: unknown},
  data?: unknown
): void {
  if (typeof typeOrEntries === 'string') { 
    this.setData({[typeOrEntries]: data});
  } else {
    // 处理多种类型的数据
    for (const [type, data] of Object.entries(typeOrEntries)) {
      const stringData =
        typeof data === 'object' ? JSON.stringify(data) : `${data}`;
      this.dataTransfer.setData(normalizeType(type), stringData);
     }
   }
}

Как видно из приведенного выше кода, вsetDataВнутри метод в конечном итоге вызоветdataTransfer.setDataспособ сохранения данных.dataTransferобъектsetDataМетод поддерживает два параметра строкового типа:formatа такжеdata. Они представляют собой формат сохраняемых данных и фактические данные соответственно.Если данный формат данных не существует, сохраните соответствующие данные в конец. Если данный формат данных уже существует, старые данные будут заменены новыми данными..

На картинке ниже dataTransfer.setDataОписание совместимости метода, из рисунка видно, что основные современные браузеры поддерживают этот метод.

(Источник изображения:потрите news.com/madonna-api_datang…

В дополнение к классу TransmatsetDataметод, он также содержитgetDataспособ получения сохраненных данных.getDataМетод поддерживает параметр типа stringtype, используемый для указания типа данных. Прежде чем получить данные, он вызоветhasTypeМетод определяет, содержит ли он данные этого типа. Если он включен, он пройдетdataTransferобъектgetDataметод для получения данных, соответствующих типу.

// src/transmat.ts
getData(type: string): string | undefined {
  return this.hasType(type)
    ? this.dataTransfer.getData(normalizeType(type))
    : undefined;
}

Кроме того, при вызовеgetDataметод, он также вызоветnormalizeTypeфункция, для входящегоtypeПараметры типа нормализованы. В частности, следующим образом:

// src/data_transfer.ts
export function normalizeType(input: string) {
  const result = input.toLowerCase();
  switch (result) {
    case 'text':
      return 'text/plain';
    case 'url':
      return 'text/uri-list';
    default:
      return result;
  }
}

Аналогично, давайте посмотрим наdataTransfer.getDataСовместимость методов:

(Источник изображения:потрите news.com/madonna-api_datang…

Хорошо, в классе TransmatsetDataа такжеgetDataЭти два основных метода представлены здесь первыми. Далее мы вводим еще один класс — TransmatObserver.

3.3 Класс TransmatObserver

Роль класса TransmatObserver заключается в том, чтобы помочь нам реагировать на поведение пользователя при перетаскивании, и его можно использовать для выделения области перетаскивания в процессе перетаскивания. Например, в предыдущем примере мы добились выделения области перетаскивания следующим образом:

const obs = new TransmatObserver((entries) => {
  for (const entry of entries) {
    const transmat = new Transmat(entry.event);
    if (transmat.hasType("application/json")) {
      entry.target.classList.toggle("drag-active", entry.isActive);
      entry.target.classList.toggle("drag-over", entry.isTarget);
    }
  }
});
obs.observe(target);

Точно так же давайте сначала проанализируем конструктор класса TransmatObserver:

// src/transmat_observer.ts
export class TransmatObserver {
  private readonly targets = new Set<Element>(); // 观察的目标集合
  private prevRecords: ReadonlyArray<TransmatObserverEntry> = []; // 保存前一次的记录
  private removeEventListeners = () => {};

  constructor(private readonly callback: TransmatObserverCallback) {}
}

Как видно из приведенного выше кода, конструктор класса TransmatObserver поддерживает типTransmatObserverCallbackпараметрыcallback, соответствующий тип этого параметра определяется следующим образом:

// src/transmat_observer.ts
export type TransmatObserverCallback = (
  entries: ReadonlyArray<TransmatObserverEntry>,
  observer: TransmatObserver
) => void;

TransmatObserverCallbackТипы функций получают два параметра:entriesа такжеobserver. вentriesТип параметра

Массив только для чтения (ReadonlyArray), тип каждого элемента в массивеTransmatObserverEntry, соответствующие типы определяются следующим образом:

// src/transmat_observer.ts
export interface TransmatObserverEntry {
  target: Element;
  /** type DataTransferEvent = DragEvent | ClipboardEvent */
  event: DataTransferEvent;
  /** Whether a transfer operation is active in this window. */
  isActive: boolean;
  /** Whether the element is the active target (dragover). */
  isTarget: boolean;
}

спередиtransmat-targetнапример, при созданииTransmatObserverэкземпляр, экземплярobserveметод и передать объект для наблюдения.observeРеализация метода не сложная, а заключается в следующем:

// src/transmat_observer.ts
observe(target: Element) {
  /** private readonly targets = new Set<Element>(); */
  this.targets.add(target);
  if (this.targets.size === 1) {
    this.addEventListeners();
  }
}

существуетobserveВнутри метода наблюдаемый элемент будет сохранен вtargets Setв коллекции. когдаtargetsКогда размер коллекции равен 1, будет вызван текущий экземпляр.addEventListenersметод добавления прослушивателей событий:

// src/transmat_observer.ts
private addEventListeners() {
  const listener = this.onTransferEvent as EventListener;
  this.removeEventListeners = addEventListeners(
    document,
    ['dragover', 'dragend', 'dragleave', 'drop'],
    listener,
    true
  );
}

наединеaddEventListenersВнутри метода мы будем использовать введенный ранееaddEventListenersфункционировать, чтобыdocumentДобавляйте прослушиватели событий, связанные с перетаскиванием, к элементам в пакетах. Соответствующее описание события выглядит следующим образом:

  • dragover: срабатывает, когда элемент или выделенный текст перетаскиваются на освобождаемую цель;
  • dragend: срабатывает при завершении операции перетаскивания (например, при отпускании кнопки мыши);
  • dragleave: срабатывает, когда перетаскиваемый элемент или выделенный текст покидают освобождаемую цель;
  • drop: Запускается, когда элемент или выделенный текст высвобождаются на освобождаемой цели.

На самом деле, есть не только четыре вышеупомянутых события, связанных с перетаскиванием.Если вас интересуют полные события, вы можете прочитать MDN наAPI перетаскивания HTMLЭта статья. Ниже мы сосредоточимся на анализеonTransferEventПрослушиватель событий:

private onTransferEvent = (event: DataTransferEvent) => {
  const records: TransmatObserverEntry[] = [];
  for (const target of this.targets) {
    // 当光标离开浏览器时,对应的事件将会被派发到body或html节点
    const isLeavingDrag =
      event.type === 'dragleave' &&
        (event.target === document.body ||
         event.target === document.body.parentElement);

    // 页面上是否有拖拽行为发生
    // 当拖拽操作结束时触发dragend事件
    // 当元素或选中的文本在可释放目标上被释放时触发drop事件
    const isActive = event.type !== 'drop'
      && event.type !== 'dragend' && !isLeavingDrag;

    // 判断可拖拽的元素是否被拖到target元素上
    const isTargetNode = target.contains(event.target as Node);
    const isTarget = isActive && isTargetNode 
      && event.type === 'dragover';

    records.push({
      target,
      event,
      isActive,
      isTarget,
   });
 }
    
 // 仅当记录发生变化的时候,才会调用回调函数
 if (!entryStatesEqual(records, this.prevRecords)) {
   this.prevRecords = records as ReadonlyArray<TransmatObserverEntry>;
   this.callback(records, this);
 }
}

В приведенном выше коде используйтеnode.contains(otherNode)Метод для определения того, перетаскивается ли перетаскиваемый элемент вtargetна элементе. когдаotherNodeдаnodeпотомок узла , илиnodeКогда сам узел возвращаетtrue, иначе возвратfalse.此外,为了避免频繁地触发回调函数,在调用回调函数前会先调用entryStatesEqualфункция, чтобы определить, изменилась ли запись.entryStatesEqualРеализация функции относительно проста, а именно:

// src/transmat_observer.ts
function entryStatesEqual(
  a: ReadonlyArray<TransmatObserverEntry>,
  b: ReadonlyArray<TransmatObserverEntry>
): boolean {
  if (a.length !== b.length) {
    return false;
  }
  // 如果有一项不匹配,则立即返回false。
  return a.every((av, index) => {
    const bv = b[index];
    return av.isActive === bv.isActive && av.isTarget === bv.isTarget;
  });
}

а такжеMutationObserverТакой же,TransmatObserverТакже предоставляет метод для получения недавно инициированных записей.takeRecordsСпособы и способы «отключения» соединенийdisconnectметод:

// 返回最近已触发记录
takeRecords() {
  return this.prevRecords;
}

// 移除所有目标及事件监听器
disconnect() {
  this.targets.clear();
  this.removeEventListeners();
}

Соответствующее содержание анализа исходного кода Transmat было представлено здесь.Если вы заинтересованы в проекте, вы можете самостоятельно прочитать полный исходный код проекта. В проекте используетсяTypeScriptразработка, началоTypeScriptНебольшие партнеры могут использовать этот проект для консолидации знаний TS и идей объектно-ориентированного проектирования ООП, которые они изучили.

4. Резюме

В этой статье Baoge представил GoogletransmatСценарии приложений, методы использования и соответствующий исходный код проектов с открытым исходным кодом. При анализе исходного кода мы рассмотрели события, связанные с перетаскиванием иDataTransferAPI. Кроме того, мы проанализировалиTransmatObserverкласс, я надеюсь, что, проанализировав класс, выMutationObserverAPI может иметь более глубокое понимание. В то же время, в дальнейшей работе, если вы столкнетесь с подобными сценариями, вы можете обратиться кTransmatObserver класс для реализации собственногоObserverДобрый.

Хотя настраиваемые полезные нагрузки (настраиваемые данные JSON) полезны для связи между приложениями, которыми вы управляете, они также ограничивают возможность передачи данных во внешние приложения. Чтобы исправить это, вы можете рассмотреть возможность использования облегченногоJSON-LD (связанные данные)формат данных, соответствующий ему тип MIME'application/ld+json'. С помощью этого формата данных данные могут быть лучше организованы и связаны для создания лучших веб-приложений. Если вас интересует этот формат данных и вы хотите узнать большеJSON-LD (связанные данные), вы можете прочитать этостатья.

5. Справочные ресурсы