SharePoint Framework 1.7版本发布了,带来了很多新功能,新功能的简介请参见这里。
这篇博客介绍其中的新功能:动态数据(Dynamic Data)。
在SPFx1.7版本之前,SPFx不同的组件之间通信会比较麻烦,动态数据的功能就是为了解决SPFx组件之间通信的问题。
动态数据分为两个部分,一个是动态数据源,一个是数据接收者。动态数据源既可以是一个webpart也可以是一个扩展,同样数据接收者也一样,既可以是webpart也可以是一个扩展。这里我们使用两个webpart来展示一下如果发布和接受动态数据,也就是如何在webpart之间传递数据。
首先使用yeoman创建两个webpart,一个名为SourceWebpart作为动态数据源,用于发布数据,另一个名为TargetWebpart,用于接收数据。
创建完毕之后,使用Code打开项目,可以看到新创建的两个webpart。
我在SourceWebpart中画了一个黄色的区域,当鼠标点击黄色区域的时候,会将鼠标的x和y坐标发布出去。TargetWebpart接收坐标数据并显示在webpart上:
首先看一下SourceWebpart如何获取鼠标位置数据。创建一个IPoint接口,包含x和y两个成员。在“SourceWebpartWebPart”类中添加私有成员mousePosition用来保存鼠标位置数据,然后修改render方法,显示黄色区域,以及绑定onclick事件,代码如下:
export interface IPoint { //定义IPoint接口
x: number;
y: number;
}
export interface ISourceWebpartWebPartProps {
description: string;
}
export default class SourceWebpartWebPart extends BaseClientSideWebPart<ISourceWebpartWebPartProps>
{
private mousePosition: IPoint; //mousePosition用来保存鼠标位置数据
public onMouseClick(e) { //onMouseClick方法用来获取鼠标位置数据并保存在mousePosition中
this.mousePosition = { x: e.clientX, y: e.clientY };
}
public render(): void {
//显示黄色区域
this.domElement.innerHTML = `
<div id="webpartdiv" style="width: 700px; height: 200px; background-color: yellow">
</div>`;
//绑定onclick事件
this.domElement.onclick=this.onMouseClick.bind(this);
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: 'Description',
groupFields: [
PropertyPaneTextField('description', {
label: 'description'
})
]
}
]
}
]
};
}
}
以上就完成了点击鼠标获取数据的部分,如果需要将数据发布出去,需要改造一下SourceWebpart,首先需要导入两个接口:
import { IDynamicDataCallables, IDynamicDataPropertyDefinition } from '@microsoft/sp-dynamic-data';
然后SourceWebpart继承IDynamicDataCallables接口:
export default class SourceWebpartWebPart extends BaseClientSideWebPart<ISourceWebpartWebPartProps>
implements IDynamicDataCallables
每一个动态数据源都需要实现IDynamicDataCallables接口,这个接口定义如下:
export declare interface IDynamicDataCallables {
/**
* 定义数据源返回的数据名称以及类型
*/
getPropertyDefinitions(): ReadonlyArray<IDynamicDataPropertyDefinition>;
/**
* 根据数据的id返回数据的值
*
*/
getPropertyValue(propertyId: string): any;
/**
* 根据数据的id返回注释信息(可以不实现)
*/
getAnnotatedPropertyValue?(propertyId: string): IDynamicDataAnnotatedPropertyValue | undefined;
}
它包含两个必须实现的方法:getPropertyDefinitions和getPropertyValue方法。
getPropertyDefinitions用来定义数据源发布的数据类型,因为我们要发布鼠标位置信息,所以这个方法是这样实现的:
public getPropertyDefinitions(): ReadonlyArray<IDynamicDataPropertyDefinition> {
return [
{
id: 'x',
title: 'Mouse-X'
},
{
id: 'y',
title: 'Mouse-y'
}
];
}
定义了两个数据,x表示x坐标,id就是propertyId,这个id会在接下来的getPropertyValue方法中用到,title用来被其他webpart识别。
getPropertyValue方法的实现:
public getPropertyValue(propertyId: string): number {
switch (propertyId) {
case 'x':
return this.mousePosition.x;
case 'y':
return this.mousePosition.y;
}
throw new Error('Bad property id');
}
定义好数据之后,需要做两件事,一个是将这个webpart注册为一个数据源,另一个就是对外发布数据。,它们都是用上下文中的dynamicDataSourceManage对象。
将webpart注册为数据源是在onInit()方法中实现的:
protected onInit(): Promise<void> {
//将webpart注册为动态数据源
this.context.dynamicDataSourceManager.initializeSource(this);
return Promise.resolve();
}
而发布数据是在onMouseClick方法中实现的,当点击鼠标的时候,就会发布数据。onMouseClick方法修改如下:
public onMouseClick(e) { //onMouseClick方法用来获取鼠标位置数据并保存在mousePosition中
this.mousePosition = { x: e.clientX, y: e.clientY };
this.context.dynamicDataSourceManager.notifyPropertyChanged('x');
this.context.dynamicDataSourceManager.notifyPropertyChanged('y');
}
到这里SourceWebpart的部分就结束了,完整代码如下:
import { Version } from '@microsoft/sp-core-library';
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField
} from '@microsoft/sp-webpart-base';
import { escape } from '@microsoft/sp-lodash-subset';
import styles from './SourceWebpartWebPart.module.scss';
import * as strings from 'SourceWebpartWebPartStrings';
import { IDynamicDataCallables, IDynamicDataPropertyDefinition } from '@microsoft/sp-dynamic-data';
export interface IPoint { //定义IPoint接口
x: number;
y: number;
}
export interface ISourceWebpartWebPartProps {
description: string;
}
export default class SourceWebpartWebPart extends BaseClientSideWebPart<ISourceWebpartWebPartProps>
implements IDynamicDataCallables
{
private mousePosition: IPoint; //mousePosition用来保存鼠标位置数据
protected onInit(): Promise<void> {
//将webpart注册为动态数据源
this.context.dynamicDataSourceManager.initializeSource(this);
return Promise.resolve();
}
public onMouseClick(e) { //onMouseClick方法用来获取鼠标位置数据并保存在mousePosition中
this.mousePosition = { x: e.clientX, y: e.clientY };
this.context.dynamicDataSourceManager.notifyPropertyChanged('x');
this.context.dynamicDataSourceManager.notifyPropertyChanged('y');
}
public getPropertyDefinitions(): ReadonlyArray<IDynamicDataPropertyDefinition> {
return [
{
id: 'x',
title: 'Mouse-X'
},
{
id: 'y',
title: 'Mouse-y'
}
];
}
public getPropertyValue(propertyId: string): number {
switch (propertyId) {
case 'x':
return this.mousePosition.x;
case 'y':
return this.mousePosition.y;
}
throw new Error('Bad property id');
}
public render(): void {
//显示黄色区域
this.domElement.innerHTML = `
<div id="webpartdiv" style="width: 700px; height: 200px; background-color: yellow">
</div>`;
//绑定onclick事件
this.domElement.onclick=this.onMouseClick.bind(this);
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: 'Description',
groupFields: [
PropertyPaneTextField('description', {
label: 'description'
})
]
}
]
}
]
};
}
}
然后我们修改TargetWebpart来使用SourceWebpart发布的数据。
首先导入DynamicProperty对象,然后再webpart属性中添加动态属性:
import { DynamicProperty } from '@microsoft/sp-component-base';
export interface ITargetWebpartWebPartProps {
description: string;
x: DynamicProperty<number>;
y: DynamicProperty<number>;
}
然后修改render方法,读取并显示动态数据:
public render(): void {
const x: number | undefined = this.properties.x.tryGetValue();
const y: number | undefined = this.properties.y.tryGetValue();
console.log(x);
this.domElement.innerHTML = `
<div class="${ styles.targetWebpart }">
<div class="${ styles.container }">
<div class="${ styles.row }">
<div class="${ styles.column }">
<span class="${ styles.title }">TargetWebpart</span>
<p class="${ styles.subTitle }">显示鼠标x和y坐标</p>
<div>Mouse X: ${ x == undefined ? '0' : x }</div>
<div>Mouse Y: ${ y == undefined ? '0' : y }</div>
</div>
</div>
</div>
</div>`;
}
然后添加一个propertiesMetadata方法,来指定动态数据的类型:
protected get propertiesMetadata(): IWebPartPropertiesMetadata {
return {
'x': {
dynamicPropertyType: 'number'
},
'y': {
dynamicPropertyType: 'number'
}
};
}
最后修改getPropertyPaneConfiguration方法,连接数据源:
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
groups: [
{
groupFields: [
PropertyPaneDynamicFieldSet({
label: 'Select data source',
fields: [
PropertyPaneDynamicField('x', {
label: 'Position x'
})
]
}),
PropertyPaneDynamicFieldSet({
label: 'Select data source',
fields: [
PropertyPaneDynamicField('y', {
label: 'Position y'
})
]
})
]
}
]
}
]
};
}
TargetWebpart的完整代码如下:
import { Version } from '@microsoft/sp-core-library';
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField,
IWebPartPropertiesMetadata,
IPropertyPaneConditionalGroup,
DynamicDataSharedDepth,
PropertyPaneDynamicFieldSet,
PropertyPaneDynamicField
} from '@microsoft/sp-webpart-base';
import { escape } from '@microsoft/sp-lodash-subset';
import styles from './TargetWebpartWebPart.module.scss';
import * as strings from 'TargetWebpartWebPartStrings';
import { DynamicProperty } from '@microsoft/sp-component-base';
export interface ITargetWebpartWebPartProps {
description: string;
x: DynamicProperty<number>;
y: DynamicProperty<number>;
}
export default class TargetWebpartWebPart extends BaseClientSideWebPart<ITargetWebpartWebPartProps> {
public render(): void {
const x: number | undefined = this.properties.x.tryGetValue();
const y: number | undefined = this.properties.y.tryGetValue();
console.log(x);
this.domElement.innerHTML = `
<div class="${ styles.targetWebpart }">
<div class="${ styles.container }">
<div class="${ styles.row }">
<div class="${ styles.column }">
<span class="${ styles.title }">TargetWebpart</span>
<p class="${ styles.subTitle }">显示鼠标x和y坐标</p>
<div>Mouse X: ${ x == undefined ? '0' : x }</div>
<div>Mouse Y: ${ y == undefined ? '0' : y }</div>
</div>
</div>
</div>
</div>`;
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
protected get propertiesMetadata(): IWebPartPropertiesMetadata {
return {
'x': {
dynamicPropertyType: 'number'
},
'y': {
dynamicPropertyType: 'number'
}
};
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
groups: [
{
groupFields: [
PropertyPaneDynamicFieldSet({
label: 'Select data source',
fields: [
PropertyPaneDynamicField('x', {
label: 'Position x'
})
]
}),
PropertyPaneDynamicFieldSet({
label: 'Select data source',
fields: [
PropertyPaneDynamicField('y', {
label: 'Position y'
})
]
})
]
}
]
}
]
};
}
}
gulp serve启动本地工作台,添加两个webpart,然后打开TargetWebpart的配置面版(如果打不开需要刷新一下页面),可以看到在配置面板中,可以选择数据源连接。连接数据源之后,鼠标点击黄色区域,TargetWebpart就会显示鼠标的坐标。
完整代码:https://gitee.com/shrenk/spfx-dynamicdata
参考文档:https://docs.microsoft.com/en-us/sharepoint/dev/spfx/dynamic-data