Поделиться через


Переход от UserCustomAction к расширениям SharePoint Framework

Многие корпоративные решения, созданные на основе Microsoft 365 и SharePoint Online, использовали возможность сайта CustomAction sharePoint Feature Framework для расширения пользовательского интерфейса страниц. В текущем "современном" пользовательском интерфейсе SharePoint Server 2019 и SharePoint Online большинство этих настроек больше не доступны. К счастью, с помощью расширений SharePoint Framework вы можете предоставить аналогичные функции в "современном" пользовательском интерфейсе.

Из данного руководства вы узнаете, как перейти со старых ("классических") настроек на новую модель на основе расширений SharePoint Framework.

Сначала рассмотрим доступные разработчикам варианты для создания расширений SharePoint Framework.

  • Настройщик приложений. Расширьте встроенный "современный" пользовательский интерфейс SharePoint, добавив пользовательские элементы HTML и клиентский код в заранее определенные заполнители на "современных" страницах. Дополнительные сведения о настройщиках приложений см. в разделе Создание первого расширения SharePoint Framework (Hello World, часть 1)
  • Набор команд. добавляет пользовательские пункты меню ECB и настраиваемые кнопки на панель команд или в представление списка или библиотеки. С этими командами можно связать любое действие на стороне клиента. Дополнительные сведения о наборах команд см. в разделе Создание первого расширения набора команд ListView.
  • Настройщик полей. Настройте отображение поля в представлении списка, используя настраиваемые элементы HTML и клиентский код. Дополнительные сведения о настройщиках полей см. в разделе Создание первого расширения настройщика полей.

Наиболее полезным вариантом в этом контексте является расширение настройщика приложений.

Предположим, что у вас есть customAction в SharePoint Online для пользовательского нижнего колонтитула на всех страницах сайта.

Ниже представлен XML-код этого элемента CustomAction на платформе SharePoint Feature Framework.

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

Как видите, в файле определено несколько элементов типа CustomAction, которые необходимо включить на страницы целевого сайта: код jQuery, загружаемый через общедоступную сеть CDN, и пользовательский файл JavaScript.

Для полноты картины ниже показан код JavaScript, который отрисовывает специальный нижний колонтитул с предопределенными элементами меню.

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

На следующем рисунке показан результат предыдущего дополнительного действия на домашней странице классического сайта.

Специальный нижний колонтитул на классической странице

Ниже описано, как перенести старое решение в "современный" пользовательский интерфейс.

Создание решения SharePoint Framework

  1. С помощью консоли создайте папку для проекта:

    md spfx-react-custom-footer
    
  2. Перейдите в папку проекта:

    cd spfx-react-custom-footer
    
  3. В папке проекта запустите генератор Yeoman для SharePoint Framework, чтобы сформировать шаблон проекта на платформе SharePoint Framework:

    yo @microsoft/sharepoint
    
  4. При появлении запроса введите следующие значения (выберите вариант по умолчанию для всех запросов, не перечисленных ниже).

    • Как называется ваше решение?: spfx-react-custom-footer
    • Какие базовые пакеты нужно выбрать как целевые для ваших компонентов? Только SharePoint Online (последняя версия)
    • Какой тип клиентского компонента нужно создать?: Расширение
    • Какой тип клиентского расширения нужно создать? Настройщик заполнителей
    • Как называется настройщик полей? CustomFooter

    На этом этапе Yeoman устанавливает необходимые зависимости и выполняет скаффолдинг файлов и папок решения вместе с расширением CustomFooter. Это может занять несколько минут.

  5. Запустите Visual Studio Code (или другой редактор кода) и начните разработку решения. Чтобы запустить Visual Studio Code, можно выполнить следующий оператор:

    code .
    

Определение новых элементов пользовательского интерфейса

Элементы специального нижнего колонтитула отрисовываются с помощью React и пользовательского компонента React. Элементы пользовательского интерфейса примера нижнего колонтитула можно создать с помощью любой технологии. В этом руководстве мы используем React, чтобы получить доступ к компонентам Office UI Fabric для React.

  1. Откройте папку ./src/extensions/customFooter/CustomFooterApplicationCustomizer.manifest.json . Скопируйте значение свойства id и сохраните его в надежном месте, так как оно понадобится вам позже.

  2. Откройте файл ./src/extensions/customFooter/CustomFooterApplicationCustomizer.ts и импортируйте типы PlaceholderContent и PlaceholderName из пакета @microsoft/sp-application-base.

    В самом начале файла добавьте import директивы для React.

    В приведенном ниже фрагменте кода показан раздел импорта в файле 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. Найдите определение класса CustomFooterApplicationCustomizer и объявите новый частный элемент bottomPlaceholder типа PlaceholderContent | undefined.

  4. В переопределении метода onInit() вызовите пользовательскую функцию renderPlaceHolders и определите эту функцию.

    В следующем фрагменте кода вы можете увидеть реализацию пользовательского класса Application Customizer для нижнего колонтитула.

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

    Метод renderPlaceHolders() ищет заполнитель типа Bottom и (если он найден) отрисовывает его содержимое. Фактически в самом конце renderPlaceHolders() метода код создает новый экземпляр CustomFooter компонента React и отображает его в заполнитель нижней части страницы (то есть в том месте, где должен быть отрисован нижний колонтитул).

    Примечание.

    В "современной" модели компонент React заменяет файл JavaScript из "классической" модели. Конечно, вы можете по-прежнему отрисовывать нижний колонтитул, используя по большей части имеющийся чистый код JavaScript. Однако рекомендуется обновить реализацию. Это целесообразно с методологической, и с практической точки зрения.

  5. Добавьте новую папку с именем components в папку src/extensions/customFooter .

  6. Создайте в новой папке файл и назовите его CustomFooter.tsx.

    Добавьте следующий код в этот файл:

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

    В данном документе не рассматривается создание компонента React. Обратите внимание на инструкции import в начале, где компонент импортирует React, а CommandButton компонент React из библиотеки компонентов Office UI Fabric.

    Вывод компонента CustomFooter определен в методе render() с несколькими экземплярами компонента CommandButton, представляющими собой ссылки в нижнем колонтитуле. Все выходные данные HTML заключены в макет сетки из Office UI Fabric.

    Примечание.

    Дополнительные сведения о макете сетки Office UI Fabric см. в разделе Гибкий макет.

    На приведенном ниже рисунке показан результат.

    Специальный нижний колонтитул на

Тестирование решения в режиме отладки

  1. Вернитесь в окно консоли и выполните приведенную ниже команду, чтобы выполнить сборку и запустить локальный сервер Node.js для размещения решения.

    gulp serve --nobrowser
    
  2. Теперь откройте любой браузер и перейдите на "современную" страницу любого "современного" сайта группы. Добавьте приведенные ниже параметры строки запроса в URL-адрес страницы.

    ?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"82242bbb-f951-4c71-a978-80eb8f35e4c1":{"location":"ClientSideExtension.ApplicationCustomizer"}}
    

    В этой строке запроса замените GUID сохраненным значением id из файла CustomFooterApplicationCustomizer.manifest.json.

    При выполнении запроса страницы появится запрос разрешения на запуск кода с домена localhost (окно с заголовком "Разрешить скрипты отладки?"). Если вы хотите отладить и протестировать решение локально, необходимо разрешить загрузку скриптов отладки.

    Примечание.

    Либо можно создавать записи конфигурации службы в файле config/serve.json проекта для автоматизации создания параметров строки запроса отладки, как описано в этом документе: Отладка решений SharePoint Framework на современных страницах SharePoint

Упаковка и размещение решения

Если вы довольны результатом, упакуйте решение и разместите его в настоящей инфраструктуре.

Прежде чем собирать пакет, необходимо объявить XML-файл Feature Framework для подготовки расширения.

Обзор элементов Feature Framework

  1. В редакторе кода откройте файл /sharepoint/assets/elements.xml. В приведенном ниже фрагменте кода показано, как должен выглядеть файл.

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

    Как видите, он напоминает файл SharePoint Feature Framework из "классической" модели, но использует атрибут ClientSideComponentId, чтобы ссылаться на свойство id специального расширения. Вы также можете добавить ClientSideComponentProperties атрибут, если вам нужно предоставить настраиваемые параметры для расширения, что не так в этом руководстве.

  2. Откройте папку ./config/package-solution.json решения. В файле можно увидеть ссылку на файлelements.xml в assets разделе.

    {
      "$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"
      }
    }
    

Объединение, упаковка и развертывание решения

Затем необходимо объединить в пакет и упаковать пакет решения в каталог приложений. Для этого выполните указанные ниже действия.

Подготовьте и разверните решение для клиента SharePoint Online:

  1. Выполните приведенную ниже задачу, чтобы создать пакет решения. При этом создается сборка выпуска проекта:

    gulp bundle --ship
    
  2. Выполните приведенную ниже задачу, чтобы упаковать решение. Эта команда создает пакет *.sppkg в папке sharepoint/solution .

    gulp package-solution --ship
    
  3. Добавьте или перетащите новый пакет клиентского решения в каталог приложений в клиенте и нажмите кнопку Развернуть.

Установка и запуск решения

  1. Откройте браузер и перейдите на любой "современный" сайт.

  2. Перейдите на страницу Содержимое сайта и добавьте новое приложение.

  3. Выберите Из вашей организации, чтобы просмотреть решения, доступные в каталоге приложений.

  4. Выберите решение spfx-react-custom-footer-client-side-solution и установите его на целевом сайте.

    Добавление решения на сайт

  5. После установки приложения обновите страницу или перейдите на домашнюю страницу сайта. Вы должны увидеть пользовательский нижний колонтитул в действии.

Наслаждайтесь новым пользовательским нижним колонтитулом, созданным с помощью расширений SharePoint Framework!

См. также