Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
При разработке решений с помощью модели надстроек SharePoint вы использовали объектную модель JavaScript (JSOM) SharePoint для использования SharePoint Online из клиентского кода. Например, вы использовали для получения ссылки на контекст клиента с помощью следующего синтаксиса.
Важно!
В этой статье рассматриваются так называемые компоненты PnP, примеры и (или) инструменты, которые представляют собой ресурсы с открытым кодом, поддерживаемые активным сообществом, предоставляющим их поддержку. Со стороны официальных каналов поддержки Майкрософт отсутствуют соглашения об уровне обслуживания (SLA) для инструментов с открытым исходным кодом. Однако эти компоненты или примеры используют поддерживаемые корпорацией Майкрософт готовые API и функции, поддерживаемые корпорацией Майкрософт.
var context = SP.ClientContext.get_current();
var user = context.get_web().get_currentUser();
Или вы использовали для получения элементов библиотеки на целевом хост-сайте SharePoint Online с помощью следующего синтаксиса.
// Get a reference to the current host web
var clientContext = SP.ClientContext.get_current();
var hostWebContext = new SP.AppContextSite(clientContext, hostweburl);
var hostweb = hostWebContext.get_web();
// Get a reference to the 'Documents' library
var list = hostweb.get_lists().getByTitle("Documents");
// Define a query to get all the items
var camlQuery = SP.CamlQuery.createAllItemsQuery();
var docs = documentsLibrary.getItems(camlQuery);
// Load and execute the actual query
clientContext.load(docs);
clientContext.executeQueryAsync(
// Success callback
function() {
// Iterate through the items and display their titles
var docsEnumerator = docs.getEnumerator();
while (docsEnumerator.moveNext()) {
var doc = docsEnumerator.get_current();
console.log(doc.get_item('Title'));
}
},
// Failure callback
function(sender, args) {
console.log('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}
);
Приведенный выше синтаксис основан на JSOM (sp.js) и очень тесно связан с архитектурой модели надстройки SharePoint, так как, например, он зависит от наличия маркеров SharePoint в URL-адресе сайта, размещенного в SharePoint.
При желании вы можете watch следующее видео, а не читать всю статью, которую вы по-прежнему можете рассматривать как гораздо более подробный справочник.
Использование данных SharePoint Online в SharePoint Framework
В современной модели разработки для SharePoint Online библиотека JSOM больше не подходит, поэтому следует полагаться на REST API SharePoint Online или API Microsoft Graph. Например, при разработке решения SharePoint Framework можно использовать SPHttpClient и объекты MSGraphClientV3 контекста SPFx для использования REST API SharePoint или API Microsoft Graph Graph соответственно.
Использование данных SharePoint Online через SPHttpClient
Например, в следующем фрагменте кода вы можете увидеть, как использовать тот же список документов из приведенного выше примера, в то время как в SPFx через SPHttpClient.
import { Version } from '@microsoft/sp-core-library';
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
import styles from './ConsumeSpoViaClientCodeWebPart.module.scss';
// Import spHttpClient
import { SPHttpClient, SPHttpClientResponse } from '@microsoft/sp-http';
// Define interface for each list item
export interface IListItem {
Title?: string;
Id: number;
}
// Define interface for list item collection
export interface ISPListItems {
value: IListItem[];
}
export interface IConsumeSpoViaClientCodeWebPartProps {
}
export default class ConsumeSpoViaClientCodeWebPart extends BaseClientSideWebPart<IConsumeSpoViaClientCodeWebPartProps> {
private _docs: ISPListItems;
public render(): void {
// For each document in the list, render a <li/> HTML element
let docsOutput = '';
this._docs.value.forEach(d => { docsOutput += `<li>${d.Title}</li>`; });
this.domElement.innerHTML = `<div class="${ styles.consumeSpoViaClientCode }"><ul>${docsOutput}</ul></div>`;
}
protected async onInit(): Promise<void> {
// Load all the documents onInit
this._docs = await this._getDocuments();
return super.onInit();
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
// Get list items using spHttpClient
private _getDocuments = async (): Promise<ISPListItems> => {
// Get the REST response of the SharePoint REST API and return as collection of items
return this.context.spHttpClient.get(this.context.pageContext.web.absoluteUrl +
`/_api/web/lists/GetByTitle('Documents')/items`,
SPHttpClient.configurations.v1)
.then((response: SPHttpClientResponse) => {
return response.json();
});
}
}
Код берется из веб-части SharePoint Framework, где отображается список файлов в библиотеке "Документы" текущего сайта.
Обратите внимание, что вам не нужно полагаться на какие-либо маркеры querystring или параментеры, и вы можете просто запросить this.context.spHttpClient , чтобы сделать HTTP-запрос GET к REST API SharePoint для доступа к элементам библиотеки документов "Документы". Вы также можете использовать тот же объект this.context.spHttpClient для выполнения HTTP-запроса POST или любого другого HTTP-запроса с помощью метода fetch . Однако, несмотря на то, что код довольно прост и прост, необходимо учитывать URL-адрес REST API SharePoint для вызова и структуру ответа в формате JSON, что в некоторых сценариях может оказаться сложной задачей.
Тем не менее, используя приведенный выше метод, вы можете делать все, что вам нужно, просто потребляя SharePoint Online через REST.
Примечание.
Вы можете покопаться в использовании REST API SharePoint Online в SharePoint Framework, прочитав статью Подключение к API SharePoint.
Использование данных SharePoint Online через MSGraphClient
Другой вариант — использовать данные SharePoint Online с помощью microsoft API Graph. Здесь можно найти пример фрагмента кода веб-части, использующий тот же список документов, но использующий Microsoft Graph и объект MSGraphClientV3 .
import { Version } from '@microsoft/sp-core-library';
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
import styles from './ConsumeSpoViaGraphWebPart.module.scss';
import { MSGraphClientV3 } from '@microsoft/sp-http';
// Define interface for each list item
export interface IListItem {
name?: string;
id: number;
}
// Define interface for list item collection
export interface ISPListItems {
value: IListItem[];
}
export interface IConsumeSpoViaGraphWebPartProps {
}
export default class ConsumeSpoViaGraphWebPart extends BaseClientSideWebPart<IConsumeSpoViaGraphWebPartProps> {
private _docs: ISPListItems;
public render(): void {
// For each document in the list, render a <li/> HTML element
let docsOutput = '';
this._docs.value.forEach(d => { docsOutput += `<li>${d.name}</li>`; });
this.domElement.innerHTML = `<div class="${ styles.consumeSpoViaGraph }"><ul>${docsOutput}</ul></div>`;
}
protected async onInit(): Promise<void> {
await super.onInit();
// Load all the documents onInit
this._docs = await this._getDocuments();
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
// Get list items using spHttpClient
private _getDocuments = async (): Promise<ISPListItems> => {
// Get the REST response of the SharePoint REST API and return as collection of items
const graphClient: MSGraphClientV3 = await this.context.msGraphClientFactory.getClient("3");
return graphClient.api(`/sites/${this.context.pageContext.site.id}/drive/root/children`)
.version('v1.0')
.get();
}
}
Как и в случае с SPHttpClient, синтаксис не слишком сложный, и, узнав, какие конечные точки Microsoft API Graph вам нужны, и структуру ответов JSON, вы можете легко использовать любые данные в SharePoint Online или любой другой службе в экосистеме Microsoft 365, если у вас будут соответствующие разрешения, предоставленные вашему решению SharePoint Framework.
Примечание.
Вы можете покопаться в использовании microsoft API Graph в SharePoint Framework, прочитав статью Подключение к Microsoft Graph с помощью MSGraphClientV3.
Знакомство с библиотекой PnPjs
PnPjs — это открытый код клиентская библиотека, реализованная сообществом для сообщества, которая предоставляет коллекцию библиотек fluent для использования SharePoint Online, Microsoft Graph и API REST Microsoft 365 в типобезопасном способе. PnPjs можно использовать в SharePoint Framework решениях, в Node.js модулях (например, скриптах, Функции Azure и т. д.), в любом решении JavaScript или на стороне клиента.
Использование данных SharePoint Online через PnPjs
Чтобы использовать данные SharePoint Online с помощью PnPjs в веб-части SharePoint Framework, необходимо импортировать через npm одну или несколько библиотек, предлагаемых PnPjs. Давайте создадим проект веб-части SharePoint Framework и сделаем это пошагово.
Прежде всего, необходимо создать шаблон решения SharePoint Framework, поэтому запустите командную строку или окно терминала, создайте папку и из созданной папки выполните следующую команду.
Важно!
Чтобы выполнить иллюстрированную процедуру, необходимо установить SharePoint Framework в среде разработки. Подробные инструкции по настройке среды см. в статье Настройка среды разработки SharePoint Framework.
yo @microsoft/sharepoint
Следуйте инструкциям, чтобы создать шаблон решения для современной веб-части. В частности, при появлении запроса средства сделайте следующие варианты:
- Как называется ваше решение? spo-sp-fx-pn-pjs
- Какой тип клиентского компонента нужно создать? WebPart
- Как называется ваша веб-часть? UsePnPjsMinimal
- Какой шаблон следует использовать? Минимальное количество
С помощью приведенных выше ответов вы решили создать решение с именем spo-sp-fx-pn-pjs, в котором будет веб-часть с именем UsePnPjsMinimal и будет основана на шаблоне Minimal , то есть он будет основан только на коде HTML, CSS и JavaScript.
Средство формирования шаблонов создаст для вас новое решение SharePoint Framework. По завершении вы можете просто открыть текущую папку с помощью любимого редактора кода. Однако перед открытием решения необходимо добавить пакеты PnPjs, выполнив следующую команду:
npm install @pnp/sp @pnp/graph @pnp/logging --save
Приведенная выше команда устанавливает пакеты @pnp/sp и @pnp/graph в текущем решении вместе с @pnp/logging для ведения журнала. В целом доступные пакеты PnPjs:
@pnp/ | ||
Основные | Предоставляет общие функциональные возможности для всех библиотек pnp | |
График | Предоставляет api fluent для работы с Microsoft Graph | |
Ведение журнала | Легкая, подписываемая платформа ведения журнала | |
msalовеlient | Предоставляет оболочку msal, подходящую для использования с PnPjs | |
nodejs | Предоставляет функциональные возможности, позволяющие использовать библиотеки @pnp в nodejs | |
Queryable | Предоставляет функции общих запросов и базовые классы | |
Sp | Предоставляет api fluent для работы с SharePoint REST | |
sp-admin | Предоставляет api fluent для работы с методами администрирования клиента M365. |
Теперь решение можно открыть в любимом редакторе кода. Если ваш любимый редактор кода — Microsoft Visual Studio Code, просто выполните следующую команду:
code .
Прежде всего, необходимо импортировать типы PnPjs, необходимые для использования данных SharePoint Online. Поэтому откройте исходный файл веб-части и добавьте следующие инструкции импорта .
import { spfi, SPFx } from "@pnp/sp";
import "@pnp/sp/webs";
import "@pnp/sp/lists";
import "@pnp/sp/items";
Самый первый оператор import импортирует типы инициализации для PnPjs, а последующие инструкции импорта просто импортируют типы, необходимые для работы с веб-объектами, объектами списка и объектами элементов списка. После этого можно реализовать такой метод, как в следующем фрагменте кода, чтобы загрузить документы в библиотеку "Документы".
// Get list items using PnPjs
private _getDocuments = async (): Promise<IListItem[]> => {
// Initialized PnPjs
const sp = spfi().using(SPFx(this.context));
const items: IListItem[] = await sp.web.lists.getByTitle('Documents').items();
return items;
}
Как видите, синтаксис очень прост и прост. Фактически код инициализирует новый экземпляр объекта типа SPFI (означает интерфейс фабрики SharePoint), предоставляя объект контекста SharePoint Framework, где SPFI — это тип PnPjs. Затем, используя только что инициализированный объект sp , он использует синтаксический синтаксис для сбора элементов списка с заголовком "Документы" в текущем интернете.
В следующем фрагменте кода вы увидите весь код веб-части.
import { Version } from '@microsoft/sp-core-library';
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
import { spfi, SPFx } from "@pnp/sp";
import "@pnp/sp/webs";
import "@pnp/sp/lists";
import "@pnp/sp/items";
import styles from './UsePnPjsMinimalWebPart.module.scss';
// Define interface for each list item
export interface IListItem {
Title?: string;
Id: number;
}
export interface IUsePnPjsMinimalWebPartProps {
}
export default class UsePnPjsMinimalWebPart extends BaseClientSideWebPart<IUsePnPjsMinimalWebPartProps> {
private _docs: IListItem[];
public render(): void {
// For each document in the list, render a <li/> HTML element
let docsOutput = '';
this._docs.forEach(d => { docsOutput += `<li>${d.Title}</li>`; });
this.domElement.innerHTML = `<div class="${ styles.usePnPjsMinimal }"><ul>${docsOutput}</ul></div>`;
}
protected async onInit(): Promise<void> {
// Load all the documents onInit
this._docs = await this._getDocuments();
return await super.onInit();
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
// Get list items using PnPjs
private _getDocuments = async (): Promise<IListItem[]> => {
// Initialized PnPjs
const sp = spfi().using(SPFx(this.context));
const items: IListItem[] = await sp.web.lists.getByTitle('Documents').items();
return items;
}
}
Свободно используемый синтаксис PnPjs также напоминает синтаксис, который использовался с CSOM или JSOM в классической модели надстройки SharePoint.
Использование PnPjs в веб-части React
Теперь, когда вы знаете, как читать данные SharePoint в базовом коде JavaScript, давайте перейдем к более реальному и распространенному варианту использования, который использует PnPjs в веб-части React с SharePoint Framework.
Откройте командную строку и перейдите в ту же папку предыдущего решения SPFx, а затем снова запустите средство формирования шаблонов SPFx, выполнив следующую команду.
yo @microsoft/sharepoint
При многократном выполнении средства формирования шаблонов в одном и том же решении вы сможете добавить дополнительные артефакты или компоненты в уже существующее решение.
Следуйте инструкциям, чтобы создать шаблон решения для современной веб-части. В частности, при появлении запроса средства сделайте следующие варианты:
- Какой тип клиентского компонента нужно создать? WebPart
- Как называется ваша веб-часть? UsePnPjsReact
- Какой шаблон следует использовать? React;
С помощью приведенных выше ответов вы решили добавить в решение другую веб-часть. Новое имя веб-части — UsePnPjsReact, и она будет использовать шаблон React для пользовательского интерфейса или пользовательского интерфейса.
Теперь можно инициализировать объект SPFI PnPjs, как в предыдущем примере, и передать его в компонент React, отрисовывая веб-часть как пользовательское свойство. Например, интерфейс, определяющий свойства компонента React, может выглядеть так, как в следующем коде.
import { SPFI } from "@pnp/sp";
export interface IUsePnPjsReactProps {
description: string;
isDarkTheme: boolean;
environmentMessage: string;
hasTeamsContext: boolean;
userDisplayName: string;
sp: SPFI;
}
Веб-часть может инициализировать компонент React, как в следующем фрагменте кода.
export default class UsePnPjsReactWebPart extends BaseClientSideWebPart<IUsePnPjsReactWebPartProps> {
private _isDarkTheme: boolean = false;
private _environmentMessage: string = '';
private _sp: SPFI;
public render(): void {
const element: React.ReactElement<IUsePnPjsReactProps> = React.createElement(
UsePnPjsReact,
{
description: this.properties.description,
isDarkTheme: this._isDarkTheme,
environmentMessage: this._environmentMessage,
hasTeamsContext: !!this.context.sdks.microsoftTeams,
userDisplayName: this.context.pageContext.user.displayName,
sp: this._sp
}
);
ReactDom.render(element, this.domElement);
}
protected async onInit(): Promise<void> {
// Initialized PnPjs
this._sp = spfi().using(SPFx(this.context));
return this._getEnvironmentMessage().then(message => {
this._environmentMessage = message;
});
}
// Omitted code, for the sake of simplicity ...
Наконец, в компоненте React можно использовать свойство sp, доступное в свойствах компонента, чтобы использовать синтаксис PnPjs fluent и получить элементы в целевой библиотеке. Ниже приведен упрощенный пример этой логики.
import * as React from 'react';
import styles from './UsePnPjsReact.module.scss';
import { IUsePnPjsReactProps } from './IUsePnPjsReactProps';
import { IUsePnPjsReactState } from './IUsePnPjsReactState';
import "@pnp/sp/webs";
import "@pnp/sp/lists";
import "@pnp/sp/items";
export default class UsePnPjsReact extends React.Component<IUsePnPjsReactProps, IUsePnPjsReactState> {
constructor(props: IUsePnPjsReactProps) {
super(props);
this.state = {
documents: []
}
}
override async componentDidMount(): Promise<void> {
const docs = await this.props.sp.web.lists.getByTitle("Documents").items<{Id: number; Title: string;}[]>();
this.setState({
documents: docs
});
}
public render(): React.ReactElement<IUsePnPjsReactProps> {
const {
isDarkTheme,
hasTeamsContext
} = this.props;
const {
documents
} = this.state;
return (
<section className={`${styles.usePnPjsReact} ${hasTeamsContext ? styles.teams : ''}`}>
<div className={styles.welcome}>
<img alt="" src={isDarkTheme ? require('../assets/welcome-dark.png') : require('../assets/welcome-light.png')} className={styles.welcomeImage} />
</div>
<div>
<h3>Here are the documents!</h3>
<ul className={styles.links}>
{ documents.map(d => <li key={d.Id}>{d.Title}</li>)}
</ul>
</div>
</section>
);
}
}
Однако в ваших решениях необходимо использовать PnPjs из нескольких компонентов React, и предоставление экземпляра объекта SPFI всем компонентам в качестве свойства не обязательно является лучшим вариантом.
Чтобы улучшить качество кода, необходимо создать файл в решении, например назвать его pnpjsConfig.ts со следующим содержимым.
import { WebPartContext } from "@microsoft/sp-webpart-base";
// import pnp and pnp logging system
import { spfi, SPFI, SPFx } from "@pnp/sp";
import { LogLevel, PnPLogging } from "@pnp/logging";
import "@pnp/sp/webs";
import "@pnp/sp/lists";
import "@pnp/sp/items";
import "@pnp/sp/batching";
// eslint-disable-next-line no-var
var _sp: SPFI = null;
export const getSP = (context?: WebPartContext): SPFI => {
if (!!context) { // eslint-disable-line eqeqeq
//You must add the @pnp/logging package to include the PnPLogging behavior it is no longer a peer dependency
// The LogLevel set's at what level a message will be written to the console
_sp = spfi().using(SPFx(context)).using(PnPLogging(LogLevel.Warning));
}
return _sp;
};
Файл экспортирует функцию, которая создает новый экземпляр SPFI на основе предоставленного необязательного контекста SPFx. Если вы вызываете функцию без указания контекста, она попытается повторно использовать ранее созданный экземпляр SPFI, если он имеется.
Примечание.
Дополнительные сведения об этом шаблоне можно найти в статье Настройка конфигурации и служб Project, а полнофункциональный пример этого шаблона можно найти на сайте GitHub в примере решения Using @pnp/js and ReactJS.
Определив файл pnpjsConfig.ts , его можно импортировать в класс веб-части и вызвать метод getSP из метода onInit веб-части, как показано в следующем фрагменте кода.
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Version } from '@microsoft/sp-core-library';
import {
IPropertyPaneConfiguration,
PropertyPaneTextField
} from '@microsoft/sp-property-pane';
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
import { IReadonlyTheme } from '@microsoft/sp-component-base';
import * as strings from 'UsePnPjsReactBetterWebPartStrings';
import UsePnPjsReactBetter from './components/UsePnPjsReactBetter';
import { IUsePnPjsReactBetterProps } from './components/IUsePnPjsReactBetterProps';
// Import the getSP function from the pnpjsConfig file
import { getSP } from '../../pnpjsConfig';
export interface IUsePnPjsReactBetterWebPartProps {
description: string;
}
export default class UsePnPjsReactBetterWebPart extends BaseClientSideWebPart<IUsePnPjsReactBetterWebPartProps> {
private _isDarkTheme: boolean = false;
private _environmentMessage: string = '';
public render(): void {
const element: React.ReactElement<IUsePnPjsReactBetterProps> = React.createElement(
UsePnPjsReactBetter,
{
description: this.properties.description,
isDarkTheme: this._isDarkTheme,
environmentMessage: this._environmentMessage,
hasTeamsContext: !!this.context.sdks.microsoftTeams,
userDisplayName: this.context.pageContext.user.displayName
}
);
ReactDom.render(element, this.domElement);
}
protected onInit(): Promise<void> {
//Initialize our _sp object that we can then use in other packages without having to pass around the context.
// Check out pnpjsConfig.ts for an example of a project setup file.
getSP(this.context);
return this._getEnvironmentMessage().then(message => {
this._environmentMessage = message;
});
}
// Omitted code, for the sake of simplicity ...
Теперь, где бы вам ни понадобилось получить доступ к PnPjs, можно просто импортировать функцию getSP и вызвать ее, не предоставляя никаких аргументов для возврата уже инициализированного экземпляра объекта SPFI . Например, в любом React компоненте решения можно написать следующий синтаксис.
import * as React from 'react';
import styles from './UsePnPjsReactBetter.module.scss';
import { IUsePnPjsReactBetterProps } from './IUsePnPjsReactBetterProps';
import { IUsePnPjsReactBetterState } from './IUsePnPjsReactBetterState';
import { SPFI } from "@pnp/sp";
import "@pnp/sp/webs";
import "@pnp/sp/lists";
import "@pnp/sp/items";
import { getSP } from '../../../pnpjsConfig';
export default class UsePnPjsReactBetter extends React.Component<IUsePnPjsReactBetterProps, IUsePnPjsReactBetterState> {
private _sp: SPFI;
constructor(props: IUsePnPjsReactBetterProps) {
super(props);
this.state = {
documents: []
}
this._sp = getSP();
}
override async componentDidMount(): Promise<void> {
const docs = await this._sp.web.lists.getByTitle("Documents").items<{Id: number; Title: string;}[]>();
this.setState({
documents: docs
});
}
public render(): React.ReactElement<IUsePnPjsReactBetterProps> {
const {
isDarkTheme,
hasTeamsContext
} = this.props;
const {
documents
} = this.state;
return (
<section className={`${styles.usePnPjsReactBetter} ${hasTeamsContext ? styles.teams : ''}`}>
<div className={styles.welcome}>
<img alt="" src={isDarkTheme ? require('../assets/welcome-dark.png') : require('../assets/welcome-light.png')} className={styles.welcomeImage} />
</div>
<div>
<h3>Here are the documents!</h3>
<ul className={styles.links}>
{ documents.map(d => <li key={d.Id}>{d.Title}</li>)}
</ul>
</div>
</section>
);
}
}
Обратите внимание на синтаксис в конструкторе, где вызывается функция getSP .
this._sp = getSP();
Кроме того, обратите внимание на использование полученного экземпляра SPFI , например в методе componentDidMount .
const docs = await this._sp.web.lists.getByTitle("Documents").items<{Id: number; Title: string;}[]>();
Тот, который вы только что видели, является очень распространенным шаблоном при использовании PnPjs в веб-частях на основе React, и вы должны полагаться на него в своих собственных решениях.
Важно!
Существуют сценарии, в которых необходимо использовать PnPjs в классе службы, поддерживающем бизнес-логику. В таких сценариях у вас не обязательно есть компонент React, и вы не можете полагаться на объект контекста SPFx, если вы не предоставите его классу службы в качестве входного аргумента, например в конструкторе класса службы. Однако и в целом передача контекста SPFx в качестве параметра конструктора или свойства компонента React не является хорошим шаблоном проектирования. Если вам нужно создать класс службы, который использует PnPjs в SPFx, можно обратиться к шаблону конструктора класса служб .
Рекомендуемое содержимое
Дополнительные сведения об этой теме см. в следующих документах: