如何在Anki与AnkiDroid中通过JS从collection.media导入非媒体JSON文件?
问题:Anki桌面版与AnkiDroid兼容的非媒体文件加载方案
我需要从collection.media目录导入非音频、图片或视频类的文件(例如JSON文件)。目前已将_script.jquery-3.3.1.min.js和_data.json放入该目录:
在Ubuntu系统的Anki桌面版(2.0.47版本,搭配JS Booster插件)中,以下代码可正常运行:
<script src="_script.jquery-3.3.1.min.js"></script> <script> $.getJSON('_data.json', function(data) { // 在Anki桌面版成功执行,在AnkiDroid中失败 }); </script>
但在AnkiDroid中,JQuery能通过script标签正常加载,$.getJSON却找不到_data.json文件。我需要在大量卡片/笔记中使用该JSON文件,请问如何通过JavaScript实现同时兼容Anki桌面版与AnkiDroid的非媒体、非JS文件导入方案?
兼容解决方案
针对你遇到的跨平台加载问题,我整理了三个可靠的方案,你可以根据自己的需求选择:
方案1:将JSON内容嵌入模板隐藏元素(最推荐)
这是最稳定的跨平台方案,完全避开文件路径差异问题:
- 在卡片模板里添加一个隐藏的容器,直接把JSON内容写进去(如果JSON内容很大,可以把它存在Anki的字段里,然后用
{{字段名}}引用):<div id="json-data-container" style="display: none;"> {"menu": {"id": "file", "value": "File", "popup": {"menuitem": [{"value": "New", "onclick": "CreateNewDoc()"}, {"value": "Open", "onclick": "OpenDoc()"}]}}} </div> - 然后在JS中直接读取并解析:
$(document).ready(function() { // 获取隐藏容器的文本内容并解析成JSON const jsonData = JSON.parse($('#json-data-container').text().trim()); // 这里就可以正常使用数据了 console.log(jsonData.menu.popup.menuitem); }); - 优点:完全兼容所有Anki平台,没有路径问题;加载速度快,不需要额外请求;修改数据可以直接编辑字段或模板。
- 缺点:如果JSON内容非常大,模板会显得冗长,但用Anki字段存储的话可以规避这个问题。
方案2:用iframe中转加载JSON
利用AnkiDroid允许iframe加载HTML文件的特性,作为JSON加载的中转:
- 先在
collection.media目录创建一个json-loader.html文件,内容如下:<script> // 在iframe里加载JSON,然后把数据传给父页面 fetch('_data.json') .then(res => res.json()) .then(data => { window.parent.postMessage(data, '*'); }) .catch(err => console.error('加载JSON失败:', err)); </script> - 然后在卡片模板中添加iframe并监听消息:
<script src="_script.jquery-3.3.1.min.js"></script> <!-- 隐藏的iframe用来加载JSON --> <iframe src="json-loader.html" style="display: none;" id="json-loader"></iframe> <script> $(document).ready(function() { // 监听来自iframe的消息 window.addEventListener('message', function(event) { const jsonData = event.data; // 在这里处理你的数据 console.log(jsonData); }); }); </script>
- 原理:AnkiDroid对直接加载JSON文件有路径限制,但允许加载同目录的HTML文件,HTML文件可以正常读取JSON,再通过
postMessage把数据传递给卡片页面。
方案3:把JSON转成JS全局变量加载
把JSON改成JS文件,用script标签直接加载,和jQuery的加载逻辑完全一致:
- 将
_data.json重命名为_data.js,内容修改为把JSON赋值给一个全局变量:// 定义全局变量存储JSON数据 window.ankiJsonData = {"key1": "value1", "key2": ["item1", "item2"]}; - 在卡片模板中先加载这个JS文件,再直接使用变量:
<script src="_script.jquery-3.3.1.min.js"></script> <script src="_data.js"></script> <script> $(document).ready(function() { // 直接使用全局变量里的数据 console.log(window.ankiJsonData.key2); }); </script>
- 优点:兼容性极强,和加载JS文件的逻辑完全一样;修改数据只需要更新
_data.js,不需要改动模板。 - 缺点:数据会变成全局变量,要注意避免命名冲突;如果数据有敏感性,需要注意本地文件的安全性(不过Anki媒体文件本身是本地存储的,风险可控)。
内容的提问来源于stack exchange,提问作者well




