生成属性窗格的自定义控件
SharePoint 框架包含一组属性窗格的标准控件。 不过,有时除了这组基本控件之外,还需要其他功能。 可能需要异步更新控件或特定用户界面上的数据。 生成属性窗格的自定义控件可以实现所需的功能。
在本文中,你将生成自定义下拉列表控件,在不阻止 Web 部件的用户界面的情况下,从外部服务异步加载数据。
可以从 GitHub (sp-dev-fx-webparts/samples/react-custompropertypanecontrols/) 获取有效 Web 部件的源。
注意
请务必先设置开发环境,以生成 SharePoint 框架解决方案,再执行本文中的步骤。
新建项目
首先,为项目新建文件夹:
md react-custompropertypanecontrol
转到项目文件夹:
cd react-custompropertypanecontrol
在项目文件夹中,运行 SharePoint Framework Yeoman 生成器,以搭建新的 SharePoint Framework 项目:
yo @microsoft/sharepoint
出现提示时,请输入以下值(为下面省略的所有提示选择默认选项):
- 要创建哪种类型的客户端组件? WebPart
- Web 部件名称是什么? 列表项目
- 你想要使用哪个模板? React
在代码编辑器中,打开项目文件夹。
定义 Web 部件属性以存储选定列表
正在生成的 Web 部件显示了选定 SharePoint 列表中的列表项。 用户可以在 Web 部件属性中选择列表。 要存储选定列表,请新建 Web 部件属性,名为 listName
。
在代码编辑器中,打开 src/webparts/listItems/ListItemsWebPartManifest.json 文件。 将默认的
description
属性替换为名为listName
的新属性:{ ... "preconfiguredEntries": [{ ... "properties": { "listName": "" } }] }
打开 src/webparts/listItems/ListItemsWebPart.ts 文件,并将
IListItemsWebPartProps
接口更新为以下内容:export interface IListItemsWebPartProps { description: string; listName: string; }
在 src/webparts/listItems/ListItemsWebPart.ts 文件中,将
render()
方法更改为:export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> { // ... public render(): void { const element: React.ReactElement<IListItemsProps> = React.createElement( ListItems, { listName: this.properties.listName, 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); } // ... }
将
getPropertyPaneConfiguration()
方法更新为:export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> { // ... protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration { return { pages: [ { header: { description: strings.PropertyPaneDescription }, groups: [ { groupName: strings.BasicGroupName, groupFields: [ PropertyPaneTextField('listName', { label: strings.ListFieldLabel }) ] } ] } ] }; } // ... }
在 src/webparts/listItems/loc/mystrings.d.ts 文件中, 向现有的
IListItemsWebPartStrings
接口添加类型string
的新属性ListFieldLabel
:declare interface IListItemsWebPartStrings { PropertyPaneDescription: string; BasicGroupName: string; .. ListFieldLabel: string; }
在 src/webparts/listItems/loc/en-us.js 文件中,向返回的对象添加新属性
ListFieldLabel
:define([], function() { return { "PropertyPaneDescription": "Description", "BasicGroupName": "Group Name", ... "ListFieldLabel": "List" } });
打开 src/webparts/listItems/components/IListItemsProps.ts 文件,将
listName
属性添加到列表接口:export interface IListItemsProps { description: string; isDarkTheme: boolean; environmentMessage: string; hasTeamsContext: boolean; userDisplayName: string; listName: string; }
在 src/webparts/listItems/components/ListItems.tsx 文件中,将
render()
方法的内容更改为:export default class ListItems extends React.Component<IListItemsProps, {}> { public render(): React.ReactElement<IListItemsProps> { const { description, isDarkTheme, environmentMessage, hasTeamsContext, userDisplayName, listName } = this.props; return ( <section className={`${styles.listItems} ${hasTeamsContext ? styles.teams : ''}`}> <div className={styles.welcome}> <img alt="" src={isDarkTheme ? require('../assets/welcome-dark.png') : require('../assets/welcome-light.png')} className={styles.welcomeImage} /> <h2>Well done, {escape(userDisplayName)}!</h2> <div>{environmentMessage}</div> <div>List name: <strong>{escape(listName)}</strong></div> </div> </section> ); } }
运行以下命令,确认项目是否正在运行:
gulp serve
在 Web 浏览器中,将列表项 Web 部件添加到画布,然后打开其属性。 验证为 List 属性设置的值是否显示在 Web 部件主体中。
创建异步下拉列表属性窗格控件
SharePoint Framework 提供了标准的下拉列表控件,使用户可以选择一个特定的值。 该下拉列表控件的构建方式要求提前知道其所有值。 如果要动态加载值,或者从外部服务异步加载值,并且不想阻止整个 Web 部件,则生成自定义下拉列表控件是一个选项。
当在 SharePoint Framework 中创建一个使用 React 的自定义属性窗格控件时,该控件包含可在 Web 部件中注册该控件的类和会呈现下拉列表并管理其数据的 React 组件。
添加异步下拉列表属性窗格控件 React 组件
创建“components”文件夹。 在项目“src”文件夹中,创建包含三个新文件夹的层次结构,这样文件夹结构显示为“src/controls/PropertyPaneAsyncDropdown/components”。
定义异步下拉列表 React 组件属性。 在“src/controls/PropertyPaneAsyncDropdown/components”文件夹中,新建“IAsyncDropdownProps.ts”文件,并输入以下代码:
import { IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown'; export interface IAsyncDropdownProps { label: string; loadOptions: () => Promise<IDropdownOption[]>; onChanged: (option: IDropdownOption, index?: number) => void; selectedKey: string | number; disabled: boolean; stateKey: string; }
IAsyncDropdownProps
类定义可在“回应”组件(由自定义属性窗格控件使用)上设置的属性:-
label
属性指定下拉列表控件的标签。 - 与
loadOptions
委托关联的函数由控件调用,以加载可用选项。 - 用户在下拉列表中选择选项后,系统会调用与
onChanged
委托关联的函数。 -
selectedKey
属性指定选定值,该值可以为字符串或数字。 -
disabled
属性指定是否禁用下拉列表控件。 -
stateKey
属性用于强制“回应”组件重新呈现。
-
定义异步下拉列表 React 组件接口。 在“src/controls/PropertyPaneAsyncDropdown/components”文件夹中,新建“IAsyncDropdownState.ts”文件,并输入以下代码:
import { IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown'; export interface IAsyncDropdownState { loading: boolean; options: IDropdownOption[]; error: string; }
IAsyncDropdownState
接口描述“回应”组件的状态:-
loading
属性确定组件是否正在给定时刻加载其选项。 -
options
属性包含所有可用选项。 - 如果发生错误,则系统会将其分配给其与用户通信的
error
属性中。
-
定义异步下拉列表 React 组件。 在“src/controls/PropertyPaneAsyncDropdown/components”文件夹中,新建“AsyncDropdown.tsx”文件,并输入以下代码:
import * as React from 'react'; import { Dropdown, IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown'; import { Spinner } from 'office-ui-fabric-react/lib/components/Spinner'; import { IAsyncDropdownProps } from './IAsyncDropdownProps'; import { IAsyncDropdownState } from './IAsyncDropdownState'; export default class AsyncDropdown extends React.Component<IAsyncDropdownProps, IAsyncDropdownState> { private selectedKey: React.ReactText; constructor(props: IAsyncDropdownProps, state: IAsyncDropdownState) { super(props); this.selectedKey = props.selectedKey; this.state = { loading: false, options: undefined, error: undefined }; } public componentDidMount(): void { this.loadOptions(); } public componentDidUpdate(prevProps: IAsyncDropdownProps, prevState: IAsyncDropdownState): void { if (this.props.disabled !== prevProps.disabled || this.props.stateKey !== prevProps.stateKey) { this.loadOptions(); } } private loadOptions(): void { this.setState({ loading: true, error: undefined, options: undefined }); this.props.loadOptions() .then((options: IDropdownOption[]): void => { this.setState({ loading: false, error: undefined, options: options }); }, (error: any): void => { this.setState((prevState: IAsyncDropdownState, props: IAsyncDropdownProps): IAsyncDropdownState => { prevState.loading = false; prevState.error = error; return prevState; }); }); } public render(): JSX.Element { const loading: JSX.Element = this.state.loading ? <div><Spinner label={'Loading options...'} /></div> : <div />; const error: JSX.Element = this.state.error !== undefined ? <div className={'ms-TextField-errorMessage ms-u-slideDownIn20'}>Error while loading items: {this.state.error}</div> : <div />; return ( <div> <Dropdown label={this.props.label} disabled={this.props.disabled || this.state.loading || this.state.error !== undefined} onChanged={this.onChanged.bind(this)} selectedKey={this.selectedKey} options={this.state.options} /> {loading} {error} </div> ); } private onChanged(option: IDropdownOption, index?: number): void { this.selectedKey = option.key; // reset previously selected options const options: IDropdownOption[] = this.state.options; options.forEach((o: IDropdownOption): void => { if (o.key !== option.key) { o.selected = false; } }); this.setState((prevState: IAsyncDropdownState, props: IAsyncDropdownProps): IAsyncDropdownState => { prevState.options = options; return prevState; }); if (this.props.onChanged) { this.props.onChanged(option, index); } } }
AsyncDropdown
类代表用于呈现异步下拉列表属性窗格控件的“回应”组件:- 当组件首次加载时,
componentDidMount()
方法或其disabled
或stateKey
属性发生更改,并调用通过属性传递的loadOptions()
方法以加载可用选项。 - 加载选项后,组件更新它的状态,同时显示可用选项。
- 使用 Office UI Fabric React 下拉列表组件呈现下拉列表本身。
- 组件加载可用选项时,它使用 Office UI Fabric React 旋转图标组件显示旋转图标。
- 当组件首次加载时,
下一步是定义自定义属性窗格控件。 在属性窗格中定义属性时,即在 Web 部件内使用此控件,它使用之前定义的 React 组件进行呈现。
添加异步下拉列表属性窗格控件
定义异步下拉列表属性窗格控件属性。 自定义属性窗格控件有两个属性集。
第一组属性是公开的,用于定义 Web 部件内的 Web 部件属性。 这些属性是组件专用属性,如控件旁边显示的标签、旋转图标的最小值和最大值或下拉列表的可用选项。 在定义自定义属性窗格控件时,在实现
IPropertyPaneField<TProperties>
接口时,必须将描述这些属性的类型作为TProperties
类型进行传递。第二组属性是专用属性,在自定义属性窗格控件内部使用。 这些属性必须遵守 SharePoint Framework API 以便正确呈现自定义控件。 这些属性必须实现
IPropertyPaneCustomFieldProps
@microsoft/sp-property-pane 包中的 接口。定义异步下拉列表属性窗格控件的公共属性。 在“src/controls/PropertyPaneAsyncDropdown”文件夹中,新建“IPropertyPaneAsyncDropdownProps.ts”文件,并输入以下代码:
import { IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown'; export interface IPropertyPaneAsyncDropdownProps { label: string; loadOptions: () => Promise<IDropdownOption[]>; onPropertyChange: (propertyPath: string, newValue: any) => void; selectedKey: string | number; disabled?: boolean; }
在
IPropertyPaneAsyncDropdownProps
接口中:-
label
: 定义下拉列表旁边显示的标签。 -
loadOptions
: 定义被调用以加载可用下拉列表选项的方法。 -
onPropertyChange
: 定义用户在下拉列表中选择值时调用的方法。 -
selectedKey
: 返回选定的下拉列表值。 -
disabled
: 指定是否禁用控件。
-
定义异步下拉列表属性窗格控件的内部属性。 在“src/controls/PropertyPaneAsyncDropdown”文件夹中,新建“IPropertyPaneAsyncDropdownInternalProps.ts”文件,并输入以下代码:
import { IPropertyPaneCustomFieldProps } from '@microsoft/sp-property-pane'; import { IPropertyPaneAsyncDropdownProps } from './IPropertyPaneAsyncDropdownProps'; export interface IPropertyPaneAsyncDropdownInternalProps extends IPropertyPaneAsyncDropdownProps, IPropertyPaneCustomFieldProps { }
虽然 IPropertyPaneAsyncDropdownInternalProps
接口不定义任何新属性,但其将之前定义的 IPropertyPaneAsyncDropdownProps
接口中的属性与标准 SharePoint 框架 IPropertyPaneCustomFieldProps
接口(自定义控件正确运行的必需项)组合在了一起。
定义异步下拉列表属性窗格控件。 在“src/controls/PropertyPaneAsyncDropdown”文件夹中,新建“PropertyPaneAsyncDropdown.ts”文件,并输入以下代码:
import * as React from 'react'; import * as ReactDom from 'react-dom'; import { IPropertyPaneField, PropertyPaneFieldType } from '@microsoft/sp-property-pane'; import { IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown'; import { IPropertyPaneAsyncDropdownProps } from './IPropertyPaneAsyncDropdownProps'; import { IPropertyPaneAsyncDropdownInternalProps } from './IPropertyPaneAsyncDropdownInternalProps'; import AsyncDropdown from './components/AsyncDropdown'; import { IAsyncDropdownProps } from './components/IAsyncDropdownProps'; export class PropertyPaneAsyncDropdown implements IPropertyPaneField<IPropertyPaneAsyncDropdownProps> { public type: PropertyPaneFieldType = PropertyPaneFieldType.Custom; public targetProperty: string; public properties: IPropertyPaneAsyncDropdownInternalProps; private elem: HTMLElement; constructor(targetProperty: string, properties: IPropertyPaneAsyncDropdownProps) { this.targetProperty = targetProperty; this.properties = { key: properties.label, label: properties.label, loadOptions: properties.loadOptions, onPropertyChange: properties.onPropertyChange, selectedKey: properties.selectedKey, disabled: properties.disabled, onRender: this.onRender.bind(this), onDispose: this.onDispose.bind(this) }; } public render(): void { if (!this.elem) { return; } this.onRender(this.elem); } private onDispose(element: HTMLElement): void { ReactDom.unmountComponentAtNode(element); } private onRender(elem: HTMLElement): void { if (!this.elem) { this.elem = elem; } const element: React.ReactElement<IAsyncDropdownProps> = React.createElement(AsyncDropdown, { label: this.properties.label, loadOptions: this.properties.loadOptions, onChanged: this.onChanged.bind(this), selectedKey: this.properties.selectedKey, disabled: this.properties.disabled, // required to allow the component to be re-rendered by calling this.render() externally stateKey: new Date().toString() }); ReactDom.render(element, elem); } private onChanged(option: IDropdownOption, index?: number): void { this.properties.onPropertyChange(this.targetProperty, option.key); } }
PropertyPaneAsyncDropdown
类将IPropertyPaneAsyncDropdownProps
接口用作可从 Web 部件内部设置的公共属性的合同,从而实现标准的 SharePoint 框架IPropertyPaneField
接口。 该类包含以下三个由IPropertyPaneField
接口定义的公共属性:-
type
: 必须设置为自定义属性窗格控件的PropertyPaneFieldType.Custom
。 -
targetProperty
: 用于指定要与控件一同使用的 Web 部件属性的名称。 -
properties
: 用于定义控件特定的属性。
请注意,
properties
属性为内部IPropertyPaneAsyncDropdownInternalProps
类型,而非由类实现的公共IPropertyPaneAsyncDropdownProps
接口。 这是有意为之,以便properties
属性可以定义 SharePoint 框架所需的onRender()
方法。 如果onRender()
方法为公共IPropertyPaneAsyncDropdownProps
接口的一部分,则在 Web 部件中使用异步下拉列表控件时,需要在 Web 部件内为其分配值,而这并不可取。PropertyPaneAsyncDropdown
类定义公共render()
方法,该方法可用于重画控件。 在某些情况下,如果级联下拉列表中一个下拉列表内设置的值决定了另一个下拉列表中的可用选项,这就非常有用。 在选择项后,调用render()
方法,便可以具有相关的下拉列表负载可用选项。 要实现这一点,必须让“回应”检测控件是否已更改。 为此,请将stateKey
的值设置为当前日期。 使用此技巧后,每次调用onRender()
方法时,不仅会重新呈现组件,而且还会更新其可用选项。 不要忘记实现onDispose()
方法,以在每次关闭属性窗格时卸载元素。-
在 Web 部件中使用异步下拉列表属性窗格控件
异步下拉列表属性窗格控件就绪后,下一步是在 Web 部件中使用它,以便用户能够选择列表。
添加列表信息接口
若要以一致的方式传递可用列表的相关信息,请定义表示列表相关信息的接口。 在“src/webparts/listItems”文件夹中,新建“IListInfo.ts”文件,并输入以下代码:
export interface IListInfo {
Id: string;
Title: string;
}
使用异步下拉列表属性窗格控件呈现 listName Web 部件属性
引用所需的类型。 在 src/webparts/listItems/ListItemsWebPart.ts 文件的顶部部分,添加以下内容,以导入之前创建的
PropertyPaneAsyncDropdown
类:import { PropertyPaneAsyncDropdown } from '../../controls/PropertyPaneAsyncDropdown/PropertyPaneAsyncDropdown';
在该代码之后,添加对
IDropdownOption
接口的引用以及处理 Web 部件属性所需的两个帮助程序函数。import { IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown'; import { update, get } from '@microsoft/sp-lodash-subset';
添加用于加载可用列表的方法。 在
ListItemsWebPart
类中,添加以下loadLists()
方法以加载可用列表。 在本文中,你使用模拟数据,但仍然可以调用 SharePoint REST API 以从当前网站检索可用列表的列表。 为了模拟从外部服务加载选项,此方法使用两秒延迟。private loadLists(): Promise<IDropdownOption[]> { return new Promise<IDropdownOption[]>((resolve: (options: IDropdownOption[]) => void, reject: (error: any) => void) => { setTimeout(() => { resolve([{ key: 'sharedDocuments', text: 'Shared Documents' }, { key: 'myDocuments', text: 'My Documents' }]); }, 2000); }); }
添加处理下拉列表中值更改的方法。 在
ListItemsWebPart
类中,添加名为onListChange()
的新方法。private onListChange(propertyPath: string, newValue: any): void { const oldValue: any = get(this.properties, propertyPath); // store new value in web part properties update(this.properties, propertyPath, (): any => { return newValue; }); // refresh web part this.render(); }
当用户在下拉列表中选择一个列表后,选定值应暂留在 Web 部件属性中,且应重新呈现 Web 部件以反映选定属性。
使用异步下拉列表属性窗格控件呈现“列表”Web 部件属性。 在
ListItemsWebPart
类中,将getPropertyPaneConfiguration()
方法更改为使用异步下拉列表属性窗格控件,以呈现listName
Web 部件属性。export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> { // ... protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration { return { pages: [ { header: { description: strings.PropertyPaneDescription }, groups: [ { groupName: strings.BasicGroupName, groupFields: [ new PropertyPaneAsyncDropdown('listName', { label: strings.ListFieldLabel, loadOptions: this.loadLists.bind(this), onPropertyChange: this.onListChange.bind(this), selectedKey: this.properties.listName }) ] } ] } ] }; } // ... }
此时,可以使用新建的异步下拉列表属性窗格控件以选择列表。 要验证控件是否按预期工作,请打开控制台并运行:
gulp serve
使用异步下拉列表属性窗格控件实现级联下拉列表
生成 SharePoint 框架 Web 部件时,可能需要实现可用选项取决于之前选择的其他选项的配置。 一个常见例子是先让用户选择列表,再选择此列表中的列表项。 一组可用列表项视选定列表而定。 下面介绍了如何使用先前步骤中实现的异步下拉列表属性窗格控件实现此类方案。
添加“列表项”Web 部件属性
在代码编辑器中,打开“src/webparts/listItems/ListItemsWebPart.manifest.json”文件。 向
properties
部分添加名为item
的新属性,如下所示:{ ... "preconfiguredEntries": [{ ... "properties": { "description": "List items", "listName": "", "item": "" } }] }
将 src/webparts/listItems/ListItemsWebPart.ts 文件中的 IListItemsWebPartProps 接口中的代码更改为:
export interface IListItemsWebPartProps { description: string; listName: string; item: string; }
更新 src/webparts/listItems/components/IListItemsProps.ts 文件的内容,添加
item
属性:export interface IListItemsProps { ... listName: string; itemName: string; }
在 src/webparts/listItems/ListItemsWebPart.ts 文件中,更改
render()
方法的代码,使其包含item
属性:export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> { // ... public render(): void { const element: React.ReactElement<IListItemsProps> = React.createElement(ListItems, { listName: this.properties.listName, itemName: this.properties.item, ... }); ReactDom.render(element, this.domElement); } // ... }
在 src/webparts/listItems/loc/mystrings.d.ts 文件中,更改
IListItemsWebPartStrings
接口,使其包含ItemFieldLabel
属性:declare interface IListItemsWebPartStrings { ... PropertyPaneDescription: string; BasicGroupName: string; ListFieldLabel: string; ItemFieldLabel: string; }
在 src/webparts/listItems/loc/en-us.js 文件中,添加
ItemFieldLabel
字符串缺少的定义:define([], function() { return { ... "PropertyPaneDescription": "Description", "BasicGroupName": "Group Name", "ListFieldLabel": "List", "ItemFieldLabel": "Item" } });
呈现项 Web 部件属性的值
在 src/webparts/listItems/components/ListItems.tsx 文件中,将 render()
方法更改为:
export default class ListItems extends React.Component<IListItemsProps, {}> {
public render(): React.ReactElement<IListItemsProps> {
const {
description,
isDarkTheme,
environmentMessage,
hasTeamsContext,
userDisplayName,
listName,
itemName
} = this.props;
return (
<section className={`${styles.listItems} ${hasTeamsContext ? styles.teams : ''}`}>
<div className={styles.welcome}>
<img alt="" src={isDarkTheme ? require('../assets/welcome-dark.png') : require('../assets/welcome-light.png')} className={styles.welcomeImage} />
<h2>Well done, {escape(userDisplayName)}!</h2>
<div>{environmentMessage}</div>
<div>List name: <strong>{escape(listName)}</strong></div>
<div>Item name: <strong>{escape(itemName)}</strong></div>
</div>
</section>
);
}
}
添加加载列表项的方法
在 src/webparts/listItems/ListItemsWebPart.ts 文件中,在 ListItemsWebPart
类中添加新方法,以从选定列表加载可用的列表项。 与加载可用列表的方法一样,使用的是模拟数据。 根据之前选择的列表, loadItems()
方法会返回模拟列表项。 没有选择列表时,此方法可解决这一承诺,而不包含任何数据。
private loadItems(): Promise<IDropdownOption[]> {
if (!this.properties.listName) {
// resolve to empty options since no list has been selected
return Promise.resolve([]);
}
const wp: ListItemsWebPart = this;
return new Promise<IDropdownOption[]>((resolve: (options: IDropdownOption[]) => void, reject: (error: any) => void) => {
setTimeout(() => {
const items = {
sharedDocuments: [
{
key: 'spfx_presentation.pptx',
text: 'SPFx for the masses'
},
{
key: 'hello-world.spapp',
text: 'hello-world.spapp'
}
],
myDocuments: [
{
key: 'isaiah_cv.docx',
text: 'Isaiah CV'
},
{
key: 'isaiah_expenses.xlsx',
text: 'Isaiah Expenses'
}
]
};
resolve(items[wp.properties.listName]);
}, 2000);
});
}
添加用于处理列表项选择的方法
在 ListItemsWebPart
类中,添加名为 onListItemChange()
的新方法。 在项下拉列表中选择一项后,Web 部件应在 Web 部件中存储新值并重新呈现 Web 部件以反映用户界面中的更改。
private onListItemChange(propertyPath: string, newValue: any): void {
const oldValue: any = get(this.properties, propertyPath);
// store new value in web part properties
update(this.properties, propertyPath, (): any => { return newValue; });
// refresh web part
this.render();
}
在属性窗格中呈现“列表项”Web 部件属性
在
ListItemsWebPart
类中,添加名为itemsDropdown
的新类属性:export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> { private itemsDropDown: PropertyPaneAsyncDropdown; // ... }
将
getPropertyPaneConfiguration()
方法的代码更改为:export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> { // ... protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration { // reference to item dropdown needed later after selecting a list this.itemsDropDown = new PropertyPaneAsyncDropdown('item', { label: strings.ItemFieldLabel, loadOptions: this.loadItems.bind(this), onPropertyChange: this.onListItemChange.bind(this), selectedKey: this.properties.item, // should be disabled if no list has been selected disabled: !this.properties.listName }); return { pages: [ { header: { description: strings.PropertyPaneDescription }, groups: [ { groupName: strings.BasicGroupName, groupFields: [ new PropertyPaneAsyncDropdown('listName', { label: strings.ListFieldLabel, loadOptions: this.loadLists.bind(this), onPropertyChange: this.onListChange.bind(this), selectedKey: this.properties.listName }), this.itemsDropDown ] } ] } ] }; } // ... }
item 属性的下拉列表的初始化方式与 listName 属性的下拉列表类似。 唯一区别在于,必须将控件实例分配给类变量,因为在用户选择列表后必须刷新“列表项”下拉列表。
加载选定列表的列表项
开始时,如果用户未选择任何列表,“列表项”下拉列表处于禁用状态,并在用户选择列表后启用。 在用户选择列表后,“列表项”下拉列表还加载相应列表中的列表项。
要实现此逻辑,请将之前定义的
onListChange()
方法扩展到:private onListChange(propertyPath: string, newValue: any): void { const oldValue: any = get(this.properties, propertyPath); // store new value in web part properties update(this.properties, propertyPath, (): any => { return newValue; }); // reset selected item this.properties.item = undefined; // store new value in web part properties update(this.properties, 'item', (): any => { return this.properties.item; }); // refresh web part this.render(); // reset selected values in item dropdown this.itemsDropDown.properties.selectedKey = this.properties.item; // allow to load items this.itemsDropDown.properties.disabled = false; // load items and re-render items dropdown this.itemsDropDown.render(); }
选择列表后,选定的项将重置、保持在 Web 部件属性中,并在项目下拉列表中重置。 将启用用于选择项的下拉列表,并刷新下拉列表以加载其选项。
要验证一切是否按预期正常运行,请在控制台中运行:
gulp serve
第一次向页中添加 Web 部件并打开其属性窗格后,你会看到下拉列表被禁用并加载其选项。
加载选项后,就会启用列表下拉列表。 因为尚未选择任何列表,项下拉列表将保持禁用状态。
在列表下拉列表中选择一个列表后,项下拉列表将加载该列表中的可用项。
加载可用项后,就会启用项下拉列表。
在项下拉列表中选择一项后,会刷新 Web 部件,在其主体中显示所选的项。
通过在控制台中按 CTRL+C 来停止本地 Web 服务器。