Chrome扩展能否调用网站已加载的flatpickr模块?
问题:Chrome扩展操作flatpickr元素时出现TypeError错误
开发Chrome自动填充扩展时,调用flatpickr实例的setDate函数始终报错:TypeError: Cannot read properties of undefined。已确认网站已加载flatpickr模块,且相同代码在开发者工具控制台能正常运行。疑问:能否直接使用网站已加载的flatpickr?还是需要自行导入?
网站HTML代码
//... <div> <div class="form-group" data-triptype="oneway"> <span class="material-icons-outlined">today</span> <label for="">Date</label> <input date="2024/01/22" flimit="" isdpromotion="false" type="hidden" slimit="2024/02/19" isspromotion="false" plimit="2024/01/26" name="toTimeInputField" limit="2024/02/19" id="toTimeInputField" class="uk-input out-date flatpickr-input" value="2024/01/22" isfreeseat="false"><input class="uk-input" placeholder="" tabindex="0" type="text" readonly="readonly"> </div> // ... </div> //...
manifest.json代码
{ "manifest_version": 3, "name": "AutoFill", "version": "1.0", "description": "", "content_scripts": [ { "matches": ["https://*"], "js": ["query_page_script.js"] } ], "permissions": [ "storage" ], "action": { "default_popup": "popup/index.html" } }
query_page_script.js代码
const columns_name = [ 'toTimeInputField' ]; const data = { toTimeInputField: ['date', '2024/02/08'] }; columns_name.forEach(e => { const target = document.getElementsByName(e); if (target && data[e]) { if (data[e][0] === 'date') { target[0]._flatpickr.setDate(data[e][1], true, 'Y/d/m'); } else { target[0].value = data[e]; } }; console.log("End."); });
解决方案思路
1. 核心问题:上下文隔离
Chrome扩展的内容脚本和页面主脚本运行在不同的上下文,两者的window对象相互独立。页面中元素的_flatpickr属性属于页面上下文,内容脚本无法直接访问,这就是报错的根本原因——控制台是运行在页面上下文的,所以代码能正常执行。
2. 如何使用页面已加载的flatpickr?
不需要自行导入flatpickr,通过向页面注入脚本即可:
- 内容脚本可以创建
<script>标签,将操作代码注入到页面的上下文环境中执行,此时代码就能直接访问页面的flatpickr实例和元素的_flatpickr属性。
3. 修改后的代码示例
基础注入版(替换原query_page_script.js)
// 要注入到页面的业务代码 const injectCode = ` const columns_name = ['toTimeInputField']; const data = { toTimeInputField: ['date', '2024/02/08'] }; columns_name.forEach(e => { const target = document.getElementsByName(e); if (target && data[e]) { if (data[e][0] === 'date') { target[0]._flatpickr.setDate(data[e][1], true, 'Y/d/m'); } else { target[0].value = data[e]; } } console.log("End."); }); `; // 创建script标签注入页面 const script = document.createElement('script'); script.textContent = injectCode; document.head.appendChild(script); script.remove(); // 执行完毕后移除标签,避免污染DOM
适配动态加载场景版
如果页面是动态初始化flatpickr元素,需要等待元素和实例加载完成后再执行:
const injectCode = ` function setDateIfReady() { const target = document.getElementsByName('toTimeInputField')[0]; // 确认元素和flatpickr实例存在 if (target && target._flatpickr) { target._flatpickr.setDate('2024/02/08', true, 'Y/d/m'); console.log("日期设置完成"); return true; } return false; } // 先尝试一次,失败则轮询等待 if (!setDateIfReady()) { const checkInterval = setInterval(() => { if (setDateIfReady()) { clearInterval(checkInterval); } }, 500); } `; const script = document.createElement('script'); script.textContent = injectCode; document.head.appendChild(script); script.remove();
4. 为什么不需要自行导入flatpickr?
页面已经加载了flatpickr实例,注入的脚本运行在页面上下文,能直接复用现有实例和方法。重复导入会增加扩展体积,还可能引发版本冲突问题。
内容的提问来源于stack exchange,提问作者Rex Huang
相关产品推荐
相关产品推荐

