Migrando de UserCustomAction para extensões de Estrutura do SharePoint
Muitas soluções corporativas criadas em cima do Microsoft 365 e do SharePoint Online aproveitaram a funcionalidade do site CustomAction da Estrutura de Recursos do SharePoint para estender a interface do usuário das páginas. Na interface do usuário "moderna" atual do SharePoint Server 2019 e do SharePoint Online, a maioria dessas personalizações não está mais disponível. Felizmente, com Estrutura do SharePoint extensões, você pode fornecer funcionalidade semelhante na interface do usuário "moderna".
Neste tutorial, você aprende a migrar das antigas personalizações "clássicas" para o novo modelo com base nas Extensões da Estrutura do SharePoint.
Primeiro, vamos apresentar as opções disponíveis ao desenvolver Extensões da Estrutura do SharePoint:
- Personalizador de Aplicativos: estende a interface do usuário nativa "moderna" do SharePoint Online adicionando o código do cliente e elementos HTML personalizados a espaços reservados predefinidos das páginas "modernas". Para obter mais informações sobre personalizadores de aplicativos, consulte Compilar sua primeira Extensão da Estrutura do SharePoint (Olá, Mundo parte um).
- Conjunto de Comandos: permite adicionar itens de menu ECB personalizados ou botões personalizados à barra de comandos do modo de exibição de lista de uma lista ou uma biblioteca. Você pode associar qualquer ação do lado do cliente a esses comandos. Para obter mais informações sobre conjuntos de comandos, consulte Construir sua primeira extensão do Conjunto de Comandos ListView.
- Personalizador de Campos: personaliza a renderização de um campo em um modo de exibição de lista usando elementos HTML personalizados e o código do cliente. Para obter mais informações sobre personalizadores de campo, consulte Compilar sua primeira extensão do Personalizador de Campos.
A opção mais útil nesse contexto é a extensão Personalizador de Aplicativo.
Suponha que você tenha um CustomAction no SharePoint Online para ter um rodapé personalizado em todas as páginas do site.
No seguinte trecho de código, é possível ver o código XML que define CustomAction usando a Estrutura de Recursos do 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 é possível ver, o arquivo de elementos do recurso define alguns dos elementos do tipo CustomAction para incluir nas páginas do site de destino o jQuery, carregado pela CDN pública, e um arquivo JavaScript personalizado que renderiza o rodapé personalizado.
Para fins de integridade, veja o código JavaScript que renderiza um rodapé personalizado, cujos itens de menu estão predefinidos no código para manter a simplicidade.
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');
});
Na figura a seguir, observe a saída da ação personalizada anterior na página inicial de um site clássico.
Para migrar a solução anterior para a interface de usuário "moderna", confira as etapas a seguir.
Criar uma nova solução da Estrutura do SharePoint
No console, crie uma nova pasta para o seu projeto:
md spfx-react-custom-footer
Vá até a pasta do projeto:
cd spfx-react-custom-footer
Na pasta do projeto, execute o gerador Yeoman da Estrutura do SharePoint para estruturar um novo projeto da Estrutura do SharePoint:
yo @microsoft/sharepoint
Quando solicitado, insira os seguintes valores (selecione a opção padrão para todos os avisos omitidos abaixo):
- Qual é o nome da solução?: spfx-react-custom-footer
- Quais pacotes de linha de base que você deseja segmentar para o(s) seu(s) componente(s)?: somente SharePoint Online (mais recente)
- Que tipo de componente do lado do cliente deve ser criado?: Extensão
- Que tipo de extensão do lado do cliente criar? Personalizador de aplicativos
- Qual o nome do Personalizador de Campos? CustomFooter
Neste ponto, o Yeoman instala as dependências necessárias e mantém a estruturação dos arquivos e pastas da solução juntamente com a extensão CustomFooter. Isso pode levar alguns minutos.
Inicie o Visual Studio Code (ou o editor de código de sua preferência) e comece a desenvolver a solução. Para iniciar o Visual Studio Code, execute a seguinte instrução.
code .
Definir os novos elementos da interface do usuário
Os elementos da interface do usuário do rodapé personalizado são renderizados usando o React e um componente personalizado do React. Você pode criar os elementos da interface do usuário do rodapé de exemplo com qualquer tecnologia que desejar. Neste tutorial, usamos o React para aproveitar os componentes do Office UI Fabric para o React.
Abra a pasta arquivo ./src/extensions/customFooter/CustomFooterApplicationCustomizer.manifest.json . Copie o valor da propriedade
id
e armazene-o em um local seguro, pois você precisará dele mais tarde.Abra o arquivo ./src/extensions/customFooter/CustomFooterApplicationCustomizer.ts e importe os tipos
PlaceholderContent
ePlaceholderName
do pacote @microsoft/sp-application-base.E, no início do arquivo, adicione as
import
diretivas para React.No trecho de código a seguir, é possível ver a seção de importação do arquivo CustomFooterApplicationCustomizer.ts.
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';
Localize a definição da classe
CustomFooterApplicationCustomizer
e declare um novo membro particular chamadobottomPlaceholder
do tipoPlaceholderContent | undefined
.Na substituição do método
onInit()
, invoque uma função personalizada chamadarenderPlaceHolders
e defina essa função.No trecho de código a seguir, você pode ver a implementação da classe personalizador de aplicativo de rodapé 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); } } }
O método
renderPlaceHolders()
procura o espaço reservado do tipoBottom
e, se houver algum, renderiza seu conteúdo. Na verdade, no final dorenderPlaceHolders()
método, o código cria uma nova instância de umCustomFooter
componente React e o renderiza dentro do espaço reservado da parte inferior das páginas (ou seja, onde o rodapé deve ser renderizado).Observação
O componente do React é a substituição na interface do usuário "moderna" do arquivo JavaScript no modelo "clássico". E, claro, é possível processar o rodapé inteiro usando o código JavaScript puro e reutilizar a maior parte do código que você já tem. No entanto, é melhor considerar a possibilidade de atualizar a implementação, não apenas de uma perspectiva tecnológica, mas, também, de uma perspectiva de código.
Adicione uma nova pasta nomeada componentes na pasta src/extensions/customFooter .
Crie um novo arquivo dentro da nova pasta e nomeie-o como CustomFooter.tsx.
Adicione o seguinte código a este arquivo:
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> ); } }
Esse documento não ensina como gravar um componente do React. Observe as
import
instruções no início, em que o componente importa React e oCommandButton
componente React da biblioteca de componentes do Office UI Fabric.No método
render()
do componente, ele define a saída deCustomFooter
com algumas instâncias do componenteCommandButton
para os links no rodapé. Toda a saída HTML está anexada a um layout de grade no Office UI Fabric.Observação
Saiba mais sobre o layout de grade do Office UI Fabric em Layout Responsivo.
Na figura a seguir, é possível ver a saída resultante.
Testar a solução no modo de depuração
Retorne à janela do console e execute o seguinte comando para criar a solução e executar o servidor Node.js local para hospedá-lo.
gulp serve --nobrowser
Agora, abra seu navegador favorito e vá para uma página "moderna" de qualquer site de equipe "moderno". Agora, acrescente os seguintes parâmetros de sequência de consulta à URL da página.
?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"82242bbb-f951-4c71-a978-80eb8f35e4c1":{"location":"ClientSideExtension.ApplicationCustomizer"}}
Na sequência de consulta, substitua o GUID pelo
id
valor salvo no arquivo CustomFooterApplicationCustomizer.manifest.json.Durante a execução de solicitação da página, uma caixa de mensagem de aviso é exibida com o título "Permitir scripts de depuração?", que solicita o consentimento para executar códigos de um host local por motivos de segurança. Se você quiser depurar localmente e testar a solução, é necessário permitir "Carregar scripts de depuração".
Observação
Como alternativa, você pode criar entradas de configuração de atendimento no arquivo
config/serve.json
em seu projeto para automatizar a criação dos parâmetros da cadeia de caracteres de consulta de depuração, conforme descrito neste documento: Depurar soluções da Estrutura do SharePoint em páginas modernas do SharePoint
Empacotar e hospedar a solução
Se você estiver satisfeito com o resultado, já pode empacotar a solução hospedá-la em uma infraestrutura de hospedagem real.
Antes de compilar o pacote, você precisa declarar um arquivo de Estrutura de Recursos XML para provisionar a extensão.
Revisar elementos da Estrutura de Recursos
No editor de código, abra o arquivo /sharepoint/assets/elements.xml. No trecho de código a seguir, é possível ver como deve ser a aparência do arquivo.
<?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 é possível ver, ele é semelhante ao arquivo da Estrutura de Recursos do SharePoint que vimos no modelo "clássico", mas usa o atributo
ClientSideComponentId
para fazer referência àid
da extensão personalizada. Você também pode adicionar umClientSideComponentProperties
atributo, se precisar fornecer configurações personalizadas à extensão, o que não é o caso neste tutorial.Abra a pasta arquivo ./config/package-solution.json da solução. No arquivo, você pode ver que há uma referência ao arquivo elements.xml na
assets
seção.{ "$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" } }
Empacotar, empacotar e implantar a solução
Em seguida, você precisa agrupar e empacotar o pacote de soluções para o catálogo de aplicativos. Para realizar essa tarefa, siga estas etapas.
Prepare e implante a solução para o locatário do SharePoint Online:
Execute a seguinte tarefa para reunir a solução. Isso executa uma versão de lançamento do seu projeto:
gulp bundle --ship
Execute a seguinte tarefa para criar um pacote para a solução. Esse comando cria um pacote *.sppkg na pasta sharepoint/solution .
gulp package-solution --ship
Carregue ou arraste e solte o pacote de solução recém-criado do lado do cliente no catálogo de aplicativos de seu locatário e então selecione o botão Implantar.
Instalar e executar a solução
Abra o navegador e acesse qualquer site de destino "moderno".
Vá até a página Conteúdo do Site e selecione adicionar um novo Aplicativo.
Escolha a opção para instalar um novo aplicativo De Sua Organização para procurar as soluções disponíveis no catálogo de aplicativos.
Escolha a solução chamada spfx-react-custom-footer-client-side-solution e instale-a no site de destino.
Após a conclusão da instalação do aplicativo, atualize a página ou vá para a home page do site. Você deve ver o rodapé personalizado em ação.
Aproveite seu novo rodapé personalizado criado usando as extensões Estrutura do SharePoint!