将现有脚本编辑器 Web 部件自定义迁移到 SharePoint 框架

SharePoint 框架是用于生成 SharePoint 自定义的模型。 如果一直以来都是使用脚本编辑器 Web 部件生成客户端 SharePoint 解决方案,可能想知道将它们迁移到 SharePoint 框架有哪些潜在优势。

本文重点介绍了将现有客户端自定义迁移到 SharePoint 框架的优势,并指出计划迁移时应注意的许多事项。

注意

本文中的信息适用于使用内容编辑器 Web 部件和脚本编辑器 Web 部件生成的自定义。 只要引用脚本编辑器 Web 部件,就应阅读内容编辑器 Web 部件和脚本编辑器 Web 部件

将现有客户端自定义迁移到 SharePoint 框架的优势

SharePoint 框架从头到尾打造为注重客户端开发的 SharePoint 开发模型。 虽然主要是为新式团队网站提供扩展性功能,但在 SharePoint 框架基础之上生成的自定义还可以与经典 SharePoint 体验配合使用。 与目前可用的其他任何 SharePoint 开发模型相比,使用 SharePoint 框架生成自定义带来了诸多优势。

只需生成一次即可跨所有设备重用

新式 SharePoint 用户体验旨在为访问任意设备上的 SharePoint 中存储的信息提供本机支持。 此外,新式体验还支持 SharePoint 移动应用。 使用 SharePoint 框架生成的解决方案与新式 SharePoint 体验无缝集成,不仅可跨不同的设备使用,还能用于 SharePoint 移动应用中。 由于 SharePoint 框架解决方案还使用经典 SharePoint 体验,因此还可供尚未迁移到新式体验的组织使用。

更可靠且不会过时

过去开发人员通过附加到用户界面中的特定 DOM 元素来自定义 SharePoint。 通过这种方法,他们可以更改标准的用户体验或向最终用户提供附加功能。 但是此类解决方案容易出错。 由于 SharePoint 页面 DOM 从不作为扩展性界面,因此一旦其发生更改,依赖它的解决方案将中断。

SharePoint 框架为开发人员提供标准化 API 和扩展点,用于生成客户端解决方案,并为最终用户提供附加功能。 开发人员可以使用 SharePoint 框架生成受支持且不会过时的解决方案,并且无需担心今后的 SharePoint 用户界面变化会影响解决方案。

可以更轻松地访问 SharePoint 和 Office 365 中的信息

Microsoft 正在持续扩展 SharePoint 和 Office 365 的功能。 随着组织更多地利用这两个平台,开发人员利用存储在Office 365中的信息和见解来构建丰富的解决方案变得越来越重要。 SharePoint Framework 的目标之一是使开发人员可以轻松地连接到各种 SharePoint 和 Office 365 API。

允许用户配置解决方案来满足他们的需求

通过脚本嵌入构建的客户端解决方案通常无法为最终用户提供一种简单的方法来配置他们以满足其需求。 配置此类解决方案的唯一方法是更改其代码或通过专为此目的生成的自定义用户界面执行操作。

SharePoint Framework 客户端 Web 部件提供了使用属性窗格配置 Web 部件的标准方法,过去使用经典 Web 部件的用户对此方法很熟悉。 生成客户端 Web 部件的开发人员可以选择其 Web 部件要包含响应式属性窗格(默认设置,此时 Web 部件属性的所有更改均会直接反映到 Web 部件主体中)还是非响应式属性窗格(此时必须显式应用 Web 部件属性的更改)。

支持启用 NoScript 的网站

为帮助组织治理自定义,Microsoft 在 SharePoint Online 中推出了 NoScript 功能。 如果租户或特定网站集已启用 NoScript 标志,依赖脚本注入和嵌入的自定义遭禁用。

由于 SharePoint 框架客户端 Web 部件通过预先批准的应用程序目录进行部署,因此可以在启用 NoScript 的网站中运行。 默认情况下,新式团队网站已启用 NoScript 设置,无法在此类网站中嵌入脚本。 这样一来,使用 SharePoint 框架成为在新式团队网站中生成客户端自定义的唯一受支持方法。

SharePoint 框架解决方案与脚本编辑器 Web 部件自定义的相似之处

使用新工具链在新开发模型上生成的 SharePoint Framework 解决方案与过去生成的脚本编辑器 Web 部件自定义项类似。 由于它们共享相同的概念,因此更便于将其迁移到新的 SharePoint Framework。

作为页面的一部分运行

与在脚本编辑器 Web 部件中嵌入的自定义相似,SharePoint 框架解决方案也作为页面的一部分运行。 这样一来,这些解决方案既可以访问页面的 DOM,也可以与同一页面上的其他组件进行通信。 此外,开发人员还可以更轻松地生成自适应解决方案,适应可能显示 SharePoint 页面的各种外形规格(包括 SharePoint 移动应用)。

与 SharePoint 加载项不同,SharePoint 框架客户端 Web 部件并未在 iframe 中进行隔离。 因此,无论特定客户端 Web 部件可以访问哪些资源,页面上的其他元素也都可以访问这些资源。 在使用持有者访问令牌生成依赖于 OAuth 隐式流的解决方案或使用 cookie 或浏览器存储来存储敏感信息时,请务必注意这一点。 由于客户端 Web 部件作为页面的一部分运行,因此,该页面上的其他元素也可以访问所有这些资源。

使用任意库生成 Web 部件

使用脚本编辑器 Web 部件生成自定义时,可能使用了 jQuery 或 Knockout 等库,让自定义动态化,并能更好地响应用户交互。 生成 SharePoint 框架客户端 Web 部件时,可以使用任意客户端库来丰富解决方案,与过去执行的操作一样。 SharePoint 框架的另一个好处是,可以隔离脚本。 即使将 Web 部件作为页面的一部分运行,也会将它的脚本打包为模块。这样,即便同一页面上的各个 Web 部件使用不同版本的 jQuery,也不会相互冲突。 借助这一强大功能,可以专注于实现业务增值,而无需考虑技术迁移和功能妥协方案。

以当前用户身份运行

在使用脚本编辑器 Web 部件生成的自定义中,无论何时需要与 SharePoint 通信,都只需调用它的 API 即可。 客户端解决方案以当前用户身份在浏览器中运行。通过自动将身份验证 Cookie 与请求一起发送,解决方案可以直接连接到 SharePoint。 无需进行其他身份验证(如在使用 SharePoint 加载项时),即可与 SharePoint 通信。 相同的机制适用于在 SharePoint 框架基础之上生成的自定义,即也是在当前已验证用户的上下文中运行,并且无需执行其他任何身份验证步骤,即可与 SharePoint 通信。

仅使用客户端代码

SharePoint Framework 和脚本编辑器 Web 部件解决方案均在浏览器中运行,并且都可以只包含客户端 JavaScript 代码。 客户端解决方案有许多限制,如无法在 SharePoint 中提升权限,或无法访问不支持使用 OAuth 隐式流进行跨源通信 (CORS) 或身份验证的外部 API。 在这些情况下,客户端解决方案可以使用远程服务器端 API 执行必要操作,并向客户端返回结果。

在 SharePoint 中托管解决方案

使用脚本编辑器 Web 部件生成 SharePoint 自定义的优势之一是,代码可以托管在常规 SharePoint 文档库中。 与 SharePoint 加载项相比,它需要的基础设施更少,因此简化了解决方案的托管过程。 此外,组织还可以使用 SharePoint 权限来控制对解决方案文件的访问。

虽然在 CDN 上托管 SharePoint Framework 解决方案具有诸多优势,但这不是必需的操作,你可以选择将其代码托管在常规 SharePoint 文档库中。 SharePoint 框架包 (*.sppkg 文件) 部署到应用目录,指定SharePoint 框架可在其中查找解决方案代码的 URL。 对于具体的 URL,没有任何限制,只要浏览包含 Web 部件的页面的用户可以从指定位置下载脚本即可。

Office 365 提供了公用 CDN 功能,通过此功能可以将特定 SharePoint 文档库中的文件发布到 CDN。 Office 365 公用 CDN 巧妙地平衡了使用 CDN 的优势和在 SharePoint 文档库中托管代码文件的易用性。 如果组织不介意公开发布代码文件,可以考虑使用 Office 365 公用 CDN。

SharePoint 框架解决方案与脚本编辑器 Web 部件自定义的区别

使用 SharePoint 框架和脚本编辑器 Web 部件生成的 SharePoint 自定义相似。 它们全都作为页面的一部分在当前用户上下文中运行,并且都使用客户端 JavaScript 生成。 不过,也存在一些可能会影响体系结构决策的显著差异,应在设计解决方案时注意这些差异。

在启用 NoScript 的网站中运行

使用脚本编辑器 Web 部件生成客户端自定义时,必须考虑要使用自定义的网站是否已启用 NoScript。 如果网站已启用 NoScript,要么必须让管理员禁用 NoScript 设置,要么必须以其他方式(例如,使用加载项模型)生成解决方案。

由于 SharePoint Framework 解决方案是通过预先批准的应用程序目录部署的,因此它们不受无脚本限制的制约,并且适用于所有站点。

通过 IT 组织部署和更新

脚本编辑器 Web 部件主要供普通开发人员用来生成 SharePoint 自定义。 只需具备网站所有者权限,普通开发人员就可以生成有吸引力的 SharePoint 自定义,从而增加业务价值。 只要需要更新自定义,具备必要权限的用户就可以对解决方案的脚本文件应用更新,而相应更改也会立即反映给所有用户。

脚本编辑器 Web 部件解决方案使 IT 组织难以跟踪正在使用的自定义项和正在使用自定义项的位置。 此外,组织无法分辨其内部网中正在使用哪些外部脚本及哪些脚本可以访问其数据。

SharePoint Framework 向 IT 组织返还了此控制权限。 由于 SharePoint Framework 解决方案是在应用程序目录中集中进行部署和管理的,因此组织可以在部署前检查解决方案。 此外,所有更新也都是通过应用程序目录部署的,这样组织可以在部署前对他们进行验证和审批。

更加注重统一的用户体验

使用脚本编辑器 Web 部件生成自定义时,普通开发人员拥有自定义的完整 DOM。 没有关于用户体验和这些自定义的工作原理的指南。 因此,不同的开发人员生成自定义的方式也不同,进而导致最终用户的用户体验不一致。

SharePoint 框架的目标之一是将生成客户端自定义的过程标准化,以便从部署、维护和用户体验角度实现统一性。 使用 Office UI Fabric ,开发人员可以更轻松地生成外观和行为如同 SharePoint 一部分的自定义解决方案,让用户更易接受。 SharePoint 框架工具链为已部署到应用程序目录的解决方案生成包文件,并为已部署到选定托管位置的脚本捆绑包生成包文件。 每个解决方案都以相同方式进行构造和管理。

不在自定义范畴外修改 DOM

脚本编辑器 Web 部件过去经常用于修改页面部件,如向工具栏添加按钮,或更改页面的标题或品牌。 此类自定义依赖特定 DOM 元素,一旦 SharePoint UI 要进行更新,此类自定义可能会中断。

SharePoint 框架建议使用结构化程度更高且更可靠的方法来自定义 SharePoint。 SharePoint Framework 未使用特定 DOM 元素来自定义 SharePoint,而是向开发人员提供一种公共 API 用于扩展 SharePoint。 客户端 Web 部件是 SharePoint 框架唯一支持的形状,但 JSLink 和“用户自定义操作”的等效项等其他形状将在未来被纳入考虑,让开发人员能够使用 SharePoint 框架实现最常见的自定义场景。

以包的形式分发

SharePoint 客户端自定义项通常使用 SharePoint 列表和库存储其数据。 使用脚本生成器 Web 部件生成时,没有可以自动预配所需必备项的简单方法。 将同一个自定义项部署到其他站点中不只是意味着复制 Web 部件,还意味着以正确的方式重新创建和维护必要的数据存储。

SharePoint 框架解决方案以能够自动预配必备项(如字段、内容类型或列表)的包形式进行分发。 生成包的开发人员可以指定解决方案必需的项目;只要在网站中安装此包,就会创建指定的项目。 这极大地简化了在多个网站上部署和管理解决方案的过程。

使用 TypeScript 生成更可靠且更易维护的解决方案

使用脚本编辑器 Web 部件生成自定义时,普通开发人员通常使用的是纯 JavaScript。 此类解决方案经常不含任何自动测试,且重构代码容易出错。

通过 SharePoint 框架,开发人员可以在生成解决方案时受益于 TypeScript 类型系统。 有了此类型系统,就可以在开发期间捕获错误,而无需等到运行时捕获。 此外,可以更加轻松地完成代码重构,因为对代码的更改受 TypeScript 的保护。 由于所有 JavaScript 都是有效的 TypeScript,进入限制较低,因此可以逐渐将纯 JavaScript 迁移到 TypeScript,从而提高解决方案的可维护性。

无法依赖 spPageContextInfo 对象

生成可重用客户端自定义时,为了获取当前页面、网站或用户的相关信息,开发人员过去使用的是 spPageContextInfo JavaScript 对象。 该对象为开发人员提供了一种简单的方法,使其解决方案可重用于 SharePoint 中的不同站点且不必使用固定的 URL。

虽然经典 SharePoint 页面上仍有 spPageContextInfospPageContextInfo对象,但此对象无法可靠用于新式 SharePoint 页面和库。 在 SharePoint 框架上生成解决方案时,建议开发人员改用 [IWebPartContext.pageContext](/javascript/api/sp-webpart-base/iwebpartcontext)对象,其中包含特定解决方案的上下文信息。

默认不访问 SharePoint JavaScript 对象模型

生成经典 SharePoint 用户体验的客户端自定义项时,许多开发人员使用 JavaScript 对象模型 (JSOM) 与 SharePoint 进行通信。 JSOM 为开发人员提供 IntelliSense,并方便他们轻松访问 SharePoint API,就像客户端对象模型 (CSOM) 一样。 在经典 SharePoint 页面中,JSOM 的核心部分默认显示在页面上,开发人员可以加载其他部分,与 SharePoint 搜索(举个例子)进行通信。

新式 SharePoint 用户体验默认不包括 SharePoint JSOM。 虽然开发人员可以自行加载它,但仍建议改用 REST API。 使用 REST 更为通用,且可以在不同的客户端库(如 jQuery、Angular 或 React)之间进行互换。

Microsoft 不再继续积极研究和改善 JSOM。 如果更倾向于使用 API,也可以使用SharePoint 模式和做法 JavaScript 核心库,其中包含 Fluent API 和 TypeScript 类型定义。

将现有自定义迁移到 SharePoint 框架

将现有脚本编辑器 Web 部件自定义迁移到 SharePoint 框架,为最终用户和开发人员带来了诸多优势。 考虑将现有自定义迁移到 SharePoint 框架时,可以选择尽量重用现有脚本,也可以选择完全重写自定义。

重用现有脚本

将现有脚本编辑器 Web 部件自定义迁移到 SharePoint 框架时,可以选择重用现有脚本。 即使 SharePoint 框架建议使用 TypeScript,也可以使用纯 JavaScript,并逐渐转换为 TypeScript。 如果需要在有限时间内为特定解决方案提供支持或预算有限,这种方法可能是理想之选。

在 SharePoint 框架解决方案中重用现有脚本的方法不一定可行。 例如,将 SharePoint 框架解决方案打包为 JavaScript 模块,并在页面上异步加载。 一些 JavaScript 库在模块中获得引用时无法正常运行,或必须以特定方式引用才能运行。 此外,依赖于页面事件(如 onload())或使用 jQuery ready() 函数还可能会导致意外结果。

鉴于 JavaScript 库的多样性,很难提前判断是能够在 SharePoint 框架解决方案中重用现有脚本,还是需要进行完全重写。 为了确定这一点,只能尝试将不同部分移到 SharePoint 框架解决方案中,并检查这些部分能否按预期正常运行。

重写自定义

如果需要在较长的一段时间内支持解决方案、要更好地利用 SharePoint 框架,或事实证明现有脚本无法重用于 SharePoint 框架,可能需要完全重写自定义。 虽然相对于重用现有脚本而言,这样做的成本更高,但它可以在较长时间内实现更佳效果,即性能更优且更易维护和使用的解决方案。

将现有脚本编辑器 Web 部件自定义重写为 SharePoint 框架解决方案时,应从所需的功能入手。 若要实现用户体验,应考虑使用 Office UI Fabric,让解决方案看起来是 SharePoint 不可分割的一部分。 对于特定组件(如图表或滑块),应尝试寻找以模块的形式分发且包含 TypeScript 类型定义的新式库。 这样就可以在解决方案中更轻松地集成组件。

对于哪个组件最适用于哪个方案的问题,没有唯一答案,但是 SharePoint 框架足以灵活满足多数常见方案的需求,应能将现有客户端自定义转换为功能完备的 SharePoint 框架解决方案。

迁移提示

将现有脚本编辑器 Web 部件自定义转换到 SharePoint 框架时,有一些常见模式。

将现有代码迁移到 SharePoint 框架

使用脚本编辑器 Web 部件生成的 SharePoint 自定义通常包含一些 HTML 标记(包含在 Web 部件中),以及一个或多个对 JavaScript 文件的引用。 将现有的自定义转换为 SharePoint 框架解决方案时,很可能需要将脚本编辑器 Web 部件内的 HTML 标记移动到 SharePoint 框架客户端 Web 部件的 render()方法中。 对外部脚本的引用更改为 ./config/config.json 文件的externals属性中的引用。 内部脚本被复制到 Web 部件源文件夹,并使用require()语句通过 Web 部件类进行引用。

通过脚本文件引用函数

若要通过脚本文件引用函数,必须将这些函数定义为导出。 考虑要用于 SharePoint 框架客户端 Web 部件的现有 JavaScript 文件:

var greeting = function() {
  alert('How are you doing?');
  return false;
}

若要能够通过 Web 部件类调用 greetinggreeting 函数,需要将 JavaScript 文件更改为:

var greeting = function() {
  alert('How are you doing?');
  return false;
}

module.exports = {
  greeting: greeting
};

然后,可以在 Web 部件类中引用脚本,并调用greeting函数:

public render(): void {
  this.domElement.innerHTML = `<input type="button" value="Click me"/>`;

  const myScript = <any> require('./my-script.js');
  this.domElement.querySelector('input').addEventListener('click', myScript.greeting);
}

执行 AJAX 调用

为了实现简单性和跨浏览器兼容性,许多客户端自定义都使用 jQuery 执行 AJAX 请求。 如果这是使用 jQuery 的全部原因,可以使用 SharePoint 框架提供的标准 HTTP 客户端执行 AJAX 调用。

SharePoint Framework 提供了两种类型的 HTTP 客户端:SPHttpClient(用于执行对 SharePoint REST API 的请求)和 HttpClient(用于发出对其他 REST API 的 Web 请求)。 下面展示了如何使用 SPHttpClient 执行调用,以获取当前 SharePoint 网站的标题:

this.context.spHttpClient.get(`${this.context.pageContext.web.absoluteUrl}/_api/web?$select=Title`,
SPHttpClient.configurations.v1,
{
  headers: {
    'Accept': 'application/json;odata=nometadata',
    'odata-version': ''
  }
})
.then((response: SPHttpClientResponse): Promise<{Title: string}> => {
  return response.json();
})
.then((web: {Title: string}): void => {
  // web.Title
}, (error: any): void => {
  // error
});

另请参阅