Composants personnalisés
Web SDK propose plusieurs méthodes pour intégrer des composants personnalisés afin d’étendre et d’adapter ses fonctionnalités. Ce guide présente plusieurs méthodes courantes.
Univer ne transmet pas directement les composants en tant que paramètres aux fonctions de rendu. Vous devez d’abord les enregistrer auprès d’Univer à l’aide de la Facade API avant de pouvoir les utiliser dans les différents points de montage.
Si vous ne savez pas comment obtenir une instance de la Facade API, consultez la page Facade API.
Enregistrer des composants personnalisés
univerAPI.registerComponent(componentKey, CustomComponent, options)Utilisez la méthode univerAPI.registerComponent pour enregistrer des composants personnalisés. Cette méthode accepte trois paramètres :
componentKey: identifiant unique du composant, utilisé pour le référencer dans Univer.CustomComponent: implémentation du composant, qui peut être un composant React, Vue ou Web Component.options: options de configuration facultatives permettant notamment d’indiquer le framework dont dépend le composant.
Composants React
L’enregistrement d’un composant React ne nécessite aucune configuration supplémentaire ; assurez-vous simplement qu’il s’agit d’un composant React valide. Voici un exemple simple :
function ReactComponent(props: Record<string, any>) { return <div>Hello Univer!</div>}univerAPI.registerComponent('MyReactComponent', ReactComponent)Composants Vue
Vue 3.x
Pour enregistrer des composants Vue, installez et enregistrez le plugin UniverVue3AdapterPlugin du package @univerjs/ui-adapter-vue3 :
pnpm add @univerjs/ui-adapter-vue3npm install @univerjs/ui-adapter-vue3yarn add @univerjs/ui-adapter-vue3bun add @univerjs/ui-adapter-vue3import { UniverVue3AdapterPlugin } from '@univerjs/ui-adapter-vue3'univer.registerPlugin(UniverVue3AdapterPlugin)Lors de l’enregistrement de composants Vue, vous devez définir l’option framework sur 'vue3' :
const Vue3Component = defineComponent({ setup(props) { return () => <div>Hello Univer!</div> },})univerAPI.registerComponent('MyVue3Component', Vue3Component, { framework: 'vue3',})Vue 2.x
Comme Vue 2.x est arrivé en fin de vie et n’est plus maintenu, Univer ne fournit actuellement aucun plugin d’adaptation d’interface utilisateur pour Vue 2.x. Vous pouvez toutefois créer un plugin personnalisé afin d’implémenter votre propre adaptateur Vue 2.x. Voici un exemple :
import { DependentOn, Inject, Injector, Plugin } from '@univerjs/core'import { ComponentManager, UniverUIPlugin } from '@univerjs/ui'import Vue from 'vue'/** * The plugin that allows Univer to use Vue 2 components as UI components. */@DependentOn(UniverUIPlugin)export class UniverVue2AdapterPlugin extends Plugin { static override pluginName = 'UNIVER_UI_VUE2_ADAPTER_PLUGIN' constructor( private readonly _config = {}, @Inject(Injector) protected readonly _injector: Injector, @Inject(ComponentManager) protected readonly _componentManager: ComponentManager, ) { super() } override onStarting(): void { const { createElement, useEffect, useRef } = this._componentManager.reactUtils this._componentManager.setHandler('vue2', (component: any) => { return (props: Record<string, any>) => createElement(VueComponentWrapper, { component, props: Object.keys(props).reduce<Record<string, any>>((acc, key) => { if (key !== 'key') { acc[key] = props[key] } return acc }, {}), reactUtils: { createElement, useEffect, useRef }, }) }) }}export function VueComponentWrapper(options: { component: any props: Record<string, any> reactUtils: typeof ComponentManager.prototype.reactUtils}) { const { component, props, reactUtils } = options const { createElement, useEffect, useRef } = reactUtils const domRef = useRef<HTMLDivElement>(null) useEffect(() => { if (!domRef.current) return const Constructor = Vue.extend(component) const instance = new Constructor({ data: props, }) instance.$mount() domRef.current.appendChild(instance.$el) return () => { instance.$destroy() } }, [props]) return createElement('div', { ref: domRef })}Enregistrez-le ensuite :
import { UniverVue2AdapterPlugin } from './ui-adapter-vue2'univer.registerPlugin(UniverUIPlugin)univer.registerPlugin(UniverVue2AdapterPlugin)Lors de l’enregistrement de composants Vue 2.x, vous devez définir l’option framework sur 'vue2' :
const Vue2Component = Vue.component('MyVue2Component', { template: '<div>Hello, Univer!</div>',})univerAPI.registerComponent('MyVue2Component', Vue2Component, { framework: 'vue2',})Web Components
Pour enregistrer des Web Components, assurez-vous qu’ils respectent le standard Web Components, puis installez et enregistrez le plugin UniverWebComponentAdapterPlugin du package @univerjs/ui-adapter-web-component :
pnpm add @univerjs/ui-adapter-web-componentnpm install @univerjs/ui-adapter-web-componentyarn add @univerjs/ui-adapter-web-componentbun add @univerjs/ui-adapter-web-componentimport { UniverWebComponentAdapterPlugin } from '@univerjs/ui-adapter-web-component'univer.registerPlugin(UniverWebComponentAdapterPlugin)Lors de l’enregistrement de Web Components, vous devez définir l’option framework sur 'web-component' :
class WebComponent extends HTMLElement { constructor() { super() const shadow = this.attachShadow({ mode: 'open' }) const div = document.createElement('div') div.textContent = 'Hello Univer!' shadow.appendChild(div) }}univerAPI.registerComponent('my-web-component', WebComponent, { framework: 'web-component',})Angular
Convertissez un composant Angular en élément personnalisé avec createCustomElement de @angular/elements, puis enregistrez-le avec l’adaptateur Web Component de Univer. Il pourra apparaître dans une barre latérale ou un dialogue.
Ajoutez @angular/elements à la même version que @angular/core, et @univerjs/ui-adapter-web-component à la même version que les autres packages Univer.
Appelez cette fonction après l’initialisation de Univer. Dans le composant hôte, obtenez l’injecteur avec private readonly injector = inject(Injector), puis appelez registerAngularPanel(univer, univerAPI, this.injector). Importez inject et Injector depuis @angular/core dans ce composant.
import type { Injector } from '@angular/core'import type { FUniver, Univer } from '@univerjs/presets'import { Component } from '@angular/core'import { createCustomElement } from '@angular/elements'import { UniverWebComponentAdapterPlugin } from '@univerjs/ui-adapter-web-component'@Component({ selector: 'app-angular-panel', standalone: true, template: '<p>Hello from Angular!</p>',})export class AngularPanelComponent {}export function registerAngularPanel(univer: Univer, univerAPI: FUniver, injector: Injector) { const element = createCustomElement(AngularPanelComponent, { injector }) univer.registerPlugin(UniverWebComponentAdapterPlugin) return univerAPI.registerComponent('univer-angular-panel', element, { framework: 'web-component', })}Une fois l’éditeur rendu, utilisez la clé enregistrée comme contenu de la barre latérale :
const sidebar = univerAPI.openSidebar({ header: { title: 'Angular' }, children: { label: 'univer-angular-panel' }, width: 360,})Conservez les handles d’enregistrement et de barre latérale, puis appelez leur méthode dispose() quand ils ne sont plus nécessaires. Enregistrez l’élément une seule fois dans l’application. Son nom doit contenir un trait d’union et différer du selector Angular.
Angular Elements convertit les entrées en propriétés et les sorties en événements DOM CustomEvent. L’adaptateur Univer transmet les propriétés sans s’abonner automatiquement aux sorties Angular : reliez explicitement les événements nécessaires.
Utiliser des composants personnalisés
Les méthodes suivantes vous permettent d’intégrer avec souplesse différents composants personnalisés dans Univer afin d’enrichir et d’adapter ses fonctionnalités.
Attention
- Avant d’utiliser ces méthodes, assurez-vous qu’Univer a terminé le rendu. 2. Pour les composants qui doivent être
enregistrés, vérifiez que leur enregistrement a bien été effectué avant de les utiliser. 3. Utilisez la méthode
dispose()pour nettoyer et supprimer les composants ajoutés afin d’éviter les fuites de mémoire.
Ajouter des éléments de menu personnalisés
La barre de menu supérieure (Ribbon) et le menu contextuel (Context Menu) peuvent tous deux contenir des composants personnalisés. Pour ajouter ces composants à des éléments de menu, vous devez créer un plugin personnalisé. Nous avons préparé un guide de bonnes pratiques pour l’ajout d’éléments de menu personnalisés afin de vous aider à démarrer rapidement.
Remplacer des composants intégrés
Avertissement
Le remplacement de composants intégrés peut empêcher certaines fonctionnalités de fonctionner correctement. Lisez attentivement le code source et la documentation avant de tenter de remplacer des composants, et procédez avec prudence.
univerAPI.registerComponent enregistre une substitution par défaut (override: true). Elle est prioritaire, quel que soit l’ordre d’enregistrement du composant par défaut du plugin. Une seule substitution peut être active par componentKey : libérez la précédente avant d’en enregistrer une autre. La méthode dispose() de l’objet retourné rétablit le composant par défaut, s’il est enregistré. Utilisez { override: false } pour enregistrer un composant par défaut.
Enregistrez la substitution avant la première ouverture de la vue. Modifier l’enregistrement ne déclenche pas automatiquement un nouveau rendu des vues déjà montées.
Les entrées publiques des packages Sheets exposent ces clés pour remplacer les composants intégrés correspondants :
| Composant | Clé exportée | Package |
|---|---|---|
| Noms définis | DEFINED_NAME_CONTAINER | @univerjs/sheets-ui |
| Autres fonctions | MORE_FUNCTIONS_COMPONENT | @univerjs/sheets-formula-ui |
| Validation des données | DATA_VALIDATION_PANEL | @univerjs/sheets-data-validation-ui |
| Mise en forme conditionnelle | CF_PANEL_KEY | @univerjs/sheets-conditional-formatting-ui |
Par exemple, pour remplacer simplement le composant ColorPicker intégré :
// Following code only replaces the UI of the built-in ColorPicker component, not its functionalityuniverAPI.registerComponent('UI_COLOR_PICKER_COMPONENT', () => <input type="color" />)Utiliser des composants comme contenu
Dans la barre latérale
La méthode univerAPI.openSidebar permet d’ouvrir dans l’interface d’Univer une barre latérale contenant un composant personnalisé.
// You should register the component at an appropriate time (e.g., after Univer has loaded)univerAPI.registerComponent('MyCustomSidebarComponent', () => <div>Hello Univer!</div>)const sidebar = univerAPI.openSidebar({ header: { title: 'My Sidebar' }, children: { label: 'MyCustomSidebarComponent' }, onClose: () => { console.log('close') }, width: 360,})// Later close the sidebarsidebar.dispose()Référence : univerAPI.openSidebar
Dans une boîte de dialogue
La méthode univerAPI.openDialog permet d’ouvrir une boîte de dialogue contenant un composant personnalisé.
// You should register the component at an appropriate time (e.g., after Univer has loaded)univerAPI.registerComponent('MyCustomDialogComponent', () => <div>Hello Univer!</div>)const dialog = univerAPI.openDialog({ id: 'unique-dialog-id', // The unique identifier for the dialog draggable: true, width: 300, title: { title: 'My Dialog' }, children: { label: 'MyCustomDialogComponent', }, destroyOnClose: true, preservePositionOnDestroy: true, onClose: () => {},})// Later close the dialogdialog.dispose()Référence : univerAPI.openDialog
Associer une fenêtre contextuelle à des cellules
La méthode FRange.attachPopup permet d’associer une fenêtre contextuelle personnalisée à une plage de cellules donnée.
- Une fenêtre contextuelle est un élément DOM temporaire associé à une cellule. Elle sert généralement à afficher des informations d’état provisoires et ne prend pas en charge le stockage persistant.
- La méthode
FRange.attachPopup(popup: IFCanvasPopup)permet d’associer une fenêtre contextuelle personnalisée à une plage de cellules donnée. - La fenêtre contextuelle se fixe sur les bords de la cellule et ajuste automatiquement sa position et son orientation si elle est masquée.
// You should register the component at an appropriate time (e.g., after Univer has loaded)univerAPI.registerComponent('MyCustomPopupComponent', () => <div>Hello Univer!</div>)const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()const fRange = fWorksheet.getRange('A1:J10')// Attach the popup to the first cell of the range// If `disposable` is null, it indicates that the popup was not added successfullyconst disposable = fRange.attachPopup({ componentKey: 'MyCustomPopupComponent',})// Remove the popupdisposable.dispose()Associer une fenêtre contextuelle d’alerte
La méthode FRange.attachAlertPopup permet d’associer une fenêtre contextuelle d’alerte à la cellule de départ d’une plage donnée.
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()const fRange = fWorksheet.getRange('A1:B2')const disposable = fRange.attachAlertPopup({ key: 'unique-alert-key', // Unique identifier title: '这是一个警告!', message: '这是一个警告!', width: 300, height: 200, // 0: Information // 1: Warning // 2: Error type: 0,})// Remove the alert laterdisposable.dispose()Ajouter un DOM flottant à une feuille de calcul
La méthode FWorksheet.addFloatDomToPosition permet d’ajouter un DOM flottant à une feuille de calcul.
- Avant d’utiliser cette méthode, vous devez installer le plugin
@univerjs/sheets-drawing-uiou le preset@univerjs/preset-sheets-drawing. - Le DOM flottant est un composant déplaçable qui s’affiche au-dessus de la feuille de calcul et prend en charge le stockage persistant.
- Vous devez appeler cette méthode une fois le rendu d’Univer terminé.
componentKey: identifiant unique du composant, utilisé pour y faire référence dans Univer.- Définition complète des paramètres
// You should register the component at an appropriate time (e.g., after Univer has loaded)univerAPI.registerComponent('MyCustomFloatDOMComponent', ({ data }) => ( <div> Hello {data?.label}! </div>))const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()// Add a floating DOM to the worksheet// If `disposable` is null, it indicates that the floating DOM was not added successfullyconst disposable = fWorksheet.addFloatDomToPosition({ componentKey: 'MyCustomFloatDOMComponent', initPosition: { startX: 100, endX: 200, startY: 100, endY: 200, }, // The data for the component data: { label: 'Univer', },})// Remove the floating DOMdisposable.dispose()Que pensez-vous de ce guide ?