Share via


UserCustomAction から SharePoint Framework 機能拡張への移行

Microsoft 365 と SharePoint Online の上に構築された多くのエンタープライズ ソリューションでは、SharePoint Feature Framework のサイト CustomAction 機能を利用してページの UI を拡張しました。 SharePoint Server 2019と SharePoint Online の現在の "モダン" UI では、これらのカスタマイズのほとんどは使用できなくなりました。 幸いなことに、SharePoint Framework拡張機能では、"モダン" UI で同様の機能を提供できます。

このチュートリアルでは、以前の "クラシック" カスタマイズから SharePoint Framework 拡張機能に基づく新しいモデルに移行する方法について説明します。

最初に、SharePoint Framework 拡張機能を開発するときに使用できるオプションを紹介します。

  • アプリケーション カスタマイザー: "モダン" ページの事前定義されたプレースホルダーにカスタム HTML 要素とクライアント側コードを追加することによって、SharePoint のネイティブ "モダン"UI を拡張します。 アプリケーション カスタマイザーの詳細については、「SharePoint Framework の最初の拡張機能をビルドする (Hello World パート 1)」を参照してください。
  • コマンド セット: カスタムの編集コントロール ブロック (ECB) のメニュー項目またはカスタム ボタンを、リストまたはライブラリのリスト ビューのコマンド バーに追加します。 これらのコマンドには、任意のクライアント側アクションを関連付けることができます。 コマンド セットの詳細については、「最初の ListView コマンド セット拡張機能をビルドする」を参照してください。
  • フィールド カスタマイザー: カスタム HTML 要素とクライアント側コードを使用して、リスト ビュー内のフィールドの表示をカスタマイズします。 フィールド カスタマイザーの詳細については、「最初のフィールド カスタマイザー拡張機能をビルドする」を参照してください。

このコンテキストで最も便利なオプションは、Application Customizer 拡張機能です。

SharePoint Online に CustomAction があり、サイトのすべてのページにカスタム フッターがあるとします。

次のコード スニペットでは、SharePoint フィーチャー フレームワークを使用して CustomAction を定義する XML コードを確認できます。

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

ご覧のように、機能の要素ファイルは、パブリック CDN を介して読み込まれた jQuery と、ユーザー設定のフッターをレンダリングするユーザー独自の JavaScript ファイルをターゲット サイトのページに含めるための、いくつかの CustomAction の種類の要素を定義します。

完全性の確保のため、ユーザー設定のフッターをレンダリングする 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');
});

次の図では、従来のサイトのホーム ページ内での、前のカスタム アクションの出力を確認することができます。

従来のページでのユーザー設定のフッター

従来のソリューションを "モダン” UI に移行するには、次の手順を参照してください。

新しい SharePoint Framework ソリューションの作成

  1. コンソールから、プロジェクト用の新しいフォルダーを作成します。

    md spfx-react-custom-footer
    
  2. プロジェクト フォルダーに移動します。

    cd spfx-react-custom-footer
    
  3. プロジェクト フォルダーで SharePoint Framework Yeoman ジェネレーターを実行して、新しい SharePoint Framework プロジェクトをスキャホールディングします。

    yo @microsoft/sharepoint
    
  4. プロンプトが表示されたら、以下の値を入力します (以下で省略されたすべてのプロンプトに対して既定のオプションを選択します)。

    • ソリューション名は何ですか?: spfx-react-custom-footer
    • どのベースライン パッケージをコンポーネントのターゲットにしますか?: SharePoint Online のみ (最新)
    • どの種類のクライアント側コンポーネントを作成しますか?: 拡張機能
    • どの種類のクライアント側拡張機能を作成しますか? アプリケーション カスタマイザー
    • フィールド カスタマイザーの名前は何ですか? CustomFooter

    この時点で、Yeoman は必要な依存関係をインストールし、ソリューション ファイルおよびフォルダーを CustomFooter 拡張機能とともにスキャフォールディングします。 これには数分かかる場合があります。

  5. Visual Studio Code (または選択した他のコード エディター) を起動し、ソリューションの開発を開始します。 Visual Studio Code を開始するには、次のステートメントを実行します。

    code .
    

新しい UI 要素を定義する

ユーザー設定のフッターの UI 要素は、React とユーザー設定の React コンポーネントによってレンダリングされます。 好きなテクノロジを使用して、サンプル フッターの UI 要素を作成できます。 このチュートリアルでは、React の Office UI Fabric コンポーネントを活用するために、React を使用します。

  1. ファイル ./src/extensions/customFooter/CustomFooterApplicationCustomizer.manifest.json フォルダーを開きます。 id プロパティの値をコピーします。この値は後で必要になるため、安全な場所に保存します。

  2. ファイル ./src/extensions/customFooter/CustomFooterApplicationCustomizer.ts を開き、型PlaceholderContentPlaceholderName パッケージ @microsoft/sp-application-base からインポートします。

    また、ファイルの先頭に、Reactのディレクティブを追加importします。

    次のコードの引用部分で、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 の定義を検索し、種類 PlaceholderContent | undefinedbottomPlaceholder と呼ばれる新しいプライベート メンバーを宣言します。

  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()最後に、コードはReact コンポーネントの新しいインスタンスをCustomFooter作成し、ページの下部 (つまりフッターをレンダリングする必要がある) のプレースホルダー内にレンダリングします。

    注:

    "モダン" UI の React コンポーネントは、"クラシック" モデルの JavaScript ファイルの代わりです。 もちろん、純粋な JavaScript コードを使用し、既存のコードの大部分を再利用してフッター全体をレンダリングすることもできます。 ただし、テクノロジの観点からだけでなく、コードの観点からも、実装のアップグレードを検討することをお勧めします。

  5. src/extensions/customFooter フォルダーに components という名前の新しいフォルダーを追加します。

  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 のコンポーネントの記述方法については記載されていません。 コンポーネントがimportReactをインポートする最初のステートメントとCommandButton、Office UI Fabric コンポーネント ライブラリからReact コンポーネントに注目してください。

    コンポーネントの render() メソッドでは、フッター内のリンクの CommandButton コンポーネントのごく少数のインスタンスを伴う CustomFooter の出力が定義されています。 すべての HTML 出力は、Office UI Fabric のグリッド レイアウト内にラップされます。

    注:

    Office の UI ファブリックのグリッド レイアウトの詳細については、「応答性の高いレイアウト」を参照してください。

    次の図では、出力結果を確認できます。

デバッグ モードでソリューションをテストする

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

    このクエリ文字列では、CustomFooterApplicationCustomizer.manifest.json ファイルから保存した id の値で GUID を置き換えます。

    ページ要求を実行すると、セキュリティ上の理由から、"デバッグ スクリプトを許可しますか?" という警告メッセージ ボックスが表示され、ローカルホストからのコード実行への同意を求められます。 ソリューションをローカルでデバッグしてテストする場合は、"デバッグ スクリプトを読み込む" ことをそれに許可する必要があります。

    注:

    または、プロジェクト内の config/serve.json ファイルにサービス構成エントリを作成して、「SharePoint のモダン ページでの SharePoint Framework ソリューションのデバッグ」で説明するデバッグ クエリ文字列パラメーターの作成を自動化することもできます。

ソリューションをパッケージ化してホストする

結果に問題がなければ、ソリューションをパッケージ化して実際のホスティング インフラストラクチャでホストする準備が整ったことになります。

バンドルとパッケージを構築する前に、拡張機能をプロビジョニングするために XML フィーチャー フレームワーク ファイルを宣言する必要があります。

フィーチャー フレームワーク要素を確認する

  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 ファイルのように見えますが、ユーザー設定の拡張機能の id を参照するために ClientSideComponentId 属性を使用しています。 拡張機能にカスタム設定を ClientSideComponentProperties 指定する必要がある場合は、属性を追加することもできます。このチュートリアルではそうではありません。

  2. ソリューションの ファイル ./config/package-solution.json フォルダーを開きます。 ファイル内には、セクション内assetselements.xml ファイルへの参照があることがわかります。

    {
      "$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. 次のタスクを実行して、ソリューションをパッケージ化します。 このコマンドは、sharepoint/solution フォルダーに *.sppkg パッケージを作成します。

    gulp package-solution --ship
    
  3. 新しく作成したクライアント側ソリューション パッケージを、テナント内のアプリ カタログにアップロードまたはドラッグ アンド ドロップし、[展開] ボタンを選択します。

ソリューションのインストールと実行

  1. ブラウザーを開き、任意の "モダン" ターゲット サイトに移動します。

  2. [サイト コンテンツ] ページに移動し、新しいアプリの追加を選択します。

  3. [組織から] でインストールする新しいアプリを選択して、アプリ カタログで使用可能なソリューションを参照します。

  4. spfx-react-custom-footer-client-side-solution というソリューションを選択し、ターゲット サイトにインストールします。

    アプリの UI を追加して、サイトにソリューションを追加する

  5. アプリケーションのインストールが完了した後、ページを更新するか、サイトのホーム ページに移動します。 動作中のカスタム フッターが表示されます。

SharePoint Framework拡張機能を使用して構築された新しいカスタム フッターをお楽しみください。

関連項目