React开发SPO客户端WebPart调用OfficeJs报‘Office未定义’求助
一、核心问题分析
- Office.js加载时机错误:在React组件
render方法中插入<script>标签,无法保证脚本在componentDidMount或按钮点击前加载完成,导致Office对象未定义。 - 宿主环境误解:Outlook Add-In运行在Outlook宿主中,拥有
Office.context.mailbox上下文,但SharePoint WebPart的宿主是SharePoint/浏览器,原生不支持mailbox相关API,这是后续调用失败的根本原因。 - 类型配置冗余:
tsconfig.json中同时引入office-js和@types/office-js类型,可能导致冲突。
二、修复“Office is not defined”错误
1. 全局加载Office.js
修改WebPart的onInit方法,在WebPart初始化阶段动态加载Office.js,确保脚本在组件渲染前完成加载:
import * as React from 'react'; import * as ReactDom from 'react-dom'; import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base'; import ReplyEmailComponent from './components/ReplyEmailComponent'; export default class ReplyEmailWebPart extends BaseClientSideWebPart<unknown> { private officeLoaded: Promise<void>; protected onInit(): Promise<void> { this.officeLoaded = new Promise((resolve) => { // 检查Office是否已全局加载 if (window.Office) { Office.initialize = () => resolve(); return; } // 动态创建script标签加载Office.js const script = document.createElement('script'); script.src = 'https://appsforoffice.microsoft.com/lib/1.1/hosted/office.js'; script.onload = () => { Office.initialize = () => { console.log('Office.js初始化完成'); resolve(); }; }; script.onerror = () => { console.error('Office.js加载失败'); resolve(); }; document.head.appendChild(script); }); return Promise.all([super.onInit(), this.officeLoaded]); } public render(): void { const element: React.ReactElement<unknown> = React.createElement( ReplyEmailComponent, { officeLoaded: this.officeLoaded } ); ReactDom.render(element, this.domElement); } protected onDispose(): void { ReactDom.unmountComponentAtNode(this.domElement); } }
2. 调整React组件逻辑
移除组件内的script标签,等待Office.js加载完成后再启用按钮,并替换Outlook专属API为SharePoint环境可用的方案:
import * as React from 'react'; /* global Office */ interface IReplyEmailComponentProps { officeLoaded: Promise<void>; } export default class ReplyEmailComponent extends React.Component<IReplyEmailComponentProps, { isOfficeReady: boolean }> { constructor(props: IReplyEmailComponentProps) { super(props); this.state = { isOfficeReady: false }; } public async componentDidMount(): Promise<void> { try { await this.props.officeLoaded; this.setState({ isOfficeReady: true }); } catch (err) { console.error('Office.js未加载成功', err); } } private handleClick = (): void => { // SharePoint环境下无法使用Outlook Add-In的mailbox API,改用mailto协议唤起本地Outlook window.location.href = 'mailto:recipient@example.com?subject=Test email&body=Hello, world!'; }; public render(): React.ReactElement<IReplyEmailComponentProps> { return ( <section> <div> <button onClick={this.handleClick} disabled={!this.state.isOfficeReady} > {this.state.isOfficeReady ? '发送邮件' : '加载中...'} </button> </div> </section> ); } }
3. 清理类型配置
修改tsconfig.json,移除冗余的类型引用,避免冲突:
{ "extends": "./node_modules/@microsoft/rush-stack-compiler-4.5/includes/tsconfig-web.json", "compilerOptions": { "target": "es5", "forceConsistentCasingInFileNames": true, "module": "esnext", "moduleResolution": "node", "esModuleInterop": true, "jsx": "react", "declaration": true, "sourceMap": true, "experimentalDecorators": true, "skipLibCheck": true, "outDir": "lib", "inlineSources": false, "strictNullChecks": false, "noUnusedLocals": false, "noImplicitAny": true, "typeRoots": [ "./node_modules/@types", "./node_modules/@microsoft" ], "types": [ "webpack-env", "@types/office-js" ], "lib": [ "es5", "dom", "es2015.collection", "es2015.promise" ] }, "include": [ "src/**/*.ts", "src/**/*.tsx" ] }
4. 清理冗余依赖(可选)
若不需要本地Office.js包,可执行以下命令移除:
npm uninstall @microsoft/office-js
三、关键说明
Office.context.mailbox.displayNewMessageForm是Outlook Add-In专属API,仅能在Outlook宿主环境中运行。在SharePoint WebPart中,唤起本地Outlook新建邮件最可靠的方式是使用mailto:协议链接;若需要更复杂的邮件操作(如添加附件、HTML格式),可考虑使用Microsoft Graph API(需用户授权)。
内容的提问来源于stack exchange,提问作者EduardoCMB
相关产品推荐
相关产品推荐

