模板

前不久写了一篇文章《KindleMate + Anki —— 你不知道的记单词利器》分享用KindleMate和Anki背单词的技巧,随着时间推移,我也在不断完善Anki背单词的模板,主要更新有:

  1. 添加了大量正则表达式处理释义的格式,以达到样式的美观
  2. 修复了翻页时页面闪烁的bug,这个bug困扰了我好几天,最后无意中发现是因为在Anki上用正则表达式替换[符号就会导致页面闪烁
  3. 如果单词和原型相同,则只显示单词
  4. 如未添加音频,音频播放图标则显示为这只小熊 ʕ•́ᴥ•̀ʔっ♡
  5. 修改了音标的显示样式,使其更和谐低调
  6. 优化了答案显示时的动画特效,使其更流畅舒适
  7. 制作了3种模板
    1. 第一种是传统的单卡片模板,先出现单词,后出现释义
    2. 第二种也是单卡片模板,先出现释义,后出现单词
    3. 第三种是双卡片模板,即上面2种单卡片模板的组合

双卡片模板效果如下:
image.png
三种模板均已分享,下载后双击即可安装,请根据需要自行选择

下载链接:https://pan.baidu.com/s/1y0ROMH2_CExjm6LeMeUv0w 提取码:nsjj
image.png

代码

如果你已经安装了模板,想要修改代码,可以点击“工具” -> “管理笔记类型
image.png
image.png
如果要修改代码,选中模板后,点击 “卡片”,即可看到“正面模板”“背面模板”“样式”三部分的代码。
双卡片模板有卡片1和卡片2,点击上方的“卡片类型”可以切换以修改代码。
image.png
附上我的双卡片模板源代码如下:
单卡片模板(单词-释义)和双卡片模板的卡片一是一样的
单卡片模板(释义-单词)和双卡片模板的卡片二是一样的

注意:Anki电脑版不支持ES6语法,比如用let/const声明变量会出现意想不到的bug

卡片一

image.png

正面模板

  1. <!-- 正面区块 -->
  2. <div class="section top">
  3. <div id="front" class="items">
  4. <span id="word" class="block">{{单词}}</span>
  5. <span class="audio block">{{发音}}</span>
  6. <span id="prototype" class="block">{{原型}}</span>
  7. </div>
  8. <div id="instance" class="items" >{{用法}}</div>
  9. </div>
  10. <script>
  11. var word = document.querySelector("#word").innerText.trim()
  12. var prototype = document.querySelector("#prototype")
  13. if (word.toLowerCase() === prototype.innerText.toLowerCase()){
  14. prototype.style.display = "none"
  15. }
  16. var instance = document.querySelector("#instance")
  17. if (instance.innerHTML.trim() == '') {
  18. instance.classList.add("hide")
  19. } else {
  20. if (instance.innerHTML.indexOf(`<b><u>${word}</u></b>`) == -1){
  21. instance.innerHTML = instance.innerHTML.replace(new RegExp(word,"g"), `<b><u>${word}</u></b>`)
  22. }
  23. }
  24. var audio = document.querySelector(".audio")
  25. if (audio.innerHTML === '') {
  26. audio.innerHTML = 'ʕ•́ᴥ•̀ʔっ♡'
  27. audio.style.opacity = 1
  28. }
  29. </script>

背面模板

  1. <!-- 背面区块 -->
  2. {{FrontSide}}
  3. <div class="section bounceInUp">
  4. <div id="paraphrase" class="items2">{{释义}}</div>
  5. </div>
  6. <script type="text/javascript">
  7. var colorMap = {
  8. 'n.':'#86c440',
  9. 'a.':'#f8b002',
  10. 'adj.':'#727272',
  11. 'ad.':'#684b9d',
  12. 'adv.':'#684b9d',
  13. 'v.':'#479cdf',
  14. 'vi.':'#3e480d',
  15. 'vt.':'#3e480d',
  16. 'prep.':'#04B7C9',
  17. 'conj.':'#04B7C9',
  18. 'pron.':'#04B7C9',
  19. 'art.':'#04B7C9',
  20. 'num.':'#04B7C9',
  21. 'int.':'#04B7C9',
  22. 'interj.':'#04B7C9',
  23. 'modal.':'#04B7C9',
  24. 'aux.':'#04B7C9',
  25. 'pl.':'#D111D3',
  26. 'abbr.':'#D111D3',
  27. };
  28. [].forEach.call(document.querySelectorAll('#paraphrase'), function(div) {
  29. div.innerHTML = div.innerHTML.replace(/\b[a-z]+\./g, function(symbol) {
  30. if(colorMap[symbol]) {
  31. return '<br/><a style="background-color:' + colorMap[symbol] + ';border-radius: 4px; color:white; padding:0 3px;margin-right:5px">'+
  32. symbol + '</a>';
  33. } else {
  34. return symbol;
  35. }
  36. }).replace(/\],/g, ']&nbsp&nbsp')
  37. .replace(/(<br\/?>)+/g, '<br/>')
  38. .replace(/[美英]((?!<a\s).)*\]/g, function(symbol){
  39. symbol = symbol.replace('美', 'us').replace('英','uk').replace(/\]/g, '/').replace(new RegExp('\\[', 'g'), '/');
  40. return `<span class="soundmark">${symbol}</span>`
  41. });
  42. if(div.innerHTML.indexOf('<br') === 0) {
  43. var i = div.innerHTML.indexOf('>')
  44. div.innerHTML = div.innerHTML.slice(i+1)
  45. }
  46. });
  47. </script>

样式

  1. * {
  2. box-sizing: border-box;
  3. margin: 0;
  4. padding: 0;
  5. }
  6. body,
  7. html {
  8. background: #eaebee;
  9. font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","WenQuanYi Micro Hei",sans-serif;
  10. line-height: 1.5;
  11. font-size: 16px;
  12. }
  13. /*区块全局样式*/
  14. .section {
  15. border-radius: 13px;
  16. background-color: #fff;
  17. margin: 10px 2px;
  18. box-shadow: 0 0 2px rgba(0,0,0,0.3);
  19. }
  20. .top{
  21. margin-top: 12px;
  22. }
  23. /*区块项全局样式*/
  24. .items{
  25. border-top : 1.5px solid rgba(0,0,0, 0.1);
  26. }
  27. .items, .items2{
  28. margin: 0 14px;
  29. padding: 10px 0 8px 0;
  30. }
  31. /*正面字段样式*/
  32. #front{
  33. border-top: 0px;
  34. font-size: 24px;
  35. font-family: courier;
  36. line-height: 1;
  37. font-weight: bolder;
  38. color: #000;
  39. display: flex;
  40. justify-content: center;
  41. align-items: center;
  42. }
  43. .block {
  44. display: inline-block;
  45. }
  46. .audio {
  47. transform: scale(0.5) translateY(3px);
  48. opacity: 0.1;
  49. }
  50. .hide {
  51. display: none;
  52. }
  53. .soundmark {
  54. color: #999;
  55. font-size: 14px;
  56. }
  57. /*书籍字段样式控制*/
  58. .book{
  59. font-size:12px;
  60. font-style:italic;
  61. text-align:right;
  62. padding-top:6px;
  63. }
  64. .book:before{content:" —— ";}
  65. #prototype{
  66. font-size : 18px;
  67. text-align : left;
  68. }
  69. /* 单词在例句中样式 */
  70. #instance u {
  71. color: #2cbca1;
  72. text-decoration: none;
  73. }
  74. /* 答案显示时动画 */
  75. @keyframes bounceInUp {
  76. from {
  77. opacity: 0;
  78. transform: translate3d(0, 100px, 0);
  79. }
  80. to {
  81. opacity: 1;
  82. transform: translate3d(0, 0, 0);
  83. }
  84. }
  85. .bounceInUp {
  86. animation: bounceInUp 0.3s cubic-bezier(.39,-0.35,.23,1.51);
  87. }

卡片二

image.png

正面模板

  1. <div class="section top">
  2. <div id="paraphrase" class="items2">{{释义}}</div>
  3. </div>
  4. <script type="text/javascript">
  5. var colorMap = {
  6. 'n.':'#86c440',
  7. 'a.':'#f8b002',
  8. 'adj.':'#727272',
  9. 'ad.':'#684b9d',
  10. 'adv.':'#684b9d',
  11. 'v.':'#479cdf',
  12. 'vi.':'#3e480d',
  13. 'vt.':'#3e480d',
  14. 'prep.':'#04B7C9',
  15. 'conj.':'#04B7C9',
  16. 'pron.':'#04B7C9',
  17. 'art.':'#04B7C9',
  18. 'num.':'#04B7C9',
  19. 'int.':'#04B7C9',
  20. 'interj.':'#04B7C9',
  21. 'modal.':'#04B7C9',
  22. 'aux.':'#04B7C9',
  23. 'pl.':'#D111D3',
  24. 'abbr.':'#D111D3',
  25. };
  26. var div = document.getElementById('paraphrase')
  27. div.innerHTML = div.innerHTML.replace(/\b[a-z]+\./g, function(symbol) {
  28. if(colorMap[symbol]) {
  29. return '<br/><a style="background-color:' + colorMap[symbol] + ';border-radius: 4px; color:white; padding:0 3px;margin-right:5px">'+
  30. symbol + '</a>';
  31. }else{
  32. return symbol;
  33. }
  34. }).replace(/(<br\/?>)+/g, '<br/>').replace(/[美英]((?!<a\s).)*\][,\s]?(<br\/?>)?/g, "");
  35. if(div.innerHTML.indexOf('<br') === 0) {
  36. var i = div.innerHTML.indexOf('>')
  37. div.innerHTML = div.innerHTML.slice(i+1)
  38. }
  39. </script>

背面模板

  1. {{FrontSide}}
  2. <div class="section bounceInUp">
  3. <div id="front" class="items">
  4. <span id="word" class="block">{{单词}}</span>
  5. <span class="audio block">{{发音}}</span>
  6. <span id="prototype" class="block">{{原型}}</span>
  7. </div>
  8. <div id="instance" class="items" >{{用法}}</div>
  9. </div>
  10. <script>
  11. var word = document.querySelector("#word").innerText.trim()
  12. var prototype = document.querySelector("#prototype")
  13. if (word.toLowerCase() === prototype.innerText.toLowerCase()){
  14. prototype.style.display = "none"
  15. }
  16. var instance = document.querySelector("#instance")
  17. if (instance.innerHTML.trim() == '') {
  18. instance.classList.add("hide")
  19. } else {
  20. if (instance.innerHTML.indexOf(`<b><u>${word}</u></b>`) == -1){
  21. instance.innerHTML = instance.innerHTML.replace(new RegExp(word, "g"),`<b><u>${word}</u></b>`)
  22. }
  23. }
  24. var audio = document.querySelector(".audio")
  25. if (audio.innerHTML === '') {
  26. audio.innerHTML = 'ʕ•́ᴥ•̀ʔっ♡'
  27. audio.style.opacity = 1
  28. }
  29. </script>

样式

卡片二和卡片一的样式是共用的,不需要修改