Migrar de UserCustomAction a Extensiones de SharePoint Framework
Muchas soluciones empresariales basadas en Microsoft 365 y SharePoint Online aprovecharon la funcionalidad CustomAction del sitio de SharePoint Feature Framework para ampliar la interfaz de usuario de las páginas. En la interfaz de usuario "moderna" actual de SharePoint Server 2019 y SharePoint Online, la mayoría de esas personalizaciones ya no están disponibles. Afortunadamente, con extensiones de SharePoint Framework, puede proporcionar una funcionalidad similar en la interfaz de usuario "moderna".
En este tutorial, obtendrá información sobre cómo migrar de las anteriores personalizaciones "clásicas" al nuevo modelo basado en extensiones de SharePoint Framework.
En primer lugar, se presentan las opciones disponibles al desarrollar extensiones de SharePoint Framework:
- Personalizador de aplicaciones: se amplía la interfaz de usuario "moderna" nativa de SharePoint agregando elementos HTML personalizados y código del lado cliente a los marcadores de posición predefinidos de páginas "modernas". Para más información sobre los personalizadores de aplicaciones, vea Compilar la primera extensión de SharePoint Framework (parte 1 de Hello World).
- Conjunto de comandos: agregue elementos de menú ECB personalizados o botones personalizados a la barra de comandos de una vista de lista para una lista o biblioteca. Puede asociar cualquier acción del lado cliente a estos comandos. Para más información sobre los conjuntos de comandos, vea Compilar la primera extensión del conjunto de comandos de ListView.
- Personalizador de campo: permite personalizar la representación de un campo en una vista de lista con elementos HTML personalizados y código del lado cliente. Para más información sobre los personalizadores de campo, vea Compilación de la primera extensión de Personalizador de campo.
La opción más útil en este contexto es la extensión Application Customizer.
Supongamos que tiene customAction en SharePoint Online para tener un pie de página personalizado en todas las páginas del sitio.
En el siguiente fragmento de código, puede ver el código XML que define ese evento CustomAction con el marco de características de SharePoint.
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomAction Id="jQueryCDN"
Title="jQueryCDN"
Description="Loads jQuery from the public CDN"
ScriptSrc="https://code.jquery.com/jquery-3.2.1.slim.min.js"
Location="ScriptLink"
Sequence="100" />
<CustomAction Id="spoCustomBar"
Title="spoCustomBar"
Description="Loads a script to rendere a custom footer"
Location="ScriptLink"
ScriptSrc="SiteAssets/SPOCustomUI.js"
Sequence="200" />
</Elements>
Como puede ver, el archivo de elementos de la característica define algunos elementos de tipo CustomAction para incluir en las páginas del sitio de destino: jQuery, cargadas a través de la red CDN pública, y un archivo personalizado de JavaScript que representa el pie de página personalizado.
Por razones de integridad, puede ver el código JavaScript que representa un pie de página personalizado, cuyos elementos de menú se definen previamente en el código por simplificar.
var SPOCustomUI = SPOCustomUI || {};
SPOCustomUI.setUpCustomFooter = function () {
if ($("#SPOCustomFooter").length)
return;
var footerContainer = $("<div>");
footerContainer.attr("id", "SPOCustomFooter");
footerContainer.append("<ul>");
$("#s4-workspace").append(footerContainer);
}
SPOCustomUI.addCustomFooterText = function (id, text) {
if ($("#" + id).length)
return;
var customElement = $("<div>");
customElement.attr("id", id);
customElement.html(text);
$("#SPOCustomFooter > ul").before(customElement);
return customElement;
}
SPOCustomUI.addCustomFooterLink = function (id, text, url) {
if ($("#" + id).length)
return;
var customElement = $("<a>");
customElement.attr("id", id);
customElement.attr("href", url);
customElement.html(text);
$("#SPOCustomFooter > ul").append($("<li>").append(customElement));
return customElement;
}
SPOCustomUI.loadCSS = function (url) {
var head = document.getElementsByTagName('head')[0];
var style = document.createElement('link');
style.type = 'text/css';
style.rel = 'stylesheet';
style.href = url;
head.appendChild(style);
}
SPOCustomUI.init = function (whenReadyDoFunc) {
// avoid executing inside iframes (used by SharePoint for dialogs)
if (self !== top) return;
if (!window.jQuery) {
// jQuery is needed for Custom Bar to run
setTimeout(function () { SPOCustomUI.init(whenReadyDoFunc); }, 50);
} else {
$(function () {
SPOCustomUI.setUpCustomFooter();
whenReadyDoFunc();
});
}
}
// The following initializes the custom footer with some fake links
SPOCustomUI.init(function () {
var currentScriptUrl;
var currentScript = document.querySelectorAll("script[src*='SPOCustomUI']");
if (currentScript.length > 0) {
currentScriptUrl = currentScript[0].src;
}
if (currentScriptUrl != undefined) {
var currentScriptBaseUrl = currentScriptUrl.substring(0, currentScriptUrl.lastIndexOf('/') + 1);
SPOCustomUI.loadCSS(currentScriptBaseUrl + 'SPOCustomUI.css');
}
SPOCustomUI.addCustomFooterText('SPOFooterCopyright', '© 2017, Contoso Inc.');
SPOCustomUI.addCustomFooterLink('SPOFooterCRMLink', 'CRM', 'CRM.aspx');
SPOCustomUI.addCustomFooterLink('SPOFooterSearchLink', 'Search Center', 'SearchCenter.aspx');
SPOCustomUI.addCustomFooterLink('SPOFooterPrivacyLink', 'Privacy Policy', 'Privacy.aspx');
});
En la siguiente ilustración, puede ver el resultado de la acción personalizada anterior en la página principal de un sitio clásico.
Para migrar la solución anterior a la interfaz de usuario "moderna", vea los siguientes pasos.
Crear una solución nueva de SharePoint Framework
Desde la consola, cree una carpeta para el proyecto:
md spfx-react-custom-footer
Vaya a la carpeta del proyecto:
cd spfx-react-custom-footer
En la carpeta del proyecto, ejecute el generador de Yeoman de SharePoint Framework para aplicar scaffolding a un nuevo proyecto de SharePoint Framework:
yo @microsoft/sharepoint
En el momento en que se le solicite, introduzca los siguientes valores (seleccione la opción predeterminada para todas las solicitudes que se omitan a continuación):
- ¿Cuál es el nombre de la solución?: spfx-react-custom-footer
- ¿Qué paquetes de línea base quiere usar como destino para el componente o los componentes?: solo SharePoint Online (versión más reciente)
- ¿Cuál es el tipo de componente del lado cliente que se va a crear?: Extensión
- ¿Qué tipo de extensión del lado cliente se va a crear? Personalizador de aplicación
- ¿Cuál es el nombre del personalizador de campo? CustomFooter
En este momento, Yeoman instalará las dependencias requeridas y aplicará scaffolding a los archivos y las carpetas de la solución con la extensión CustomFooter. Esta operación puede tardar unos minutos.
Inicie Visual Studio Code (o el editor de código que prefiera) y empiece a desarrollar la solución. Para iniciar Visual Studio Code, puede ejecutar la siguiente instrucción.
code .
Definir los elementos de la nueva interfaz de usuario
Los elementos de la interfaz de usuario del pie de página personalizado se representan con React y un componente de React personalizado. Puede crear los elementos de la interfaz de usuario del pie de página de ejemplo con la tecnología que quiera. En este tutorial, se usa React para aprovechar los componentes de Office UI Fabric para React.
Abra la carpeta ./src/extensions/customFooter/CustomFooterApplicationCustomizer.manifest.json del archivo. Copie el valor de la propiedad
id
y guárdelo en un lugar seguro, ya que lo necesitará más adelante.Abra el archivo ./src/extensions/customFooter/CustomFooterApplicationCustomizer.ts e importe los tipos
PlaceholderContent
yPlaceholderName
desde el paquete @microsoft/sp-application-base.Y, al principio del archivo, agregue las
import
directivas para React.Puede ver la sección de importaciones del archivo CustomFooterApplicationCustomizer.ts en el siguiente fragmento de código.
import * as React from 'react'; import * as ReactDom from 'react-dom'; import { override } from '@microsoft/decorators'; import { Log } from '@microsoft/sp-core-library'; import { BaseApplicationCustomizer, PlaceholderContent, PlaceholderName } from '@microsoft/sp-application-base'; import { Dialog } from '@microsoft/sp-dialog'; import * as strings from 'CustomFooterApplicationCustomizerStrings'; import CustomFooter from './components/CustomFooter';
Busque la definición de la clase
CustomFooterApplicationCustomizer
y declare un nuevo miembro privado denominadobottomPlaceholder
de tipoPlaceholderContent | undefined
.En la invalidación del método
onInit()
, invoque una función personalizada denominadarenderPlaceHolders
y defina esa función.En el fragmento de código siguiente, puede ver la implementación de la clase Application Customizer de pie de página personalizada.
/** A Custom Action which can be run during execution of a Client Side Application */ export default class CustomFooterApplicationCustomizer extends BaseApplicationCustomizer<ICustomFooterApplicationCustomizerProperties> { // This private member holds a reference to the page's footer private _bottomPlaceholder: PlaceholderContent | undefined; @override public onInit(): Promise<void> { Log.info(LOG_SOURCE, `Initialized ${strings.Title}`); let message: string = this.properties.testMessage; if (!message) { message = '(No properties were provided.)'; } // Call render method for rendering the needed html elements this._renderPlaceHolders(); return Promise.resolve(); } private _renderPlaceHolders(): void { // Handling the bottom placeholder if (!this._bottomPlaceholder) { this._bottomPlaceholder = this.context.placeholderProvider.tryCreateContent(PlaceholderName.Bottom); // The extension should not assume that the expected placeholder is available. if (!this._bottomPlaceholder) { console.error('The expected placeholder (Bottom) was not found.'); return; } const element: React.ReactElement<{}> = React.createElement(CustomFooter); ReactDom.render(element, this._bottomPlaceholder.domElement); } } }
El método
renderPlaceHolders()
busca el marcador de posición de tipoBottom
y, si lo hay, representa su contenido. De hecho, al final delrenderPlaceHolders()
método, el código crea una nueva instancia de unCustomFooter
componente React y lo representa dentro del marcador de posición de la parte inferior de las páginas (es decir, donde se debe representar el pie de página).Nota:
El componente de React será el reemplazo, en la interfaz de usuario "moderna", del archivo JavaScript del modelo "clásico". Por supuesto, todavía puede representar todo el pie de página con código JavaScript puro y reutilizando la mayor parte del código que ya tiene. No obstante, se recomienda considerar la posibilidad de actualizar la implementación no solo desde la perspectiva tecnológica, sino también desde la perspectiva del código.
Agregue una nueva carpeta denominada components en la carpeta src/extensions/customFooter .
Cree un archivo en la nueva carpeta y denomínelo CustomFooter.tsx.
Agregue el código siguiente a este archivo:
import * as React from 'react'; import { CommandButton } from 'office-ui-fabric-react/lib/Button'; export default class CustomFooter extends React.Component<{}, {}> { public render(): React.ReactElement<{}> { return ( <div className={`ms-bgColor-neutralLighter ms-fontColor-white`}> <div className={`ms-bgColor-neutralLighter ms-fontColor-white`}> <div className={`ms-Grid`}> <div className="ms-Grid-row"> <div className="ms-Grid-col ms-sm2 ms-md2 ms-lg2"> <CommandButton data-automation="CopyRight" href={`CRM.aspx`}>© 2017, Contoso Inc.</CommandButton> </div> <div className="ms-Grid-col ms-sm2 ms-md2 ms-lg2"> <CommandButton data-automation="CRM" iconProps={ { iconName: 'People' } } href={`CRM.aspx`}>CRM</CommandButton> </div> <div className="ms-Grid-col ms-sm2 ms-md2 ms-lg2"> <CommandButton data-automation="SearchCenter" iconProps={ { iconName: 'Search' } } href={`SearchCenter.aspx`}>Search Center</CommandButton> </div> <div className="ms-Grid-col ms-sm2 ms-md2 ms-lg2"> <CommandButton data-automation="Privacy" iconProps={ { iconName: 'Lock' } } href={`Privacy.aspx`}>Privacy Policy</CommandButton> </div> <div className="ms-Grid-col ms-sm4 ms-md4 ms-lg4"></div> </div> </div> </div> </div> ); } }
Enseñarle a escribir un componente de React queda fuera del ámbito de este documento. Observe las
import
instrucciones al principio, donde el componente importa React y elCommandButton
componente React de la biblioteca de componentes de Office UI Fabric.En el método
render()
del componente, se define el resultado delCustomFooter
con varias instancias del componenteCommandButton
para los vínculos del pie de página. Todo el resultado HTML se ajusta en un diseño de cuadrícula de Office UI Fabric.Nota:
Para más información sobre el diseño de cuadrícula de Office UI Fabric, vea Diseño dinámico.
Puede ver el resultado en la siguiente ilustración.
Probar la solución en modo de depuración
Volver a la ventana de la consola y ejecutar el siguiente comando para compilar la solución y ejecutar el servidor local Node.js para hospedarlo.
gulp serve --nobrowser
Abra ahora su explorador favorito y vaya a una página "moderna" de un sitio de grupo "moderno". Ahora, anexe los siguientes parámetros de cadena de consulta a la dirección URL de la página.
?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"82242bbb-f951-4c71-a978-80eb8f35e4c1":{"location":"ClientSideExtension.ApplicationCustomizer"}}
En esta cadena de consulta, reemplace el GUID por el valor de
id
que ha guardado en el archivo CustomFooterApplicationCustomizer.manifest.json.Tenga en cuenta que al ejecutar la solicitud de página, se le pedirá un cuadro de mensaje de advertencia con el título "Permitir scripts de depuración?", que le pide su consentimiento para ejecutar código desde localhost por motivos de seguridad. Si desea depurar y probar localmente la solución, tiene que permitir que "Cargar scripts de depuración".
Nota:
Como alternativa, puede crear entradas de configuración de servidor en el archivo
config/serve.json
del proyecto para automatizar la creación de los parámetros de cadena de consulta de depuración como se describe en este documento: Depurar soluciones de SharePoint Framework en páginas modernas de SharePoint
Empaquetar y hospedar la solución
Si le gusta el resultado, ya puede empaquetar la solución y hospedarla en una infraestructura de hospedaje real.
Antes de crear la agrupación y el paquete, deberá declarar un archivo XML de Feature Framework para aprovisionar la extensión.
Revisar los elementos de Feature Framework
En el editor de código, abra el archivo /sharepoint/assets/elements.xml. Puede ver el aspecto que debe tener el archivo en el siguiente fragmento de código.
<?xml version="1.0" encoding="utf-8"?> <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <CustomAction Title="CustomFooter" Location="ClientSideExtension.ApplicationCustomizer" ClientSideComponentId="82242bbb-f951-4c71-a978-80eb8f35e4c1"> </CustomAction> </Elements>
Como puede ver, recuerda al archivo del marco de características de SharePoint que se ha visto en el modelo "clásico", pero usa el atributo
ClientSideComponentId
para hacer referencia aid
de la extensión personalizada. También puede agregar unClientSideComponentProperties
atributo si necesita proporcionar una configuración personalizada a la extensión, que no es el caso en este tutorial.Abra la carpeta ./config/package-solution.json del archivo de la solución. Dentro del archivo, puede ver que hay una referencia al archivo elements.xml dentro de la
assets
sección .{ "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json", "solution": { "name": "spfx-react-custom-footer-client-side-solution", "id": "911728a5-7bde-4453-97b2-2eba59277ed3", "version": "1.0.0.0", "features": [ { "title": "Application Extension - Deployment of custom action.", "description": "Deploys a custom action with ClientSideComponentId association", "id": "f16a2612-3163-46ad-9664-3d3daac68cff", "version": "1.0.0.0", "assets": { "elementManifests": [ "elements.xml" ] } }] }, "paths": { "zippedPackage": "solution/spfx-react-custom-footer.sppkg" } }
Agrupación, empaquetado e implementación de la solución
Después debe empaquetar el paquete de soluciones en el catálogo de aplicaciones. Para realizar esta tarea, siga estos pasos.
Prepare e implemente la solución para el espacio empresarial de SharePoint Online:
Ejecute la tarea siguiente para agrupar la solución. Esto crea una compilación de versión del proyecto:
gulp bundle --ship
Ejecute la siguiente tarea para empaquetar la solución. Este comando crea un paquete *.sppkg en la carpeta sharepoint/solution .
gulp package-solution --ship
En el Catálogo de aplicaciones del espacio empresarial, cargue (o arrastre y coloque) el nuevo paquete de solución del lado cliente y, después, seleccione el botón Implementar.
Instalar y ejecutar la solución
Abra el explorador y navegue a cualquier sitio de destino "moderno".
Vaya a la página Contenidos del sitio y seleccione agregar una nueva Aplicación.
Seleccione esta opción para instalar una nueva aplicación De su organización para examinar las soluciones disponibles en el Catálogo de aplicaciones.
Seleccione la solución denominada spfx-react-custom-footer-client-side-solution e instálela en el sitio de destino.
Cuando se haya completado la instalación de la aplicación, actualice la página o vaya a la página principal del sitio. Debería ver el pie de página personalizado en acción.
¡Disfruta de tu nuevo pie de página personalizado creado con las extensiones de SharePoint Framework!