练习 - 创建显示图像轮播的 SPFx 图像卡 ACE
在本练习中,你将使用图像卡模板创建一个SharePoint 框架 (SPFx) 自适应卡扩展 (ACE) ,该模板显示所选火星车上某个相机拍摄的图像。
先决条件
开发用于Viva Connections的 ACE 需要在租户中设置 Microsoft 365 租户、SharePoint Online 和Viva Connections。 使用以下资源准备租户:
还需要在工作站上安装必要的开发人员工具:
重要
在大多数情况下,安装以下工具的最新版本是最佳选择。 此模块在发布和最后测试过程中,使用了此处列出的版本。
- Node.js - v16.*
- Gulp-cli - v2.3.*
- Yeoman - v4.3.*
- 适用于 SharePoint 的 Yeoman 生成器 - v1.16.1
- Visual Studio Code
创建 SPFx 项目
打开命令提示符,移动到要在其中创建 SPFx 项目的文件夹。 然后,执行以下命令来运行 SharePoint Yeoman 生成器:
yo @microsoft/sharepoint
使用以下命令完成显示的提示:
- 解决方案名称是什么?:AceImageViewer
- 要创建哪种类型的客户端组件?:自适应卡片扩展
- 要使用哪个模板?:映像卡模板
- 自适应卡片扩展名称是什么?: AceImageViewer
预配项目所需的文件夹后,生成器将通过自动运行 npm install 来安装所有依赖项包。 在 NPM 完成下载所有依赖项后,在 Visual Studio Code 中打开项目。
向 ACE 组件添加公共属性
你将在本练习中创建的 ACE 组件将检索和显示火星车使用 美国宇航局开放 API 终结点之一拍摄的图像。
若要调用 API,需要设置三个值:
- API 密钥
- 火星车检索照片
- 火星太阳,火星上的太阳日,用于检索图像
所有这些属性都是 ACE 组件上的 公共和可配置属性。
注意
NASA 开放 API 支持使用演示 API 密钥或创建免费 API 密钥。 本练习假定你使用的是演示密钥。
演示密钥具有速率限制,例如一小时内和一天中每个 IP 地址的最大请求数。 如果超出演示 API 密钥限制,可以创建一个链接到电子邮件地址的密钥。 若要了解详细信息,请参阅 NASA 开放 API 站点。
首先,将属性添加到 ACE 组件。
在文件 ./src/adaptiveCardExtensions/aceImageViewer/AceImageViewerAdaptiveCardExtension.ts 中找到 ACE 类,并在 VS Code 中打开它。
找到 接口并将其
IAceImageViewerAdaptiveCardExtensionProps
更新为包含以下属性:export interface IAceImageViewerAdaptiveCardExtensionProps { title: string; nasa_api_key: string; nasa_rover: string; mars_sol: number; }
接下来,将属性添加到属性窗格:
在文件 ./src/adaptiveCardExtensions/aceImageViewer/AceImageViewerPropertyPane.ts 中找到 类,并在 VS Code 中打开它。
找到
import
导入 方法的PropertyPaneTextField
语句。 将此语句添加到PropertyPaneDropdown
方法import
的列表。import { IPropertyPaneConfiguration, PropertyPaneTextField, PropertyPaneDropdown // << add } from '@microsoft/sp-property-pane';
更新现有
getPropertyPaneConfiguration()
方法以接受指定所选漫游车的单个参数:public getPropertyPaneConfiguration(selectedRover: string = 'curiosity'): IPropertyPaneConfiguration { .. }
将以下字段添加到 方法中返回的 对象的 数组
groupFields
:getPropertyPaneConfiguration()
PropertyPaneTextField('nasa_api_key', { label: 'NASA API key' }), PropertyPaneDropdown('nasa_rover', { label: 'NASA Mars rover', options: [ { index: 0, key: 'curiosity', text: 'Curiosity' }, { index: 1, key: 'opportunity', text: 'Opportunity' }, { index: 2, key: 'spirit', text: 'Spirit' } ], selectedKey: selectedRover }), PropertyPaneTextField('mars_sol', { label: 'Display photos from Mars day (Sol)' })
让我们向属性窗格添加一个小的增强功能:火星车的下拉选择器应默认为当前所选的火星车。 方法的 getPropertyPaneConfiguration()
签名接受可用于设置它的输入参数:
返回 类
AceImageViewerAdaptiveCardExtension
并找到getPropertyPaneConfiguration()
方法。 将现有return
语句替换为以下内容:return this._deferredPropertyPane?.getPropertyPaneConfiguration(this.properties.nasa_rover);
最后,在将 ACE 组件添加到页面时,添加属性的一些默认值:
在文件 ./src/adaptiveCardExtensions/aceImageViewer/AceImageViewerAdaptiveCardExtension.manifest.json 中找到 ACE 类,并在 VS Code 中打开它。
将以下属性添加到 对象中的
preconfiguredEntries.properties
现有属性列表:"nasa_api_key": "DEMO_KEY", "nasa_rover": "curiosity", "nasa_sol": 1000
添加 NASA REST API 服务帮助程序
让我们向项目添加一个服务,以处理从美国宇航局 REST 开放 API 进行的所有读取。
在项目中创建一个新文件 ./src/adaptiveCardExtensions/aceImageViewer/nasa.service.ts ,并向其添加以下代码:
import { AdaptiveCardExtensionContext } from '@microsoft/sp-adaptive-card-extension-base';
import { HttpClient } from '@microsoft/sp-http';
export interface IMarsRoverCamera {
id: number;
name: string;
rover_id: number;
full_name: string;
}
export interface IMarsRoverVehicle {
id: number;
name: string;
landing_date: Date;
launch_date: Date;
status: string;
}
export interface IMarsRoverPhoto {
id: number;
sol: number;
camera: IMarsRoverCamera;
rover: IMarsRoverVehicle;
img_src: string;
earth_date: Date;
}
export const fetchRoverPhotos = async (
spContext: AdaptiveCardExtensionContext,
apiKey: string,
rover: string,
mars_sol: number): Promise<IMarsRoverPhoto[]> => {
const results: { photos: IMarsRoverPhoto[] } = await (
await spContext.httpClient.get(
`https://api.nasa.gov/mars-photos/api/v1/rovers/${rover}/photos?sol=${mars_sol}&page=1&api_key=${apiKey}`,
HttpClient.configurations.v1
)
).json();
return Promise.resolve(results.photos);
}
更新 ACE 组件的状态
创建公共属性和帮助程序服务后,现在让我们更新组件的状态,该状态用于显示组件中的数据。
在文件 ./src/adaptiveCardExtensions/aceImageViewer/AceImageViewerAdaptiveCardExtension.ts 中找到 ACE 类,并在 VS Code 中打开它。
在现有
import
语句后面添加以下import
语句:import { isEmpty } from '@microsoft/sp-lodash-subset' import { fetchRoverPhotos, IMarsRoverPhoto } from './nasa.service';
找到 接口并将其
IAceImageViewerAdaptiveCardExtensionState
更新为包含以下属性:export interface IAceImageViewerAdaptiveCardExtensionState { currentIndex: number; roverPhotos: IMarsRoverPhoto[]; }
接下来,更新
onInit()
类中的AceImageViewerAdaptiveCardExtension
方法,以将这两个属性初始化为空值:this.state = { currentIndex: 0, roverPhotos: [] };
在 中
onInit()
,添加以下代码,以在设置了最小属性的情况下从 NASA API 检索图像。 这应紧挨在现有return Promise.resolve();
if (!isEmpty(this.properties.nasa_api_key) && !isEmpty(this.properties.nasa_rover) && !isEmpty(this.properties.mars_sol)){ this.setState({ roverPhotos: await fetchRoverPhotos( this.context, this.properties.nasa_api_key, this.properties.nasa_rover, this.properties.mars_sol) }); }
最后一个语句使用
await
关键字 (keyword) ,因此你需要将async
关键字 (keyword) 添加到onInit()
方法的声明中:public async onInit(): Promise<void> {
让我们再处理一个方案:如果用户在属性窗格中更改了选定的 nasa_rover
或 mars_sol
,我们希望更新处于 状态的图像。 为此,请向 类添加以下代码 AceImageViewerAdaptiveCardExtension
。 当属性在属性窗格中发生更改时,它将运行:
protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void {
if (propertyPath === 'nasa_rover' && newValue !== oldValue) {
(async () => {
this.setState({ roverPhotos: await fetchRoverPhotos(
this.context,
this.properties.nasa_api_key,
newValue,
this.properties.mars_sol)
});
})
}
if (propertyPath === 'mars_sol' && newValue !== oldValue) {
(async () => {
this.setState({ roverPhotos: await fetchRoverPhotos(
this.context,
this.properties.nasa_api_key,
this.properties.nasa_rover,
newValue)
});
})
}
}
更新 CardView
现在,组件已设置为从 REST API 获取照片并将其存储在状态中,可以更新呈现以显示照片。 首先更新 CardView。
在 VS Code 中找到并打开 ./src/adaptiveCardExtensions/aceImageViewer/cardView/CardView.ts 文件。
添加对从包导入的
IActionArguments
接口的@microsoft/sp-adaptive-card-extension-base
引用:import { BaseImageCardView, IImageCardParameters, IExternalLinkCardAction, IQuickViewCardAction, ICardButton, IActionArguments // << add } from '@microsoft/sp-adaptive-card-extension-base';
接下来,更新 CardView 上显示的按钮。 CardView 可以返回零个、一个或两个按钮。 当不在照片集合的开头或末尾时,你想要显示两个按钮(上一个和下一个按钮)。 通过将 访问器方法的内容
cardButtons()
替换为以下代码来添加此项:const cardButtons: ICardButton[] = []; if (this.state.currentIndex !== 0) { cardButtons.push(<ICardButton>{ title: '<', id: '-1', action: { type: 'Submit', parameters: {} } }); } if (this.state.currentIndex !== (this.state.roverPhotos.length - 1)) { cardButtons.push(<ICardButton>{ title: '>', id: '1', action: { type: 'Submit', parameters: {} } }); } return (cardButtons.length === 0) ? undefined : (cardButtons.length === 1) ? [cardButtons[0]] : [cardButtons[0], cardButtons[1]];
接下来,将 访问器方法的内容
data()
替换为以下代码。 如果未指定火星车或火星索尔,这将返回火星的默认图像,其中包含一些说明。 否则,将显示当前图像:if (!this.properties.nasa_rover || !this.properties.mars_sol) { return { primaryText: `Select Mars rover & sol to display photos...`, imageUrl: 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/0e/Tharsis_and_Valles_Marineris_-_Mars_Orbiter_Mission_%2830055660701%29.png/240px-Tharsis_and_Valles_Marineris_-_Mars_Orbiter_Mission_%2830055660701%29.png', imageAltText: `Select Mars rover & sol to display photos...`, title: this.properties.title } } else { const rover = `${this.properties.nasa_rover.substring(0, 1).toUpperCase()}${this.properties.nasa_rover.substring(1)}`; const roverImage = this.state.roverPhotos[this.state.currentIndex]; if (roverImage) { return { primaryText: `Photos from the Mars rover ${rover} on sol ${this.properties.mars_sol}`, imageUrl: roverImage.img_src, imageAltText: `Image ${roverImage.id} taken on ${roverImage.earth_date} from ${rover}'s ${roverImage.camera.full_name} camera.`, title: this.properties.title }; } else { return { primaryText: `Please refresh the page to reload the rover photos`, imageUrl: '', imageAltText: '', title: this.properties.title } } }
接下来,将 访问器方法的内容
onCardSelection()
替换为以下代码。 这将打开 QuickView,在选择卡后,你将在一会儿更新该视图。return { type: 'QuickView', parameters: { view: QUICK_VIEW_REGISTRY_ID } };
接下来,通过将以下代码添加到 类来实现
onAction()
CardView
方法。 每当 CardView 的实现中发生提交操作时,都会运行该操作。 回想一下,cardButtons()
在 方法中,将按钮上的 属性设置为id
正数或负数,以在图像数组中导航:public onAction(action: IActionArguments): void { if (action.type !== 'Submit') { return; } let currentIndex = this.state.currentIndex; this.setState({ currentIndex: currentIndex + Number(action.id) }); }
最后,注释掉或删除对 对象的以下引用
strings
:import * as strings from 'AceImageViewerAdaptiveCardExtensionStrings';
更新 QuickView
测试 ACE 组件之前的最后一步是更新 QuickView。 在此方案中,QuickView 将显示有关当前照片的更多详细信息。
在 VS Code 中找到并打开 ./src/adaptiveCardExtensions/aceImageViewer/quickView/QuickView.ts 文件。
将以下
import
语句添加到现有导入:import { IMarsRoverPhoto } from '../nasa.service';
删除现有
IQuickViewData
接口。将 类
IMarsRoverPhoto
中QuickView
对 的所有剩余引用IQuickViewData
替换为 。将 访问器方法的内容
data()
替换为以下内容:return this.state.roverPhotos[this.state.currentIndex];
最后,注释掉或删除对 对象的以下引用
strings
:import * as strings from 'AceImageViewerAdaptiveCardExtensionStrings';
现在,更新自适应卡片模板:
在 VS Code 中找到并打开 ./src/adaptiveCardExtensions/aceImageViewer/quickView/template/QuickViewTemplate.json 文件。
将模板的内容替换为以下代码:
{ "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", "version": "1.2", "type": "AdaptiveCard", "body": [ { "type": "Image", "url": "${img_src}" }, { "type": "TextBlock", "text": "${rover.name} rover image #${id}", "horizontalAlignment": "Center" }, { "type": "TextBlock", "text": "Photo Details", "spacing": "Medium", "separator": true, "size": "Large", "weight": "Bolder" }, { "type": "FactSet", "facts": [ { "title": "Rover:", "value": "${rover.name}" }, { "title": "Camera:", "value": "${camera.full_name}" }, { "title": "Date taken:", "value": "${earth_date} (sol ${sol})" } ] } ] }
测试动态 ACE
让我们测试 ACE 以查看我们的图像浏览器!
在控制台中,执行以下语句:
gulp serve --nobrowser
在浏览器中,导航到要在其中测试 ACE 的站点中的 SharePoint 托管工作台。 例如,如果网站的 URL 为 https://contoso.sharepoint.com/sites/MSLearningTeam
,则托管工作台的 URL 为 https://contoso.sharepoint.com/sites/MSLearningTeam/_layouts/15/workbench.aspx
。
选择图标, + 然后从工具箱中选择 AceImageViewer :
请注意,组件的默认体验是使用火星图像。 那是因为我们没有火星索尔集:
与 SPFx Web 部件一样,可以将鼠标悬停在 ACE 组件上,然后选择铅笔图标以打开属性窗格:
将 Mars sol 设置为 1000 并关闭属性窗格,方法是选择右上角的 X ,然后选择页面顶部导航右上角的 “预览” 链接,将页面置于显示模式。
使用 CardView 上提供的按钮滚动浏览图像。 图像的裁剪版本显示在图像卡的卡片视图中
使用鼠标,选择卡上的任意位置,而无需选择任一按钮。 QuickView 将显示未裁剪的照片,其中包含有关拍摄时间的更多详细信息:
在本练习中,你创建了一个SharePoint 框架 (SPFx) 自适应卡片扩展 (ACE) ,该模板显示所选火星车上某个相机拍摄的图像。