Vue源码:mustache模板引擎学习(1),web前端开发工程师

2.2.2 不循环

在这里插入图片描述

Document

2.2.3 循环简单数组

在这里插入图片描述

循环简单数组使用.标识每一项数据

Document

2.2.4 数组可以嵌套

在这里插入图片描述

Document

2.2.5 布尔值

在这里插入图片描述

可以通过#temp中temp的bool值来决定内部内容是否显示

Document

三、mustache的底层核心机理 — 底层机理

===================================================================================

3.1 mustache库不能用简单的正则表达式思路是先


  • 在较为简单的示例情况下,可以用正则表达式实现

模板字符串:在这里插入图片描述

数据:

在这里插入图片描述

模拟实现:

字符串的replace方法,可以第一个参数接收一个正则,第二个参数接收一个函数,有四个参数。

第一个参数代表正则匹配的部分,第二个参数代表()中捕获到的内容,第三个参数代表位置,第四个参数代表源字符串

Document
  • 但是在情况复杂时,正则表达式的思路肯定就不行了。比如这样的模板字符串,是不能用正则表达式的思路实现的

模板字符串:在这里插入图片描述

3.2 mustache库的机理


在这里插入图片描述

3.3 什么是tokens?


  • tokens是一个JS的嵌套数组,说白了,就是模板字符串的JS表示

  • 它是"抽象语法树"、"虚拟节点"等等的开山鼻祖

模板字符串:

在这里插入图片描述

tokens:在这里插入图片描述

tokens是将字符串转换成了JS的嵌套数组,如果是纯文本(包括HTML标签),会被标识为text

如果是带有双括号({{}})的参数,会被标识为name

3.4 非常有创造性的、轰动性的模板解析原理


在这里插入图片描述

3.5 循环情况下的tokens


  • 当模板字符串中有循环存在时,它将被编译为嵌套更深的tokens

在这里插入图片描述

3.6 双重循环情况下的tokens


  • 当循环是双重的,那么tokens会更深一层

在这里插入图片描述

3.7 mustache库的机理


在这里插入图片描述

mustache库底层重点要做两个事情:

  • 将模板字符串编译为tokens形式

  • 将tokens结合数据,解析为dom字符串

3.8 观察token


把256行这里在这里插入图片描述

改为在这里插入图片描述

四、手写实现mustache库 — 手写

===============================================================================

4.1 使用webpack和webpack-dev-server构建


  • 模块化打包工具有webpack(webpack-dev-server)、rollup、Parcel等

在这里插入图片描述

  • mustache官方库使用rollup进行模块化打包,而我们使用webpack(webpack-dev-server)进行模块化打包,这是因为webpack(webpack-dev-server)能更方便的在浏览器中(而不是nodeJS环境中)实时调试程序,相比nodeJS控制台,浏览器控制台更好用,比如能够点击展开数组的每一项

  • 生成库是UMD的,可以同时在nodeJS环境中使用,也可以在浏览器环境中使用。实现UMD不难,只需要一个**“通用头”**即可

4.2 注意webpack和webpack-dev-server的版本


webpack最新版是5,webpack-dev-server最新版是4,但是目前最新版兼容成都不好,建议使用如下版本:

“webpack”: “^4.44.2”,

“webpack-cli”: “^3.3.12”,

“webpack-dev-server”: “^3.11.0”

4.3 webpack.config.js文件


const path = require(‘path’);

module.exports = {

mode: ‘development’,

entry: ‘./index.js’,

output: {

filename: ‘bundle.js’

},

devServer: {

contentBase: path.join(__dirname, ‘www’),

compress: false,

port: 8080,

// 虚拟打包的路径,bundle.js文件没有真正的生成

publicPath: ‘/xuni/’

}

}

4.4 开发注意事项


  • 学习源码时,源码思想要借鉴,而不要抄袭。

要能够发现源码中书写精彩的地方。

  • 将独立的功能拆分为独立的js文件中完成,通常是一个独立的类,每个单独的功能必须能独立的"单元测试"

  • 应该围绕中心功能,先把主干完成,然后修剪枝叶

  • 功能并不需要一步到位,功能的拓展要一步步完成,有的非核心功能甚至不需要实现

4.5 将模板字符串变为tokens


在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4.6 生成tokens数组


在这里插入图片描述

4.7 将零散的tokens嵌套起来


4.7.1 栈是什么

在这里插入图片描述

4.8 将tokens结合数据,解析为dom字符串


在这里插入图片描述

粗浅的完成简单的目标:

在这里插入图片描述

不带有#标记

在这里插入图片描述

  • #标记的tokens,需要递归处理它的下标为2的小数组

  • 现在遇到一个问题,JS不认识点符号

在这里插入图片描述

五、源码

===============================================================

项目目录

在这里插入图片描述

index.html

Document

index.js

import parseTemplateToTokens from “./parseTemplateToTokens”;

import renderTemplate from “./renderTemplate”;

// 全局提供HK_TemplateEngine方法

window.HK_TemplateEngine = {

// 渲染方法

render(templateStr, data) {

// 调用parseTemplateToTokens方法,让模板字符串可以变成数组

let tokens = parseTemplateToTokens(templateStr);

// 调用renderTemplate函数,让tokens数组变为dom字符串

return renderTemplate(tokens, data);

}

}

lookup.js

/**

  • 功能是可以在dataObj对象中,寻找用连续点符号的keyName属性

  • 比如,dataObj是

  • {

  • a:{

  • b:{
    
  •   c:100
    
  • }
    
  • }

  • }

  • 那么lookup(dataObj, ‘a.b.c’)结果就是100

*/

export default function lookup(dataObj, keyName) {

// 看看keyName中有没有点符号

if (keyName.indexOf(‘.’) !== -1 && keyName !== ‘.’) {

// 如果有点符号,那么拆开

let keys = keyName.split(‘.’);

// 设置一个临时变量,这个临时变量用于周转,一层一层找下去

let temp = dataObj;

// 每找一层,就把它设置为新的临时变量

for (let i = 0; i < keys.length; i++)

temp = temp[keys[i]];

return temp;

}

// 如果没有点符号

return dataObj[keyName];

};

nextTokens.js

/**

  • 折叠tokens,将#和/之间的tokens能够整合起来,作为它的下标3

  • @param tokens

*/

export default function nextTokens(tokens) {

// 结果数组

let nestedTokens = [];

// 栈结构,存放小tokens,栈顶(靠近端口的,最新进入的)的数组中当前操作的这个tokens小数组

let sections = [];

// 收集器,天生指向nestedTokens结果数组,引用类型值,所以指向的是同一个数组

// 收集器的指向会变化,当遇到#的时候,收集器会指向这个item的下标为2的新数组

let collector = nestedTokens;

tokens.forEach(token => {

switch (token[0]) {

case ‘#’:

// 收集器中放入token

collector.push(token);

// 入栈

sections.push(token);

// 更换收集器。给item添加下标为2的项,并让收集器指向它

collector = token[2] = [];

break;

case ‘/’:

// 出栈 pop()方法返回出栈结果

sections.pop();

// 改变收集器为栈结构队尾(队尾是栈顶)那项下标为2的数组

collector = sections.length > 0 ? sections[sections.length - 1][2] : nestedTokens;

break;

default:

collector.push(token);

}

})

return nestedTokens;

};

parseArray.js

import lookup from “./loopup”;

import renderTemplate from “./renderTemplate”;

/**

  • 处理数组,结合renderTemplate实现递归

  • 注意:这个函数接收的参数是token,而不是tokens

  • token是什么,就是一个简单的[“#”, ‘students’, []]

  • 这个函数要递归调用renderTemplate函数

  • 调用次数由data决定

*/

export default function parseArray(token, data) {

// 得到整体数据data中这个数组要使用的部分

let v = lookup(data, token[1]);

// 结果字符串

let resultStr = ‘’;

// 遍历v数组

// 遍历v数组,v一定是数组

// 注意,下面这个循环可能是整个包中最难思考的一个循环

// 它是遍历数据,而不是遍历tokens。数组中的数据有几条,就要遍历几条。

for (let i = 0; i < v.length; i++) {

// 这里要补一个“.”属性

// 拼接

resultStr += renderTemplate(token[2], {

…v[i],

‘.’: v[i]

});

}

return resultStr;

}

parseTemplateToTokens.js

import Scanner from ‘./Scanner.js’;

import nextTokens from “./nextTokens”;

/*

将模板字符串变为tokens数组

*/

export default function parseTemplateToTokens(templateStr) {

let tokens = [];

// 创建扫描器

let scanner = new Scanner(templateStr);

let words;

// 让扫描器工作

while (!scanner.eos()) {

// 收集开始标记出现之前的文字

words = scanner.scanUtil(‘{{’);

if (words !== ‘’) {

// 尝试写一下去掉空格,智能判断是普通文字的空格,还是标签中的空格

// 标签中的空格不能去掉,比如

不能去掉class前面的空格

let isInJJH = false;

// 空白字符串

let _words = ‘’;

for (let i = 0; i < words.length; i++) {

// 判断是否在标签里

if (words[i] === ‘<’) {

isInJJH = true;

} else if (words[i] === ‘>’) {

isInJJH = false;

}

// 如果这项不是空格,拼接上

if (!/\s/.test(words[i])) {

_words += words[i];

} else {

// 如果这项是空格,只有当它在标签内的时候,才拼接上

if (isInJJH) {

_words += ’ ';

}

}

}

// 存起来,去掉空格

tokens.push([‘text’, _words]);

}

// 过双大括号

scanner.scan(‘{{’);

// 收集开始标记出现之前的文字

words = scanner.scanUtil(‘}}’);

if (words !== ‘’) {
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

文章到这里就结束了,如果觉得对你有帮助可以点个赞哦,如果有需要前端校招面试题PDF完整版的朋友可以点击这里即可免费获取,包括答案解析。

t _words = ‘’;

for (let i = 0; i < words.length; i++) {

// 判断是否在标签里

if (words[i] === ‘<’) {

isInJJH = true;

} else if (words[i] === ‘>’) {

isInJJH = false;

}

// 如果这项不是空格,拼接上

if (!/\s/.test(words[i])) {

_words += words[i];

} else {

// 如果这项是空格,只有当它在标签内的时候,才拼接上

if (isInJJH) {

_words += ’ ';

}

}

}

// 存起来,去掉空格

tokens.push([‘text’, _words]);

}

// 过双大括号

scanner.scan(‘{{’);

// 收集开始标记出现之前的文字

words = scanner.scanUtil(‘}}’);

if (words !== ‘’) {
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-ZkinaMbv-1712228508151)]

[外链图片转存中…(img-wz3LsNjq-1712228508151)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

[外链图片转存中…(img-rhHeSEkz-1712228508152)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

文章到这里就结束了,如果觉得对你有帮助可以点个赞哦,如果有需要前端校招面试题PDF完整版的朋友可以点击这里即可免费获取,包括答案解析。

[外链图片转存中…(img-kBSJ60PD-1712228508152)]

  • 12
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值