如何用Office-JS与React创建Excel插件确认对话框?
解决React Excel插件中无法使用window.confirm的替代方案
嘿,我之前开发React版Excel插件时也踩过这个坑——Office-JS确实禁用了原生的弹窗API,而自带的Dialog API又不是真正的模态框,没法强制用户先处理再继续操作。给你分享几个亲测有效的解决方案:
1. 自定义React模态组件(最灵活)
直接在你的任务窗格里写一个React模态框组件,完全可控,样式和逻辑都能自己定制,而且是真正的模态(阻止任务窗格其他区域交互)。
示例代码:
import { useState } from 'react'; // 自定义确认模态框组件 const ConfirmModal = ({ isOpen, message, onConfirm, onCancel }) => { if (!isOpen) return null; return ( <div style={{ position: 'fixed', top: 0, left: 0, width: '100%', height: '100%', backgroundColor: 'rgba(0,0,0,0.5)', display: 'flex', justifyContent: 'center', alignItems: 'center', zIndex: 1000 }}> <div style={{ backgroundColor: 'white', padding: '2rem', borderRadius: '8px', boxShadow: '0 2px 10px rgba(0,0,0,0.2)' }}> <p>{message}</p> <div style={{ marginTop: '1rem', display: 'flex', gap: '1rem', justifyContent: 'flex-end' }}> <button onClick={onCancel} style={{ padding: '0.5rem 1rem', border: '1px solid #ccc', borderRadius: '4px' }}> Cancel </button> <button onClick={onConfirm} style={{ padding: '0.5rem 1rem', backgroundColor: '#0078d4', color: 'white', border: 'none', borderRadius: '4px' }}> Confirm </button> </div> </div> </div> ); }; // 在父组件中使用 const YourComponent = () => { const [showConfirm, setShowConfirm] = useState(false); const handleDeleteClick = () => { setShowConfirm(true); }; const handleConfirm = () => { // 执行删除逻辑 this.handleClick(); // 替换成你的实际操作 setShowConfirm(false); }; const handleCancel = () => { setShowConfirm(false); }; return ( <div> <button onClick={handleDeleteClick}>Delete Item</button> <ConfirmModal isOpen={showConfirm} message="Are you sure you wish to delete this item?" onConfirm={handleConfirm} onCancel={handleCancel} /> </div> ); };
这种方案的好处是完全自定义,和你的React项目无缝集成,不用依赖外部库。
2. 使用Office UI Fabric React的Dialog组件(贴合Office风格)
Office官方推荐的UI库Office UI Fabric React提供了原生的Dialog组件,它支持模态模式,而且样式和Office套件保持一致,用户体验更好。
示例代码:
import { useState } from 'react'; import { Dialog, DialogType, DialogFooter, PrimaryButton, DefaultButton } from '@fluentui/react'; const YourComponent = () => { const [showDialog, setShowDialog] = useState(false); const handleDeleteClick = () => { setShowDialog(true); }; const handleConfirm = () => { // 执行删除逻辑 this.handleClick(); setShowDialog(false); }; const handleCancel = () => { setShowDialog(false); }; return ( <div> <button onClick={handleDeleteClick}>Delete Item</button> <Dialog hidden={!showDialog} onDismiss={handleCancel} dialogContentProps={{ type: DialogType.normal, title: "Confirm Delete", subText: "Are you sure you wish to delete this item?" }} modalProps={{ isBlocking: true, // 这会让对话框成为模态,阻止任务窗格其他操作 styles: { main: { maxWidth: 450 } } }} > <DialogFooter> <DefaultButton onClick={handleCancel} text="Cancel" /> <PrimaryButton onClick={handleConfirm} text="Confirm" /> </DialogFooter> </Dialog> </div> ); };
记得先安装依赖:npm install @fluentui/react
这个方案的优势是UI风格和Office统一,不用自己写样式,而且组件的 accessibility(可访问性)已经处理好了。
3. 用Office-JS Dialog API模拟模态效果(适合跨窗格场景)
如果你的需求是必须跳出任务窗格显示确认框,可以用Dialog API结合Promise来模拟模态逻辑——虽然对话框本身是非模态,但可以通过异步等待让代码逻辑“阻塞”,直到用户做出选择。
示例代码:
const showConfirmDialog = async (message) => { return new Promise((resolve) => { // 创建对话框,加载一个简单的确认页面(可以是你插件内的HTML文件) Office.context.ui.displayDialogAsync( `${window.location.origin}/confirm-dialog.html?message=${encodeURIComponent(message)}`, { height: 200, width: 300 }, (asyncResult) => { const dialog = asyncResult.value; // 监听对话框发送的消息 dialog.addEventHandler(Office.EventType.DialogMessageReceived, (args) => { const result = JSON.parse(args.message); resolve(result.confirmed); dialog.close(); }); // 监听对话框关闭事件 dialog.addEventHandler(Office.EventType.DialogEventReceived, () => { resolve(false); // 用户关闭对话框默认视为取消 }); } ); }); }; // 在组件中使用 const YourComponent = () => { const handleDeleteClick = async () => { const confirmed = await showConfirmDialog('Are you sure you wish to delete this item?'); if (confirmed) { this.handleClick(); // 执行删除逻辑 } }; return ( <div> <button onClick={handleDeleteClick}>Delete Item</button> </div> ); };
然后需要创建一个confirm-dialog.html页面,里面包含确认和取消按钮,点击时向主窗格发送消息:
<!DOCTYPE html> <html> <body> <p id="message"></p> <button onclick="sendResult(true)">Confirm</button> <button onclick="sendResult(false)">Cancel</button> <script> // 获取URL中的消息 const urlParams = new URLSearchParams(window.location.search); document.getElementById('message').textContent = urlParams.get('message'); function sendResult(confirmed) { Office.context.ui.messageParent(JSON.stringify({ confirmed })); } </script> <script src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"></script> </body> </html>
这个方案适合需要脱离任务窗格的场景,但需要额外维护一个HTML页面,逻辑相对复杂一些。
内容的提问来源于stack exchange,提问作者blandine
相关产品推荐
相关产品推荐

