Поделиться через


Подключение Office.js к любой платформе JavaScript

Office.js не зависит от платформы и легко работает с любой клиентской платформой Или библиотекой JavaScript. Независимо от того, выполняется ли сборка с помощью React, Angular, Vue, Svelte или любой другой платформы, шаблон интеграции будет одинаковым: убедитесь, что Office.js инициализируется перед отрисовкой приложения.

Примечание.

Вы также можете использовать серверные платформы, такие как ASP.NET, PHP и Java, для создания надстроек Office, но в этой статье они не рассматриваются. В этой статье основное внимание уделяется клиентским платформам JavaScript, которые выполняются в браузере.

В этой статье описаны универсальные шаблоны интеграции Office.js с клиентскими платформами JavaScript, важные рекомендации и приведены примеры для нескольких платформ.

Совет

Эта статья предназначена для разработчиков, создающих надстройки Office с нуля с помощью предпочитаемой платформы JavaScript или интеграции Office.js в существующий проект платформы. Если вы используете генератор Yeoman для надстроек Office или Microsoft 365 Agents Toolkit, эти средства уже обеспечивают правильную конфигурацию Office.js.

Предварительные условия

Краткое руководство. Универсальный шаблон

Независимо от выбранной платформы используйте следующий шаблон.

  1. Ссылка Office.js из CDN в HTML <head>.
  2. Вызовите Office.onReady() и дождитесь завершения.
  3. Инициализация платформы после Office.js будет готова.
// Universal pattern - works with any framework.
Office.onReady((info) => {
  // Office.js is now ready.
  // Initialize your framework here.
  initializeYourFramework();
});

Загрузка Office.js из CDN

Необходимо ссылаться на API JavaScript для Office из сети доставки содержимого (CDN) в HTML-файле. Добавьте следующий <script> тег в <head> раздел HTML-страницы перед любыми другими тегами скриптов или ссылками на пакеты платформы.

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>My Office Add-in</title>

  <!-- Office.js must be loaded from CDN, not bundled -->
  <script src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js" type="text/javascript"></script>

  <!-- Your framework bundle loads after Office.js -->
</head>

Важно!

  • Загрузите Office.js из CDN и составьте на него ссылку в HTML-файле. Не импортируйте его в код JavaScript или TypeScript.
  • Ссылка на Office.js должна появиться в <head> разделе, чтобы убедиться, что API полностью инициализирован перед загрузкой элементов текста.
  • Не объединяйте Office.js с кодом приложения. Всегда ссылайся на него из CDN.

Дополнительные сведения о ссылках на Office.js, включая предварительные версии API и альтернативные конечные точки CDN, см. в статье Ссылка на библиотеку API JavaScript для Office.

Инициализация платформы после Office.onReady

Ключом к интеграции Office.js с любой платформой является инициализация приложения в обратном вызове Office.onReady() . Такой подход гарантирует, что Office.js будет полностью инициализирована до начала отрисовки платформы. Эта инициализация важна, так как Office.js необходимо:

  • Скачивание и кэширование файлов библиотеки API из сети CDN.
  • Инициализация среды выполнения Office.
  • Установить связь с приложением Office.

Если платформа отрисовывается до Office.js, вызовы API Office завершаются ошибкой. Инициализировав приложение внутри Office.onReady(), вы гарантируете, Office.js будет готово при запуске кода приложения.

Примеры

В следующих примерах показан один и тот же шаблон интеграции для разных платформ. Шаблон идентичен — изменяется только метод инициализации платформы.

React

// src/index.tsx
Office.onReady(() => {
  const root = ReactDOM.createRoot(document.getElementById('root'));
  root.render(<App />);
});

Angular

// src/main.ts
Office.onReady(() => {
  platformBrowserDynamic()
    .bootstrapModule(AppModule)
    .catch(err => console.error(err));
});

Vue

// src/main.ts
Office.onReady(() => {
  createApp(App).mount('#app');
});

Стройный

// src/main.ts
Office.onReady(() => {
  new App({ target: document.getElementById('app') });
});

Простой JavaScript без платформы

// src/app.js
Office.onReady((info) => {
  document.getElementById('run-button').onclick = run;

  if (info.host === Office.HostType.Excel) {
    console.log('Running in Excel');
  }
});

Использование API Office.js в приложении

После Office.js инициализации (по Office.onReady() завершении) вы можете вызывать API Office в любом месте надстройки. При необходимости используйте перехватчики жизненного цикла или обработчики событий платформы для вызова API Office.

// React example: Call an Office JS API in the useEffect lifecycle hook.
import { useEffect, useState } from 'react';

function MyComponent() {
  const [data, setData] = useState('');

  useEffect(() => {
    loadData();
  }, []);

  async function loadData() {
    await Excel.run(async (context) => {
      const range = context.workbook.getSelectedRange();
      range.load('values');
      await context.sync();

      // Update component state with the data from Excel.
      const value = range.values[0][0];
      setData(value);
    });
  }

  return <div>Selected cell: {data}</div>;
}

// Similar patterns for other frameworks:
// Angular: ngOnInit() { this.loadData(); }
// Vue: onMounted(() => { loadData(); })
// Svelte: onMount(() => { loadData(); })

Поддержка TypeScript

Чтобы включить IntelliSense и проверку типов для Office.js в проектах TypeScript, установите определения типов из DefinitelyTyped.

npm install --save-dev @types/office-js

TypeScript автоматически распознает типы. Оператор import в коде не требуется, так как Office.js загружается глобально из CDN.

// TypeScript automatically recognizes Office types.
Office.onReady((info: Office.OfficeInfo) => {
  if (info.host === Office.HostType.Excel) {
    // TypeScript provides IntelliSense for Excel APIs.
  }
});

Дополнительные сведения см. в статье Ссылка на библиотеку API JavaScript для Office.

Другие особенности

Индикаторы загрузки

Если вы хотите отобразить индикатор загрузки во время инициализации Office.js, перед вызовом Office.onReady() и скройте его внутри обратного вызова.

// Show loading indicator.
document.getElementById('loading')!.style.display = 'block';

Office.onReady((info) => {
  // Hide loading indicator.
  document.getElementById('loading')!.style.display = 'none';

  // Initialize framework.
  initializeYourFramework();
});

Для лучшего взаимодействия с платформами с собственными состояниями загрузки используйте простой загрузчик HTML/CSS, который сразу же отображается. Затем позвольте вашей платформе взять на себя после ее подключения.

Жизненный цикл API диалогового окна и компонентов

API диалогового окна Office открывает страницы в отдельных окнах браузера. Это поведение имеет важные последствия для приложений платформы:

  • Каждый диалог создает новый контекст выполнения с отдельным экземпляром платформы.
  • Диалоговое окно запускает собственную копию кода приложения.
  • Вызов необходимо выполнить Office.onReady() на странице диалогового окна.
  • Главная страница и диалоговые окна не имеют общего состояния.
  • Хранилище сеансов не используется между контекстами.

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

// Main page - opens a dialog.
Office.context.ui.displayDialogAsync(
  'https://localhost:3000/dialog-route',
  { height: 50, width: 50 },
  (result) => {
    if (result.status === Office.AsyncResultStatus.Succeeded) {
      const dialog = result.value;
      dialog.addEventHandler(Office.EventType.DialogMessageReceived, (arg) => {
        // Handle message from dialog.
      });
    } else {
      // Handle error opening the dialog.
      console.error(result.error);
    }
  }
);

// Dialog page - must also call Office.onReady.
Office.onReady(() => {
  // This is a separate framework instance.
  initializeYourFramework();
});

Обходной путь API журнала

Office.js заменяет методы replaceStateWindow.history по умолчанию и pushState на null. Если платформа или маршрутизатор зависят от этих методов (распространенных в React маршрутизатор, маршрутизатор Vue, маршрутизатор Angular и т. д.), необходимо кэшировать и восстанавливать их.

Добавьте этот код в HTML-файл, упаковав тег скрипта Office.js:

<head>
  <!-- Cache history methods before Office.js loads -->
  <script type="text/javascript">
    window._historyCache = {
      replaceState: window.history.replaceState,
      pushState: window.history.pushState
    };
  </script>

  <!-- Load Office.js -->
  <script type="text/javascript" src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"></script>

  <!-- Restore history methods after Office.js loads -->
  <script type="text/javascript">
    window.history.replaceState = window._historyCache.replaceState;
    window.history.pushState = window._historyCache.pushState;
  </script>
</head>

Примечание.

Это необходимо только в том случае, если приложение использует маршрутизацию на стороне клиента (React маршрутизатор, маршрутизатор Vue, маршрутизатор Angular и другие). Статическим приложениям без маршрутизации это обходное решение не требуется.

Тестирование вне приложений Office

Вы можете разрабатывать и тестировать пользовательский интерфейс надстройки с помощью средств разработчика браузера без загрузки неопубликованных приложений в Office. Такой подход позволяет ускорить итерацию во время разработки и упрощает отладку компонентов пользовательского интерфейса.

При открытии надстройки в обычном браузере (за пределами приложения Office) Office.onReady() по-прежнему выполняется, но разрешается с null для свойств узла и платформы.

Office.onReady((info) => {
  if (info?.host) {
    console.log(`Running in ${info.host} on ${info.platform}`);
  } else {
    console.log('Running outside of Office (development mode)');
  }

  // Initialize your framework, regardless of whether the add-in is running inside or outside of Office.
  initializeYourFramework();
});

Средства сборки и пакеты

Современные платформы JavaScript обычно используют такие средства сборки, как Webpack, Vite, Rollup или esbuild. При настройке сборки:

  • Не импортируйте и не объединяйте Office.js в код JavaScript или TypeScript.
  • Загрузите Office.js из CDN с помощью тега <script> в HTML- коде.
  • Настройте средство обработки пакетов как Office глобальную переменную.

Пример. Конфигурация TypeScript с Vite

При использовании Vite с TypeScript обычно не требуется специальная конфигурация Vite для Office.js. Пакет @types/office-js предоставляет необходимые определения типов. Однако если необходимо убедиться, что типы Office.js доступны, проверьте :tsconfig.json

// tsconfig.json
{
  "compilerOptions": {
    "types": ["office-js"]
    // ... your other compiler options ...
  }
}

Пример: конфигурация Webpack

// webpack.config.js
module.exports = {
  externals: {
    'office': 'Office'
  }
};

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

Блокировка сети и брандмауэры

Если сетевые фильтры, брандмауэры или расширения браузера блокируют Office.js CDN, Office.onReady() никогда не разрешается. Рассмотрите возможность реализации времени ожидания для корпоративных сценариев, в которых сетевые политики могут блокировать CDN.

let officeInitialized = false;

// Set a timeout.
setTimeout(() => {
  if (!officeInitialized) {
    console.error('Office.js failed to initialize. Network may be blocking CDN.');
    // Show error message to user.
  }
}, 10000); // 10 second timeout

Office.onReady((info) => {
  officeInitialized = true;
  initializeYourFramework();
});

Дополнительные сведения о рекомендациях cdn см. в статье Ссылка на библиотеку API JavaScript для Office.

Проблемы с зонами или реактивностью платформы

Некоторые платформы используют зоны или системы реактивности для отслеживания изменений состояния. В редких случаях вызовы API Office не активируют обновления пользовательского интерфейса, так как они выполняются за пределами зоны обнаружения изменений платформы.

Angular. Если пользовательский интерфейс не обновляется после вызовов API Office, заключите код в NgZone.run():

import { NgZone } from '@angular/core';

constructor(private zone: NgZone) {}

async loadDataFromExcel() {
  let cellValue: string;

  // Make Office API call
  await Excel.run(async (context) => {
    const range = context.workbook.getSelectedRange();
    range.load('values');
    await context.sync();
    cellValue = range.values[0][0];
  });

  // Update Angular component state inside zone
  this.zone.run(() => {
    this.myData = cellValue;
  });
}

См. также