Word JS API:Range.compareLocationWith方法无法正常使用的问题排查与解决
Word JS API:Range.compareLocationWith方法无法正常使用的问题排查与解决
我最近在做Word插件开发时,需要判断用户是否点击切换了段落——思路是把之前选中的段落对应的Range对象暂存,等用户再次点击时,拿新的Range和旧的做对比。但在实现过程中,Range.compareLocationWith方法却没能正常工作,折腾了一番终于找到原因,在这里分享给大家。
初始实现思路与代码
我的核心思路是:
- 编写函数获取当前选中段落的Range对象,暂存起来作为后续对比的基准
- 编写对比函数,拿暂存的旧Range和新获取的Range做位置判断,确认是否为同一段落
获取选中段落Range的初始函数
export const getSelectedParagraphRange = async () => { return await Word.run(async (context) => { const range = context.document .getSelection() .paragraphs.getFirst() .getRange() return range }) }
对比Range的初始函数
export const isParagraphStillActive = async (range: Word.Range) => { return await Word.run(async (context) => { const newRange = context.document .getSelection() .paragraphs.getFirst() .getRange() const compare = range.compareLocationWith(newRange) await context.sync() return compare.value === 'Equal' }) }
遇到的异常问题
测试时我发现了奇怪的现象:
- 如果拿新获取的
newRange和自身对比,compare.value能正常返回Equal,完全符合预期 - 但如果把暂存的旧Range作为参数传入对比函数,哪怕是和自身对比,函数会直接“卡住”,既不返回结果也不抛出任何错误
问题根源分析
后来我才搞明白,Word JS API的上下文作用域是完全隔离的——每个Word.run都会创建一个独立的执行上下文,之前暂存的Range对象属于它自己的上下文,当在新的Word.run里直接使用这个跨上下文的Range对象时,就会出现无法正常交互的问题。而且我之前没有对Range对象做**跟踪(track)**处理,导致对象在上下文同步后,无法被后续的上下文识别和访问。
修复后的工作代码
我针对上下文和对象跟踪的问题,调整了两个函数,主要做了这几点修改:
- 在获取新Range时,先对之前暂存的旧Range调用
untrack()取消跟踪,避免内存泄漏 - 对新获取的Range调用
track(),让它能在后续的上下文里被正常访问 - 对比函数的
Word.run要传入旧Range对象,让它被纳入当前上下文的管理中
修改后的获取Range函数
export const getSelectedParagraphRange = async (formerRange?: Word.Range) => { return await Word.run(async (context) => { if (formerRange) { formerRange.untrack() await context.sync() } const range = context.document .getSelection() .paragraphs.getFirst() .getRange() range.track() await context.sync() return range }) }
修改后的对比函数
export const isParagraphStillActive = async (range: Word.Range) => { return await Word.run(range, async (context) => { const newRange = context.document .getSelection() .paragraphs.getFirst() .getRange() const compare = range.compareLocationWith(newRange) await context.sync() return compare.value === 'Equal' }) }
关键知识点总结
- 每个
Word.run对应独立的执行上下文,跨上下文的对象无法直接正常使用,需要通过track()和untrack()来管理对象的生命周期 - 当需要在后续的
Word.run中使用之前的Range对象时,必须先对它调用track(),并在不需要时调用untrack()释放资源 - 在对比跨上下文的Range时,要把旧Range作为参数传入
Word.run,让它被纳入当前上下文的管理中
备注:内容来源于stack exchange,提问作者probedroid
相关产品推荐
相关产品推荐

