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', '© 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 ソリューションの作成
コンソールから、プロジェクト用の新しいフォルダーを作成します。
md spfx-react-custom-footer
プロジェクト フォルダーに移動します。
cd spfx-react-custom-footer
プロジェクト フォルダーで SharePoint Framework Yeoman ジェネレーターを実行して、新しい SharePoint Framework プロジェクトをスキャホールディングします。
yo @microsoft/sharepoint
プロンプトが表示されたら、以下の値を入力します (以下で省略されたすべてのプロンプトに対して既定のオプションを選択します)。
- ソリューション名は何ですか?: spfx-react-custom-footer
- どのベースライン パッケージをコンポーネントのターゲットにしますか?: SharePoint Online のみ (最新)
- どの種類のクライアント側コンポーネントを作成しますか?: 拡張機能
- どの種類のクライアント側拡張機能を作成しますか? アプリケーション カスタマイザー
- フィールド カスタマイザーの名前は何ですか? CustomFooter
この時点で、Yeoman は必要な依存関係をインストールし、ソリューション ファイルおよびフォルダーを CustomFooter 拡張機能とともにスキャフォールディングします。 これには数分かかる場合があります。
Visual Studio Code (または選択した他のコード エディター) を起動し、ソリューションの開発を開始します。 Visual Studio Code を開始するには、次のステートメントを実行します。
code .
新しい UI 要素を定義する
ユーザー設定のフッターの UI 要素は、React とユーザー設定の React コンポーネントによってレンダリングされます。 好きなテクノロジを使用して、サンプル フッターの UI 要素を作成できます。 このチュートリアルでは、React の Office UI Fabric コンポーネントを活用するために、React を使用します。
ファイル ./src/extensions/customFooter/CustomFooterApplicationCustomizer.manifest.json フォルダーを開きます。
id
プロパティの値をコピーします。この値は後で必要になるため、安全な場所に保存します。ファイル ./src/extensions/customFooter/CustomFooterApplicationCustomizer.ts を開き、型
PlaceholderContent
とPlaceholderName
パッケージ @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';
クラス
CustomFooterApplicationCustomizer
の定義を検索し、種類PlaceholderContent | undefined
のbottomPlaceholder
と呼ばれる新しいプライベート メンバーを宣言します。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 コードを使用し、既存のコードの大部分を再利用してフッター全体をレンダリングすることもできます。 ただし、テクノロジの観点からだけでなく、コードの観点からも、実装のアップグレードを検討することをお勧めします。
src/extensions/customFooter フォルダーに components という名前の新しいフォルダーを追加します。
新しいフォルダー内に、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`}>© 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
、Office UI Fabric コンポーネント ライブラリからReact コンポーネントに注目してください。コンポーネントの
render()
メソッドでは、フッター内のリンクのCommandButton
コンポーネントのごく少数のインスタンスを伴うCustomFooter
の出力が定義されています。 すべての HTML 出力は、Office UI Fabric のグリッド レイアウト内にラップされます。注:
Office の UI ファブリックのグリッド レイアウトの詳細については、「応答性の高いレイアウト」を参照してください。
次の図では、出力結果を確認できます。
デバッグ モードでソリューションをテストする
コンソール ウィンドウに戻り、次のコマンドを実行してソリューションを構築し、それをホストするローカル Node.js サーバーを実行します。
gulp serve --nobrowser
その後、お好きなブラウザーを開いて、任意の "モダン" チーム サイトの "モダン" ページに移動します。 そして、以下のクエリ文字列パラメーターをページの 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 フィーチャー フレームワーク ファイルを宣言する必要があります。
フィーチャー フレームワーク要素を確認する
コード エディターで、/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
指定する必要がある場合は、属性を追加することもできます。このチュートリアルではそうではありません。ソリューションの ファイル ./config/package-solution.json フォルダーを開きます。 ファイル内には、セクション内
assets
のelements.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 テナントのソリューションを準備して展開します。
次のタスクを実行して、ソリューションをバンドルします。 これにより、プロジェクトのリリース ビルドが実行されます。
gulp bundle --ship
次のタスクを実行して、ソリューションをパッケージ化します。 このコマンドは、sharepoint/solution フォルダーに *.sppkg パッケージを作成します。
gulp package-solution --ship
新しく作成したクライアント側ソリューション パッケージを、テナント内のアプリ カタログにアップロードまたはドラッグ アンド ドロップし、[展開] ボタンを選択します。
ソリューションのインストールと実行
ブラウザーを開き、任意の "モダン" ターゲット サイトに移動します。
[サイト コンテンツ] ページに移動し、新しいアプリの追加を選択します。
[組織から] でインストールする新しいアプリを選択して、アプリ カタログで使用可能なソリューションを参照します。
spfx-react-custom-footer-client-side-solution というソリューションを選択し、ターゲット サイトにインストールします。
アプリケーションのインストールが完了した後、ページを更新するか、サイトのホーム ページに移動します。 動作中のカスタム フッターが表示されます。
SharePoint Framework拡張機能を使用して構築された新しいカスタム フッターをお楽しみください。