赞
踩
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呢?
- [
- ["text", "<div><ol>"],
- ["#", "students", [
- ["text", "<li>学生"],
- ["name", "name"],
- ["text", "的爱好是<ul>"],
- ["#", "hobbies", [
- ["text", "<li>"],
- ["name", "·"],
- ["text", "</li>"],
- ]],
- ["text", "</ul></li>"],
- ]],
- ["text", "</ol></div>"]
- ]
首先模板字符串, 编译成tokens。 然后tokens 结合数据渲染成DOM 结构。
当模板中存在循环的时候, 可以将它编译成嵌套更深的的tokens。 循环遍历。 算法的提出可以解决非常复杂的事情的。
第一: 就是将模板字符串变成tokens. 双重数组
第二: 然后 tokens 结合数据, 解析为DOM 字符串。
观察 tokens 数据
- if (openSection)
- throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos);
-
- return nestTokens(squashTokens(tokens));
- ------------------------------------------------------------------------
- 改为
- var tokens = nestTokens(squashTokens(tokens));
- console.log(tokens);
- return tokens;
- function compileTags (tagsToCompile) {
- if (typeof tagsToCompile === 'string')
- tagsToCompile = tagsToCompile.split(spaceRe, 2);
-
- if (!isArray(tagsToCompile) || tagsToCompile.length !== 2)
- throw new Error('Invalid tags: ' + tagsToCompile);
-
- openingTagRe = new RegExp(escapeRegExp(tagsToCompile[0]) + '\\s*');
- closingTagRe = new RegExp('\\s*' + escapeRegExp(tagsToCompile[1]));
- closingCurlyRe = new RegExp('\\s*' + escapeRegExp('}' + tagsToCompile[1]));
- }
-
- compileTags(tags || mustache.tags);
-
- var scanner = new Scanner(template);
-
- var start, type, value, chr, token, openSection;
- while (!scanner.eos()) {
- start = scanner.pos;
-
- // Match any text between tags.
- value = scanner.scanUntil(openingTagRe);
-
- if (value) {
- for (var i = 0, valueLength = value.length; i < valueLength; ++i) {
- chr = value.charAt(i);
-
- if (isWhitespace(chr)) {
- spaces.push(tokens.length);
- indentation += chr;
- } else {
- nonSpace = true;
- lineHasNonSpace = true;
- indentation += ' ';
- }
-
- tokens.push([ 'text', chr, start, start + 1 ]);
- start += 1;
-
- // Check for whitespace on the current line.
- if (chr === '\n') {
- stripSpace();
- indentation = '';
- tagIndex = 0;
- lineHasNonSpace = false;
- }
- }
- }
-
- // Match the opening tag.
- if (!scanner.scan(openingTagRe))
- break;
-
- hasTag = true;
-
- // Get the tag type.
- type = scanner.scan(tagRe) || 'name';
- scanner.scan(whiteRe);
-
- // Get the tag value.
- if (type === '=') {
- value = scanner.scanUntil(equalsRe);
- scanner.scan(equalsRe);
- scanner.scanUntil(closingTagRe);
- } else if (type === '{') {
- value = scanner.scanUntil(closingCurlyRe);
- scanner.scan(curlyRe);
- scanner.scanUntil(closingTagRe);
- type = '&';
- } else {
- value = scanner.scanUntil(closingTagRe);
- }
-
- // Match the closing tag.
- if (!scanner.scan(closingTagRe))
- throw new Error('Unclosed tag at ' + scanner.pos);
-
- if (type == '>') {
- token = [ type, value, start, scanner.pos, indentation, tagIndex, lineHasNonSpace ];
- } else {
- token = [ type, value, start, scanner.pos ];
- }
- tagIndex++;
- tokens.push(token);
-
- if (type === '#' || type === '^') {
- sections.push(token);
- } else if (type === '/') {
- // Check section nesting.
- openSection = sections.pop();
-
- if (!openSection)
- throw new Error('Unopened section "' + value + '" at ' + start);
-
- if (openSection[1] !== value)
- throw new Error('Unclosed section "' + openSection[1] + '" at ' + start);
- } else if (type === 'name' || type === '{' || type === '&') {
- nonSpace = true;
- } else if (type === '=') {
- // Set the tags for the next time around.
- compileTags(value);
- }
- }
-
- stripSpace();
-
- // Make sure there are no open sections when we're done.
- openSection = sections.pop();
-
- if (openSection)
- throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos);
-
- return nestTokens(squashTokens(tokens));
- }
使用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类,专门用来扫描传递进来的字符串,该类中提供两个方法scan、scanUtil。
Scanner 提供了两个方法就是 scan, scanUtil 两个方法;
ScanUtil() 方法功能: 让指针进行扫描, 知道遇见指定的内容, 并且能够返回结束之前的路过的文字。
Scan() 方法功能: 功能弱, 就是走过指定的内容, 没有返回值。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。