当前位置:   article > 正文

mustache 库机理_mustache.js是双插槽鼻祖吗

mustache.js是双插槽鼻祖吗

1: mustache 库机理:

2: mustache  库并不是一个简单的正则表达式的实现的机理。  模板字符串首先编译tokens 状态,  tokens 这种过渡状态, 和数据结合然后解析成dom 字符串。

tokens的编译 : tokens 是一个js 的嵌套数组,, 最为最要就是tokens. tokens 还是抽象语法树, 虚拟DOM 等当前前端很火热技术的开山鼻祖。  tokens 其实是 js 的嵌套数组。 能够把我们写好的模板字符串转化为特殊的数组。 然后在这个数组的基础上结合数据对象, 最后渲染成dom 字符串。 先有mustache  再有vue,  开山鼻祖。

tokens: 就是二维数组的嵌套形式,  二维数组中的每一项都是一个token。 所以组成一个 tokens;  tokens 是前端技术的开山鼻祖。 是抽象语法树(AST) 虚拟DOM 鼻祖。

 tokens: 是一个js 嵌套数组, 能够把我们写好的模板字符串转化为一个特殊的数组, 然后在这个数组的基础上结合对象, 然后渲染成dom 对象。

3:  tokens:   就是二维数组的嵌套的形式。 对于上边的模板字符串, mustache  会先将模板字符串转化为tokens 值。

那么mustache是如何把模板字符串编译成tokens呢?

  1. [
  2. ["text", "<div><ol>"],
  3. ["#", "students", [
  4. ["text", "<li>学生"],
  5. ["name", "name"],
  6. ["text", "的爱好是<ul>"],
  7. ["#", "hobbies", [
  8. ["text", "<li>"],
  9. ["name", "·"],
  10. ["text", "</li>"],
  11. ]],
  12. ["text", "</ul></li>"],
  13. ]],
  14. ["text", "</ol></div>"]
  15. ]

   首先模板字符串, 编译成tokens。  然后tokens 结合数据渲染成DOM 结构。

   当模板中存在循环的时候, 可以将它编译成嵌套更深的的tokens。  循环遍历。 算法的提出可以解决非常复杂的事情的。

第一: 就是将模板字符串变成tokens.  双重数组

第二: 然后 tokens 结合数据, 解析为DOM 字符串。

观察 tokens 数据

  1. if (openSection)
  2. throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos);
  3. return nestTokens(squashTokens(tokens));
  4. ------------------------------------------------------------------------
  5. 改为
  6. var tokens = nestTokens(squashTokens(tokens));
  7. console.log(tokens);
  8. return tokens;
  1. function compileTags (tagsToCompile) {
  2. if (typeof tagsToCompile === 'string')
  3. tagsToCompile = tagsToCompile.split(spaceRe, 2);
  4. if (!isArray(tagsToCompile) || tagsToCompile.length !== 2)
  5. throw new Error('Invalid tags: ' + tagsToCompile);
  6. openingTagRe = new RegExp(escapeRegExp(tagsToCompile[0]) + '\\s*');
  7. closingTagRe = new RegExp('\\s*' + escapeRegExp(tagsToCompile[1]));
  8. closingCurlyRe = new RegExp('\\s*' + escapeRegExp('}' + tagsToCompile[1]));
  9. }
  10. compileTags(tags || mustache.tags);
  11. var scanner = new Scanner(template);
  12. var start, type, value, chr, token, openSection;
  13. while (!scanner.eos()) {
  14. start = scanner.pos;
  15. // Match any text between tags.
  16. value = scanner.scanUntil(openingTagRe);
  17. if (value) {
  18. for (var i = 0, valueLength = value.length; i < valueLength; ++i) {
  19. chr = value.charAt(i);
  20. if (isWhitespace(chr)) {
  21. spaces.push(tokens.length);
  22. indentation += chr;
  23. } else {
  24. nonSpace = true;
  25. lineHasNonSpace = true;
  26. indentation += ' ';
  27. }
  28. tokens.push([ 'text', chr, start, start + 1 ]);
  29. start += 1;
  30. // Check for whitespace on the current line.
  31. if (chr === '\n') {
  32. stripSpace();
  33. indentation = '';
  34. tagIndex = 0;
  35. lineHasNonSpace = false;
  36. }
  37. }
  38. }
  39. // Match the opening tag.
  40. if (!scanner.scan(openingTagRe))
  41. break;
  42. hasTag = true;
  43. // Get the tag type.
  44. type = scanner.scan(tagRe) || 'name';
  45. scanner.scan(whiteRe);
  46. // Get the tag value.
  47. if (type === '=') {
  48. value = scanner.scanUntil(equalsRe);
  49. scanner.scan(equalsRe);
  50. scanner.scanUntil(closingTagRe);
  51. } else if (type === '{') {
  52. value = scanner.scanUntil(closingCurlyRe);
  53. scanner.scan(curlyRe);
  54. scanner.scanUntil(closingTagRe);
  55. type = '&';
  56. } else {
  57. value = scanner.scanUntil(closingTagRe);
  58. }
  59. // Match the closing tag.
  60. if (!scanner.scan(closingTagRe))
  61. throw new Error('Unclosed tag at ' + scanner.pos);
  62. if (type == '>') {
  63. token = [ type, value, start, scanner.pos, indentation, tagIndex, lineHasNonSpace ];
  64. } else {
  65. token = [ type, value, start, scanner.pos ];
  66. }
  67. tagIndex++;
  68. tokens.push(token);
  69. if (type === '#' || type === '^') {
  70. sections.push(token);
  71. } else if (type === '/') {
  72. // Check section nesting.
  73. openSection = sections.pop();
  74. if (!openSection)
  75. throw new Error('Unopened section "' + value + '" at ' + start);
  76. if (openSection[1] !== value)
  77. throw new Error('Unclosed section "' + openSection[1] + '" at ' + start);
  78. } else if (type === 'name' || type === '{' || type === '&') {
  79. nonSpace = true;
  80. } else if (type === '=') {
  81. // Set the tags for the next time around.
  82. compileTags(value);
  83. }
  84. }
  85. stripSpace();
  86. // Make sure there are no open sections when we're done.
  87. openSection = sections.pop();
  88. if (openSection)
  89. throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos);
  90. return nestTokens(squashTokens(tokens));
  91. }

使用webpack 和 webapack-dev-server 构建

webpack 模块化构建工具, 把每一个js 文件相互引入使用。

npm run dev 命令的时候

会自动查找:  package.json 文件中  scripts 脚本。  webpack-dev-serve  命令会自动查找

webpack-config.js 文件

1:  模块打包工具具有webpack(webpack-dev-server) . rollup,  等。

 mustache 官方使用的是rollup 进行模块化打包, 而我们使用webpack (webpack-dev-server)  进行模块化打包, 这是因为webpack (webpack-dev-server):能够让我们更加方便的在浏览器中实时调试程序。 

 相比较node.js 控制台, 浏览器控制台更加好用, 比如可以展开数组的每一项。

 创建一个文件夹, 文件夹初始化操作,  npm init 初始化操作。(创建唯一的id)

npm i -D  (-D: 表示开发依赖)  webpack@4:; 表示webpack 的版本号。

 热更新就是自动更新,

在mustache官方源码里有一个Scanner类,专门用来扫描传递进来的字符串,该类中提供两个方法scanscanUtil

Scanner 提供了两个方法就是 scan,  scanUtil 两个方法;

ScanUtil() 方法功能: 让指针进行扫描, 知道遇见指定的内容, 并且能够返回结束之前的路过的文字。

Scan()  方法功能: 功能弱, 就是走过指定的内容, 没有返回值。

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
  

闽ICP备14008679号