Comparteix via


Conexión de Office.js a cualquier marco de JavaScript

Office.js es independiente del marco y funciona sin problemas con cualquier marco o biblioteca de JavaScript del lado cliente. Tanto si va a compilar con React, Angular, Vue, Svelte o cualquier otro marco, el patrón de integración es el mismo: asegúrese de que Office.js inicializa antes de que se represente la aplicación.

Nota:

También puede usar marcos del lado servidor como ASP.NET, PHP y Java para compilar complementos de Office, pero este artículo no los cubre. Este artículo se centra específicamente en los marcos de JavaScript del lado cliente que se ejecutan en el explorador.

En este artículo se explican los patrones universales para integrar Office.js con marcos de JavaScript del lado cliente, consideraciones importantes y se proporcionan ejemplos en varios marcos.

Sugerencia

Este artículo está diseñado para desarrolladores que crean complementos de Office desde cero con su marco de JavaScript preferido o integran Office.js en un proyecto de marco existente. Si usa el generador de Yeoman para complementos de Office o microsoft 365 Agents Toolkit, estas herramientas ya proporcionan la configuración correcta Office.js.

Requisitos previos

Inicio rápido: El patrón universal

Independientemente del marco que elija, use el siguiente patrón.

  1. Haga referencia a Office.js de la red CDN en el html <head>.
  2. Llame a Office.onReady() y espere a que se complete.
  3. Inicialice el marco una vez Office.js esté listo.
// Universal pattern - works with any framework.
Office.onReady((info) => {
  // Office.js is now ready.
  // Initialize your framework here.
  initializeYourFramework();
});

Carga de Office.js desde la red CDN

Debe hacer referencia a la API de JavaScript de Office desde la red de entrega de contenido (CDN) en el archivo HTML. Agregue la siguiente <script> etiqueta en la sección de la <head> página HTML, antes de cualquier otra etiqueta de script o referencias de agrupación de marcos.

<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>

Importante

  • Cargue Office.js de la red CDN y haga referencia a él en el archivo HTML. No lo importe en el código JavaScript o TypeScript.
  • La referencia Office.js debe aparecer en la <head> sección para asegurarse de que la API se inicializa por completo antes de que se carguen los elementos del cuerpo.
  • No empaquete Office.js con el código de la aplicación. Siempre haga referencia a ella desde la red CDN.

Para obtener más información sobre cómo hacer referencia a Office.js, incluidas las API de versión preliminar y los puntos de conexión de RED CDN alternativos, consulte Referencia a la biblioteca de API de JavaScript de Office.

Inicializar el marco después de Office.onReady

La clave para integrar Office.js con cualquier marco es inicializar la aplicación dentro de la Office.onReady() devolución de llamada. Este enfoque garantiza que Office.js se inicialice completamente antes de que el marco comience a representarse. Esta inicialización es importante porque Office.js debe:

  • Descargue y almacene en caché los archivos de biblioteca de API de la red CDN.
  • Inicialice el entorno en tiempo de ejecución de Office.
  • Establezca la comunicación con la aplicación de Office.

Si el marco se representa antes de que Office.js esté listo, se producirá un error en las llamadas a las API de Office. Al inicializar la aplicación dentro Office.onReady()de , garantiza que Office.js esté listo cuando se ejecute el código de la aplicación.

Ejemplos

En los ejemplos siguientes se muestra el mismo patrón de integración en diferentes marcos de trabajo. El patrón es idéntico: solo cambia el método de inicialización del marco.

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');
});

Svelte

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

JavaScript simple sin marco

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

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

Uso de api de Office.js en la aplicación

Después de que Office.js se inicialice (cuando Office.onReady() finalice), puede llamar a las API de Office en cualquier lugar del complemento. Use los enlaces de ciclo de vida del marco o los controladores de eventos para llamar a las API de Office cuando sea necesario.

// 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(); })

Compatibilidad con TypeScript

Para habilitar IntelliSense y la comprobación de tipos para Office.js en proyectos de TypeScript, instale las definiciones de tipo de DefinitelyTyped.

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

TypeScript reconoce automáticamente los tipos. No necesita una instrucción import en el código porque Office.js se carga globalmente desde la red CDN.

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

Para obtener más información, consulte Referencia a la biblioteca de API de JavaScript de Office.

Otras consideraciones

Indicadores de carga

Si desea mostrar un indicador de carga mientras Office.js se inicializa, muéstrelo antes de llamar a Office.onReady() y ocultelo dentro de la devolución de llamada.

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

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

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

Para una mejor experiencia de usuario con marcos que tienen sus propios estados de carga, use un cargador HTML/CSS simple que se muestre inmediatamente. A continuación, deje que el marco se haga cargo una vez montado.

Ciclo de vida de la API de diálogo y del componente

La API de cuadro de diálogo de Office abre páginas en ventanas de explorador independientes. Este comportamiento tiene implicaciones importantes para las aplicaciones de marco:

  • Cada cuadro de diálogo crea un nuevo contexto de ejecución con una instancia de marco independiente.
  • El cuadro de diálogo ejecuta su propia copia del código de la aplicación.
  • Debe llamar a Office.onReady() en la página de diálogo.
  • La página principal y las ventanas de diálogo no comparten el estado.
  • El almacenamiento de sesión no se comparte entre contextos.

Si usa un enrutador de marco para navegar a una ruta de diálogo, recuerde que la ventana de diálogo crea una instancia completamente nueva de la aplicación. No reutiliza la instancia existente.

// 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();
});

Solución alternativa de la API de historial

Office.js reemplaza los métodos replaceStateWindow.history predeterminados y pushState por null. Si el marco o enrutador depende de estos métodos (comunes en React Router, Vue Router, Angular Router y otros), debe almacenarlos en caché y restaurarlos.

Agregue este código al archivo HTML y ajuste la etiqueta de script de 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>

Nota:

Esta solución alternativa solo es necesaria si la aplicación usa el enrutamiento del lado cliente (React Router, Vue Router, Angular Router, entre otros). Las aplicaciones estáticas sin enrutamiento no necesitan esta solución alternativa.

Pruebas fuera de las aplicaciones de Office

Puede desarrollar y probar la interfaz de usuario del complemento mediante herramientas para desarrolladores de explorador sin transferir localmente a Office. Este enfoque permite una iteración más rápida durante el desarrollo y facilita la depuración de los componentes de la interfaz de usuario.

Al abrir el complemento en un explorador normal (fuera de una aplicación de Office), Office.onReady() se sigue ejecutando, pero se resuelve con null para las propiedades del host y de la plataforma.

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();
});

Compilación de herramientas y agrupaciones

Los marcos de JavaScript modernos suelen usar herramientas de compilación como Webpack, Vite, Rollup o esbuild. Al configurar la compilación:

  • No importe ni empaquete Office.js en el código JavaScript o TypeScript.
  • Cargue Office.js desde la red CDN mediante una <script> etiqueta en el código HTML.
  • Configure el bundler para tratarlo Office como una variable global.

Ejemplo: Configuración de TypeScript con Vite

Si usa Vite con TypeScript, normalmente no necesita una configuración especial de Vite para Office.js. El @types/office-js paquete proporciona las definiciones de tipo necesarias. Sin embargo, si necesita asegurarse de que los tipos de Office.js están disponibles, compruebe lo siguiente tsconfig.json:

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

Ejemplo: Configuración de Webpack

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

Los proyectos de complemento generados por el generador de Yeoman para complementos de Office incluyen la configuración de compilación correcta de forma predeterminada.

Bloqueo de red y firewalls

Si los filtros de red, los firewalls o las extensiones del explorador bloquean la red CDN de Office.js, Office.onReady() nunca se resuelve. Considere la posibilidad de implementar un tiempo de espera para escenarios empresariales en los que las directivas de red podrían bloquear la red 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();
});

Para obtener más información sobre las consideraciones sobre la red CDN, consulte Referencia a la biblioteca de API de JavaScript de Office.

Problemas de zona o reactividad específicos del marco

Algunos marcos usan zonas o sistemas de reactividad para realizar un seguimiento de los cambios de estado. En raras ocasiones, las llamadas API de Office no desencadenan actualizaciones de la interfaz de usuario porque se ejecutan fuera de la zona de detección de cambios del marco.

Angular: Si la interfaz de usuario no se actualiza después de llamar a la API de Office, ajuste el código en 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;
  });
}

Vea también