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


Подключение компонентов SharePoint Framework с помощью динамических данных

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

Три веб-части SharePoint Framework, подключенные друг к другу, отображают информацию о событиях

Примечание.

Шаблон динамических данных рекомендуется для обмена данными между компонентами SharePoint Framework, включая клиентские веб-части и расширения. Он был впервые реализован в SharePoint Framework v1.7.

Отображение данных с помощью динамических источников данных

Динамические данные в SharePoint Framework основаны на модели источник-уведомление. Компоненты, отмеченные как источники динамических данных, обеспечивают данные и уведомляют SharePoint Framework при их изменении.

Другие компоненты на странице можно подписать на уведомления от источника динамических данных. SharePoint Framework уведомляет клиентский компонент о том, что получено уведомление об изменении его данных. После этого клиентский компонент запрашивает данные у источника.

Все источники динамических данных используют интерфейс IDynamicDataCallables.

Ниже приведен пример кода для веб-части, которая отображает список предстоящих событий. Веб-часть события предоставляет сведения о выбранном событии другим компонентам на странице двумя способами: полные сведения о событии, а также адрес расположения.

import {
  IDynamicDataPropertyDefinition,
  IDynamicDataCallables
} from '@microsoft/sp-dynamic-data';

export default class EventsWebPart extends BaseClientSideWebPart<IEventsWebPartProps> implements IDynamicDataCallables {
  /**
   * Currently selected event
   */
  private _selectedEvent: IEvent;

  /**
   * Event handler for selecting an event in the list
   */
  private _eventSelected = (event: IEvent): void => {
    // store the currently selected event in the class variable. Required
    // so that connected component will be able to retrieve its value
    this._selectedEvent = event;
    // notify subscribers that the selected event has changed
    this.context.dynamicDataSourceManager.notifyPropertyChanged('event');
    // notify subscribers that the selected location has changed
    this.context.dynamicDataSourceManager.notifyPropertyChanged('location');
  }

  protected onInit(): Promise<void> {
    // register this web part as dynamic data source
    this.context.dynamicDataSourceManager.initializeSource(this);

    return Promise.resolve();
  }

  /**
   * Return list of dynamic data properties that this dynamic data source
   * returns
   */
  public getPropertyDefinitions(): ReadonlyArray<IDynamicDataPropertyDefinition> {
    return [
      { id: 'event', title: 'Event' },
      { id: 'location', title: 'Location' }
    ];
  }

  /**
   * Return the current value of the specified dynamic data set
   * @param propertyId ID of the dynamic data set to retrieve the value for
   */
  public getPropertyValue(propertyId: string): IEvent | ILocation {
    switch (propertyId) {
      case 'event':
        return this._selectedEvent;
      case 'location':
        return this._selectedEvent
            ? {
                city: this._selectedEvent.city,
                address: this._selectedEvent.address
              }
            : undefined;
    }

    throw new Error('Bad property id');
  }

  public render(): void {
    const element: React.ReactElement<IEventsProps> = React.createElement(
      Events,
      {
        displayMode: this.displayMode,
        onEventSelected: this._eventSelected,
        title: this.properties.title,
        updateProperty: (value: string): void => {
          this.properties.title = value;
        },
        siteUrl: this.context.pageContext.web.serverRelativeUrl
      }
    );

    ReactDom.render(element, this.domElement);
  }

  // ... omitted for brevity
}

Важно!

Интерфейс IDynamicDataCallables может быть внедрен любым классом, не только веб-частью и расширением. Если источнику динамических данных необходима сложная логика, можно переместить его в отдельный класс, а не применять его непосредственно в веб-части и расширении.

Класс, применяющий интерфейс IDynamicDataCallables, должен определять два метода: getPropertyDefinitions() и getPropertyValue().

Метод getPropertyDefinitions() возвращает массив типа данных, который возвращает определенный источник динамических данных. В приведенном выше примере веб-часть предоставляет подробные сведения о событии и его расположении. Несмотря на то, что сведения поступают из одного объекта (_selectedEvent), при использовании его в двух разных формах веб-часть лучше подходит для повторного использования и может применяться в сочетании с другими веб-частями, которые не относятся к конкретным событиям, таким как веб-часть карты, которая может отображать карту для указанного адреса. Список типов данных, предоставляемых источником данных, отображается конечным пользователям при подключении веб-частей к источнику данных.

Важно!

Объект, возвращаемый методом getPropertyValue(), способ должен быть неструктурированных, например:

{
   "date": "2018-06-01T11:21:59.446Z",
   "name": "Tampa Home Show",
   "organizerEmail": "GradyA@contoso.onmicrosoft.com",
   "organizerName": "Grady Archie"
}

При сериализации сложные объекты будут упрощены. Это может привести к непредвиденным результатам. Например, такой объект:

{
   "date": "2018-06-01T11:21:59.446Z",
   "name": "Tampa Home Show",
   "organizer": {
      "email": "GradyA@contoso.onmicrosoft.com",
      "name": "Grady Archie"
   }
}

…после сериализации будет выглядеть следующим образом:

{
   "date": "2018-06-01T11:21:59.446Z",
   "name": "Tampa Home Show",
   "organizer.email": "GradyA@contoso.onmicrosoft.com",
   "organizer.name": "Grady Archie"
}

Метод getPropertyValue() возвращает значение для определенного типа данных. Значение аргумента propertyId соответствует id определению, указанному в методе getPropertyDefinitions().

Чтобы зарегистрировать компонент как источник динамических данных, вызовите метод this.context.dynamicDataSourceManager.initializeSource(), указав экземпляр источника динамических данных в качестве параметра. В приведенном выше примере веб-часть сама по себе внедряет интерфейс IDynamicDataCallables, поэтому метод initializeSource() вызывается с this в качестве аргумента.

В примере кода веб-часть отображает будущие событие в виде списка. Каждый раз, когда пользователь выбирает событие из списка, веб-часть вызывает метод _eventSelected(). При использовании этого метода, веб-часть назначает выбранное событие для переменной класс _selectedEvent и отправляет уведомление о том, что сведения о выбранном событии и расположение изменились, вызвав методthis.context.dynamicDataSourceManager.notifyPropertyChanged(), передающий id из определения, которое представляет измененный набор данных.

Использование динамических данных в веб-частях

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

import { DynamicProperty } from '@microsoft/sp-component-base';
import {
  DynamicDataSharedDepth,
  IWebPartPropertiesMetadata,
  PropertyPaneDynamicFieldSet,
  PropertyPaneDynamicField
} from '@microsoft/sp-webpart-base';

/**
 * Map web part properties
 */
export interface IMapWebPartProps {
  /**
   * The address to display on the map
   */
  address: DynamicProperty<string>;
  /**
   * Bing maps API key to use with the Bing maps API
   */
  bingMapsApiKey: string;
  /**
   * The city where the address is located
   */
  city: DynamicProperty<string>;
  /**
   * Web part title
   */
  title: string;
}

/**
 * Map web part. Shows the map of the specified location. The location can be
 * specified either directly in the web part properties or via a dynamic data
 * source connection.
 */
export default class MapWebPart extends BaseClientSideWebPart<IMapWebPartProps> {
  /**
   * Event handler for clicking the Configure button on the Placeholder
   */
  private _onConfigure = (): void => {
    this.context.propertyPane.open();
  }

  public render(): void {
    // Get the location to show on the map. The location will be retrieved
    // either from the event selected in the connected data source or from the
    // address entered in web part properties
    const address: string | undefined = this.properties.address.tryGetValue();
    const city: string | undefined = this.properties.city.tryGetValue();
    const needsConfiguration: boolean = !this.properties.bingMapsApiKey || (!address && !this.properties.address.tryGetSource()) ||
    (!city && !this.properties.city.tryGetSource());

    const element: React.ReactElement<IMapProps> = React.createElement(
      Map,
      {
        needsConfiguration: needsConfiguration,
        httpClient: this.context.httpClient,
        bingMapsApiKey: this.properties.bingMapsApiKey,
        dynamicAddress: !!this.properties.address.tryGetSource(),
        address: `${address} ${city}`,
        onConfigure: this._onConfigure,
        width: this.domElement.clientWidth,
        height: this.domElement.clientHeight,
        title: this.properties.title,
        displayMode: this.displayMode,
        updateProperty: (value: string): void => {
          this.properties.title = value;
        }
      }
    );

    ReactDom.render(element, this.domElement);
  }

  protected get dataVersion(): Version {
    return Version.parse('1.0');
  }

  protected get propertiesMetadata(): IWebPartPropertiesMetadata {
    return {
      // Specify the web part properties data type to allow the address
      // information to be serialized by the SharePoint Framework.
      'address': {
        dynamicPropertyType: 'string'
      },
      'city': {
        dynamicPropertyType: 'string'
      }
    };
  }

  protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
    return {
      pages: [
        {
          groups: [
            {
              groupName: strings.BingMapsGroupName,
              groupFields: [
                PropertyPaneTextField('bingMapsApiKey', {
                  label: strings.BingMapsApiKeyFieldLabel
                }),
                PropertyPaneLink('', {
                  href: 'https://www.bingmapsportal.com/',
                  text: strings.GetBingMapsApiKeyLinkText,
                  target: '_blank'
                })
              ]
            },
            // Web part properties group for specifying the information about
            // the address to show on the map.
            {
              // Primary group is used to provide the address to show on the map
              // in a text field in the web part properties
              primaryGroup: {
                groupName: strings.DataGroupName,
                groupFields: [
                  PropertyPaneTextField('address', {
                    label: strings.AddressFieldLabel
                  }),
                  PropertyPaneTextField('city', {
                    label: strings.CityFieldLabel
                  })
                ]
              },
              // Secondary group is used to retrieve the address from the
              // connected dynamic data source
              secondaryGroup: {
                groupName: strings.DataGroupName,
                groupFields: [
                  PropertyPaneDynamicFieldSet({
                    label: 'Address',
                    fields: [
                      PropertyPaneDynamicField('address', {
                        label: strings.AddressFieldLabel
                      }),
                      PropertyPaneDynamicField('city', {
                        label: strings.CityFieldLabel
                      })
                    ],
                    sharedConfiguration: {
                      depth: DynamicDataSharedDepth.Property
                    }
                  })
                ]
              },
              // Show the secondary group only if the web part has been
              // connected to a dynamic data source
              showSecondaryGroup: !!this.properties.address.tryGetSource()
            } as IPropertyPaneConditionalGroup
          ]
        }
      ]
    };
  }

  protected get disableReactivePropertyChanges(): boolean {
    // set property changes mode to reactive, so that the Bing Maps API is not
    // called on each keystroke when typing in the address to show on the map
    // in web part properties
    return true;
  }
}

В SharePoint Framework есть пользовательский интерфейс для подключения двух веб-частей к динамическим источникам данных. Этот пользовательский интерфейс упрощает работу с динамическими данными, обнаруживая доступные источники динамических данных и их свойства и поддерживая настроенное подключение. Чтобы использовать этот пользовательский интерфейс, веб-часть, использующая динамические данные, должна содержать несколько определенных стандартных элементов.

Определение свойств динамической веб-части

Каждое свойство веб-части, для которого данные можно извлечь из динамического источника данных, должно быть определено как DynamicProperty<T>, где T указывает на тип данных, хранящихся в свойстве, например:

/**
 * Map web part properties
 */
export interface IMapWebPartProps {
  /**
   * The address to display on the map
   */
  address: DynamicProperty<string>;

  // ... omitted for brevity
}

В этом примере адрес представляет собой строку, но другие типы данных, например логические, цифровые данные или объекты, также поддерживаются. Свойства веб-части, определенное как DynamicProperty, можно получить свои данные из динамических источников данных или значений, предоставленных непосредственно в свойствах веб-части. Так как свойство веб-части можно использовать как для динамических источников данных, так и статических значений, настроенных в свойства веб-части, вам не нужно определять несколько свойств веб-части, что упрощает создание разнообразных веб-частей.

Определение типа данных, хранящихся в динамических свойствах

Для каждого динамического свойства необходимо указать тип данных, которые оно содержит. Это необходимо, чтобы экземпляр веб-части, добавленный на страницу, можно было надлежащим образом сериализовать. Для каждого динамического свойства веб-части динамические в метоже чтения propertiesMetadata необходимо указать значение dynamicPropertyType:

protected get propertiesMetadata(): IWebPartPropertiesMetadata {
  return {
    // Specify the web part properties data type to allow the address
    // information to be serialized by the SharePoint Framework.
    'address': {
      dynamicPropertyType: 'string'
    },
    'city': {
      dynamicPropertyType: 'string'
    }
  };
}

Возможный диапазон значений для свойства dynamicPropertyType: boolean, number, string, array и object.

Используйте стандартный пользовательский интерфейс для подключения веб-частей к источникам динамических данных

Чтобы дать пользователям возможность подключать веб-части к источникам динамических данных, имеющимся на странице, в SharePoint Framework предусмотрен стандартный пользовательский интерфейс, доступ к которому осуществляется из панели свойств веб-части.

Стандартный интерфейс для подключения веб-частей SharePoint Framework к источникам динамических данных, имеющимся на странице

Важно!

Если вы используете стандартный пользовательский интерфейс для подключения веб-части к источнику динамических данных, убедитесь, что источник динамических данных возвращает значение для заданного динамического свойства (в приведенном выше примере одно событие выбрано из списка). Если это не так, пользовательский интерфейс не сможет определить тип данных, возвращаемых источником данных, и настройка подключения завершится сбоем.

Самая простая форма пользовательского интерфейса может быть определена следующим образом:

protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
  return {
    pages: [
      {
        groups: [
          {
            groupFields: [
              PropertyPaneDynamicFieldSet({
                label: 'Select event source',
                fields: [
                  PropertyPaneDynamicField('event', {
                    label: 'Event source'
                  })
                ]
              })
            ]
          }
        ]
      }
    ]
  };
}

Для каждого набора динамических свойств добавьте новую группу с помощью метода PropertyPaneDynamicFieldSet(). Для каждого динамического свойства веб-части добавьте PropertyPaneDynamicField, что позволит пользователям выбирать, какое свойство веб-часть, указанная в PropertyPaneDynamicField, должна восстановить свои данные.

Если набор полей динамических данных состоит из нескольких динамических свойств, можно указать способ совместного использования данных подключения с помощью sharedConfiguration.depth свойства :

groupFields: [
  PropertyPaneDynamicFieldSet({
    label: 'Address',
    fields: [
      PropertyPaneDynamicField('address', {
        label: strings.AddressFieldLabel
      }),
      PropertyPaneDynamicField('city', {
        label: strings.CityFieldLabel
      })
    ],
    sharedConfiguration: {
      depth: DynamicDataSharedDepth.Property
    }
  })
]

В этом примере все динамические свойства имеют общий доступ к выбранному подключению и свойству. Это полезно в случаях, где выбранное свойство, предоставляемое источником данных, представляет собой объект, и вы хотите связать ваши динамические свойства с различными свойствами выделенного объекта. Если вы хотите использовать тот же источник данных, но подключаете каждое свойство веб-части к разным свойствам, предоставляемым выбранным источником данных, вы можете использовать DynamicDataSharedDepth.Source в качестве альтернативы. Наконец, если вы хотите, чтобы каждое свойство получало свои данные из различных источников, можно задать для свойства sharedConfiguration.depth значение DynamicDataSharedDepth.None.

Предоставьте пользователям выбор, если они хотят использовать динамические данные или указать значение самостоятельно.

При сборке веб-частей вы можете разрешить пользователям для подключать веб-части к другим компонентам на странице или задавать значения свойств веб-части самостоятельно. Это требует небольших дополнительных усилий и позволяет создавать веб-части, более универсальные и подходящие для более широкого диапазона вариантов использования.

Чтобы позволить пользователям выбирать, хотят ли они загружать данные из динамического свойства или сами вводить значение в свойствах веб-части, вы можете определить группу свойств веб-части как группу IPropertyPaneConditionalGroup.

protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
  return {
    pages: [
      {
        groups: [
          // Web part properties group for specifying the information about
          // the address to show on the map.
          {
            // Primary group is used to provide the address to show on the map
            // in a text field in the web part properties
            primaryGroup: {
              groupName: strings.DataGroupName,
              groupFields: [
                PropertyPaneTextField('address', {
                  label: strings.AddressFieldLabel
                }),
                PropertyPaneTextField('city', {
                  label: strings.CityFieldLabel
                })
              ]
            },
            // Secondary group is used to retrieve the address from the
            // connected dynamic data source
            secondaryGroup: {
              groupName: strings.DataGroupName,
              groupFields: [
                PropertyPaneDynamicFieldSet({
                  label: 'Address',
                  fields: [
                    PropertyPaneDynamicField('address', {
                      label: strings.AddressFieldLabel
                    }),
                    PropertyPaneDynamicField('city', {
                      label: strings.CityFieldLabel
                    })
                  ],
                  sharedConfiguration: {
                    depth: DynamicDataSharedDepth.Property
                  }
                })
              ]
            },
            // Show the secondary group only if the web part has been
            // connected to a dynamic data source
            showSecondaryGroup: !!this.properties.address.tryGetSource()
          } as IPropertyPaneConditionalGroup
        ]
      }
    ]
  };
}

Группа панели свойств условной веб-части состоит из основной и вспомогательной группы. С помощью свойства showSecondaryGroup вы можете указать, когда вспомогательная группа будет отображаться, а основная группа будет скрыта.

В приведенном выше примере будет после того, как пользователь выберет подключение веб-части к источнику динамических данных, нажав многоточие (), отобразится вспомогательная группа, используемая для подключения веб-части к источнику динамических данных.

Указатель мыши, наведенный на многоточие в области свойств веб-части, используемой для подключения веб-части SharePoint Framework к динамическому источнику данных.

Рекомендации

Функция динамических данных в SharePoint Framework имеет перечисленные ниже характеристики.

  • каждая страница может иметь несколько динамических источников данных и пользователей
  • каждый компонент может как передавать динамические данные другим компонента, так и использовать динамические данные других компонентов
  • компоненты могут использовать данные из нескольких динамических источников данных
  • SharePoint Framework предлагает стандартный пользовательский интерфейс для подключения веб-частей к источникам данных и автоматического сохранения информации о подключении

См. также