Compartilhar via


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', '&copy; 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.

O rodapé personalizado em uma página clássica

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

  1. No console, crie uma nova pasta para o seu projeto:

    md spfx-react-custom-footer
    
  2. Vá até a pasta do projeto:

    cd spfx-react-custom-footer
    
  3. Na pasta do projeto, execute o gerador Yeoman da Estrutura do SharePoint para estruturar um novo projeto da Estrutura do SharePoint:

    yo @microsoft/sharepoint
    
  4. 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.

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

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

  2. Abra o arquivo ./src/extensions/customFooter/CustomFooterApplicationCustomizer.ts e importe os tipos PlaceholderContent e PlaceholderName 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';
    
  3. Localize a definição da classe CustomFooterApplicationCustomizer e declare um novo membro particular chamado bottomPlaceholder do tipo PlaceholderContent | undefined.

  4. Na substituição do método onInit(), invoque uma função personalizada chamada renderPlaceHolders 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 tipo Bottom e, se houver algum, renderiza seu conteúdo. Na verdade, no final do renderPlaceHolders() método, o código cria uma nova instância de um CustomFooter 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.

  5. Adicione uma nova pasta nomeada componentes na pasta src/extensions/customFooter .

  6. 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`}>&copy; 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 o CommandButton componente React da biblioteca de componentes do Office UI Fabric.

    No método render() do componente, ele define a saída de CustomFooter com algumas instâncias do componente CommandButton 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.

    O rodapé personalizado renderizado em um site

Testar a solução no modo de depuração

  1. 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
    
  2. 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

  1. 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 um ClientSideComponentProperties atributo, se precisar fornecer configurações personalizadas à extensão, o que não é o caso neste tutorial.

  2. 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:

  1. Execute a seguinte tarefa para reunir a solução. Isso executa uma versão de lançamento do seu projeto:

    gulp bundle --ship
    
  2. 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
    
  3. 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

  1. Abra o navegador e acesse qualquer site de destino "moderno".

  2. Vá até a página Conteúdo do Site e selecione adicionar um novo Aplicativo.

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

  4. Escolha a solução chamada spfx-react-custom-footer-client-side-solution e instale-a no site de destino.

    Adicionar uma Interface do Usuário do Aplicativo para adicionar a solução a um site

  5. 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!

Confira também