SharePoint Framework 1.7版本发布了,带来了很多新功能,新功能的简介请参见这里。
这篇博客介绍其中的开发者预览版新功能:列表订阅(ListSubscriptions in browser)。
开发者可以通过这个订阅的功能来监控某个文档库的更新,如果订阅的文档库有更新,会执行订阅时指定的回调函数。
下面来看代码如何实现。
首先使用Yeoman创建一个SPFx webpart项目,配置如图所示:
yo @microsoft/sharepoint
创建完成之后使用VS Code打开项目,使用订阅功能需要安装sp-list-subscription这个包,在Code里打开terminal,使用如下npm安装命令:
npm install @microsoft/sp-list-subscription --save --save-exact
安装完成之后,在webpart类定义文件中(我的这个项目中的类定义文件是ListSubscriptionWebPart.ts),导入ListSubscriptionFactory, IListSubscription这两个类,另外导入Guid类来处理guid:
然后在ListSubscriptionWebpart类中,render方法之前添加如下代码:
其中定义了两个类成员:_listSubscriptionFactory和_listSubscription。其中_listSubscriptionFactory包含两个方法,一个是createSubscription,用来创建一个订阅,另一个是deleteSubscription,用来删除一个订阅。
_listSubscription是_listSubscriptionFactory创建订阅的返回值,类型是IListSubscription,代表一个已经创建的订阅。实际上IListSubscription接口非常简单,只有一个id成员。
接下来我们定义了一个方法,“createListSubscription”,在这个方法里,通过调用_listSubscriptionFactory的createSubscription方法来订阅文档库的更新,这个方法的参数是ICreateSunscriptionSettings类型的,用来指定订阅的设置,定义如下:
export interface ICreateSubscriptionSettings {
/**
* In the case of a multi-geography tenancy, you need to provide the domain
* that the site collection lives in.
*/
domain?: string;
/**
* The SharePoint Site Id (assuming it is not the current site)
* If the siteId parameter is not provided, the current site will be used.
*/
siteId?: Guid;
/**
* The SharePoint Web Id (assuming it is not the current web)
* If the webId parameter is not provided, the current web will be used.
*/
webId?: Guid;
/**
* The Guid of the Sharepoint List. At this point, it needs to be a
* document library, and not just a list.
*/
listId?: Guid;
/**
* the list of callbacks
*/
callbacks: ISubscriptionCallbacks;
}
其中domain,siteId,webId,listId都不是必须的,如果不指定,会默认使用当前上下文中的值。也就是代码中的pageContext对象中的各个值。所以在这段代码中,我实际上是使用了这些参数的默认值。这里硬编码了listId,是因为在online的工作台上测试的时候,上下文中没有文档库的信息,所以我指定了一个文档库的id。
除了这些参数之外,还有一个最重要的参数:callback,可以用来指定三个回调函数,其中:
1,notification:当所订阅的文档库发生更新的时候调用
2,connect:当订阅连接成功的时候调用
3,disconnect:当订阅连接断开的时候调用
在指定了所有参数之后,调用_listSubscriptionFactory的createSubscription方法创建一个文档库的订阅。
稍后会在webpart的render()方法中调用这个方法,所以当webpart渲染的时候,就会创建一个订阅。
添加完之后的类的完整代码:
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 './ListSubscriptionWebPart.module.scss';
import * as strings from 'ListSubscriptionWebPartStrings';
import { ListSubscriptionFactory, IListSubscription } from '@microsoft/sp-list-subscription';
import { Guid } from '@microsoft/sp-core-library';
export interface IListSubscriptionWebPartProps {
description: string;
}
export default class ListSubscriptionWebPart extends BaseClientSideWebPart<IListSubscriptionWebPartProps> {
private _listSubscriptionFactory: ListSubscriptionFactory;
private _listSubscription: IListSubscription;
private createListSubscription(): void {
const myDomain: string = (new URL(this.context.pageContext.site.absoluteUrl)).hostname;
const mySiteId: Guid = this.context.pageContext.site.id;
const myWebId: Guid = this.context.pageContext.web.id;
const myLibraryId: string = 'a3d898b1-bfbd-4ced-a33d-0214d9d019ed';
this._listSubscriptionFactory = new ListSubscriptionFactory(this);
this._listSubscriptionFactory.createSubscription({
domain: myDomain,
siteId: mySiteId,
webId: myWebId,
listId: Guid.parse(myLibraryId),
callbacks: {
notification: this._loadDocuments.bind(this),
connect: this._subscriptionConnected.bind(this),
disconnect: this._subscriptionDisconnected.bind(this)
}
}).then(r=>{ this._listSubscription = r });
}
private _loadDocuments(): void {
console.log('Got notification!');
this._deleteSubscription(this._listSubscription);
}
private _subscriptionConnected(): void {
console.log('Connected!');
}
private _subscriptionDisconnected(): void {
console.log('Disconnected!');
}
private _deleteSubscription(subscription: IListSubscription) {
console.log('Delete subscription!');
this._listSubscriptionFactory.deleteSubscription(subscription);
}
public render(): void {
this.createListSubscription();
this.domElement.innerHTML = `
<div class="${ styles.listSubscription }">
<div class="${ styles.container }">
<div class="${ styles.row }">
<div class="${ styles.column }">
<span class="${ styles.title }">Welcome to SharePoint!</span>
<p class="${ styles.subTitle }">Customize SharePoint experiences using Web Parts.</p>
<p class="${ styles.description }">${escape(this.properties.description)}</p>
<a href="https://aka.ms/spfx" class="${ styles.button }">
<span class="${ styles.label }">Learn more</span>
</a>
</div>
</div>
</div>
</div>`;
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('description', {
label: strings.DescriptionFieldLabel
})
]
}
]
}
]
};
}
}
使用gulp servce启动,因为需要访问文档库,所以需要在online的工作台上测试。打开online工作台之后添加webpart,会首先在控制台中输出”Connected“,然后向所订阅的文档库中添加一个文档之后,控制台会输出”Got notification!",然后因为在_loadDocuemnts方法中调用了_deleteSubscription,所以会输出“Delete subscription!”,当删除了订阅之后,会断开与文档库的连接,所以最后输出“Disconnected!"。
补充说明:
1,列表订阅功能不局限于webpart中,webpart和扩展中都可以使用列表订阅。
2,目前只支持文档库订阅。
3,订阅会有一定时间的延迟,并不是绝对实时的。
4,可以同时订阅多个文档库。
5, 可以跨站点订阅。
6,出于安全的角度考虑,订阅不会返回具体的文档信息(例如添加或者修改了哪个文档),需要额外使用SharePoint REST API 或者 Microsoft Graph来获取具体的文档信息。
可能遇到的錯誤:
1,如果使用yo @microsoft/sharepoint --plusbeta创建项目,使用npm安裝sp-list-subscription包之后,可能会出现编译错误,这个是因为开发者预览版还不稳定的原因。所以在创建项目的时候不要使用--plusbeta。
2,错误:“NotificationUrl not found in response” 。这个是由于无法找到指定的文档库。在online工作台测试的时候,需要使用
根网站下的工作台,例如https://abc.sharepoint.com/_layouts/15/workbench.aspx, 不要使用子站点下的工作台, 例如https://abc.sharepoint.com/sites/xyz/_layouts/15/workbench.aspx
参考文档:https://docs.microsoft.com/en-us/sharepoint/dev/spfx/subscribe-to-list-notifications