解决数据中对象“.”的链式调用
最终 数据结合结果 “我想painting,painting使我快乐!特殊[鼠绘]”
// lookUp.js 解决对象层级的"."的问题,通过临时存储
/**
* 功能是可以在dataObj对象中,寻找连续点符号的keyName属性
* 比如,dataObj是
* {
* a:{
* b:{
* c: 100
* }
* }
* }
* 那么lookup(dataObj,'a.b.c)
*/
export default function (keyName, dataObj) {
if (keyName.indexOf(".") != -1) {
let keys = keyName.split(".");
// 设置临时变量
let temp = dataObj;
let i = 0;
while (i < keys.length) {
// 每找一层都要重新存储
temp = temp[keys[i]];
i++;
}
return temp;
}
// 没有点
return dataObj[keyName]
}
// renderTp.js
// 字符串与数据互相转换
import LookUp from './lookUp'
/**
* 让tokens变为dom字符串
*/
export default function (tokens, data) {
// 结果字符串
let convertedStr = ''
tokens.forEach(i => {
// 看类型
if (i[0] === 'text') {
convertedStr += i[1]
} else if (i[0] === 'name') {
// 如果是 name 类型,则要使用lookup 防止 a.b.c有点符号号行是
convertedStr += LookUp(i[1], data)
}
})
return convertedStr
}
// 数据和字符串模板
const tmpStr = `我想{{doSth}},{{doSth}}使我快乐!特殊[{{m.b.c}}]`; // 特殊的数据
const data = {
doSth: "painting",
m: {
b: {
c: "鼠绘",
},
},
};
TpEngine.render(tmpStr, data);
// nextTokens.js 折叠token方法
/**
* 折叠tokens
* 栈底数组第一位,栈顶-数组尾
*/
export default function (tokens) {
// console.log(tokens)
// 结果数组
let nestedTokens = []
// 栈数字组,存放小token,栈顶(靠近端口的,最新进入的)tokens数组中当前操作的这个tokens小数组
let sections = []
// 收集器,初始指向结果数组,引用类型值,所以指向同一个数组
// 收集器指向会变化,当遇见#的时候,收集器会指向这个token的下表为2的新数组
let collector = nestedTokens
for (let i = 0; i < tokens.length; i++) {
let token = tokens[i]
switch (token[0]) {
case '#':
// console.log(token, '------------')
// 收集器里放入token,由于是引用类型,所以同时可以push到nestedTokens最终结果中
collector.push(token)
// 入栈
sections.push(token)
// console.log('collector', collector,' nestedTokens', nestedTokens, '-----#---0----')
// 收集器更换, 给token添加下标为2的数组,并更换收集器指向,改变了collector的引用指向,切断了collector,与最终结果的关系
// 下面等同于 token[2] = []; collector = token[2]
collector = token[2] = []
// console.log('collector', collector,' nestedTokens', nestedTokens, '-----#----1---')
// console.log(nestedTokens)
break;
case '/':
// console.log(sections, '-------------')
// 出栈,pop()会返回弹出的项目
sections.pop()
// 改变收集器为栈结构队尾(队尾为栈顶),那项的下标为2的数组
collector = sections.length > 0 ? sections[sections.length -1][2] : nestedTokens
break;
default:
// console.log('collector', collector,' nestedTokens', nestedTokens, '-----default-------')
// 如果 没进入栈,则直接结果里存,如果如栈了 就要往栈里 也就是 栈的 【2】数组里存
collector.push(token)
}
}
return nestedTokens
}
// parseTp2Tokens.js 无变化
import Scanner from './scaner'
import NextTokens from './nextTokens'
import RenderTp from './renderTp'
export default function (tpStr, data) {
const tokens = []
// 创建扫描器
const ScannerInit = new Scanner(tpStr)
let words;
// 扫描器
while (!ScannerInit.eos()) {
// 收集开始出现前的文字
words = ScannerInit.scanUtil('{{')
if (words !== '') {
// 存储
tokens.push(['text', words])
}
// 跳过大括号
ScannerInit.scan('{{')
words = ScannerInit.scanUtil('}}')
// 收集标记之间的
if (words !== '') {
// 存储
if (words[0] === '#') {
// 从下标为1 跳过#号开始存
tokens.push(['#', words.substring(1)])
} else if (words[0] === '/') {
tokens.push(['/', words.substring(1)])
} else {
tokens.push(['name', words])
}
}
// 跳过大括号
ScannerInit.scan('}}')
}
const nextTokens = NextTokens(tokens)
// 折叠token
return RenderTp(nextTokens, data)
}
// 扫描类未改变
// 创建扫描类
export default class Scanner {
constructor(tpStr) {
console.log('render函数里 调用Scanner')
this.tpStr = tpStr
// 建立指针
this.pos = 0
// 尾部字符串,默认为整个字符串
this.tail = tpStr
}
scan(tag) {
if (this.tail.indexOf(tag) === 0) {
// tag 有多长,指针就往后移动几位
this.pos += tag.length
// tail1也要调整
this.tail = this.tpStr.substring(this.pos)
}
}
// 让指针扫描吗,直到内容结束,并返回之前查到的文字
scanUtil(stopTag) {
// 记录指针原始位置
const pos_backup = this.pos
// 当尾巴的开头不是 stopTag的时候,就说明没有扫描到stopTag
// 写 && 很有必要,防止越界
while (this.tail.indexOf(stopTag) !== 0 && !this.eos()) {
this.pos++
//
// console.log('pos--------------', this.pos)
// 重新计算尾巴,从指针开始,到最后一位(第一个参数是启始,第二个是个数,如果省略了该参数)
this.tail = this.tpStr.substr(this.pos)
}
// 返回位于 String 对象中指定位置的子字符串(两个指定下标之间的字符,如果省略该参数,那么返回的子串会一直到字符串的结尾)
return this.tpStr.substring(pos_backup, this.pos)
}
// 指针防止越界
eos() {
return this.pos >= this.tpStr.length
}
}