目录
(1)解决数据是对象嵌套形式的问题函数(renderTemplate.js ):
注:在上篇中我们实现了将模板字符串转换为tokens数组,那么这一篇我们来聊聊将tokens数组结合数据并转换为真是DOM渲染出来的过程。
一、图示:
这一篇我们将来实现红框里面的过程。
二、代码演示:
1. index.js(入口文件):
import parseTemplateToTokens from './parseTemplateToTokens.js'
import renderTemplate from './renderTemplate.js';
import lookup from "./lookup"
//全局提供templateEngine对象
window.templateEngine = {
//渲染方法
render(templateStr, data) {
var tokens = parseTemplateToTokens(templateStr);
console.log(tokens);
// 调用renderTemplate函数,让tokens数组变为dom字符串
var domStr = renderTemplate(tokens,data);
return domStr;
}
};
将渲染出来的tokens字符串数组结合数据传入到 renderTemplate方法中。
2.数据渲染过程:
renderTemplate.js 函数的功能:是让tokens数组变为dom字符串 ,#号标记的tokens,需要递归处理它的下标为2的小数组。
首先将传入进来的tokens遍历分为三种情况进行处理,分别是:"text"类型,"name"类型和"#"类型。
- "text"类型:直接追加文本内容。
- "name"类型:这里需要进行数据处理。(因为JS不识别 ' . ' 的形式)
- "#"类型:递归处理它下标为2的小数组。
(1)解决数据是对象嵌套形式的问题函数(renderTemplate.js ):
renderTemplate.js 函数:
/*
函数的功能是让tokens数组变为dom字符串
#号标记的tokens,需要递归处理它的下标为2的小数组
*/
import lookup from "./lookup";
import parseArray from "./parseArray"
export default function renderTemplate(tokens, data){
// console.log(data);
// 结果字符串
var resultStr = "";
// 遍历tokens
for(let i = 0;i<tokens.length;i++){
let token = tokens[i];
// 查看类型
if(token[0] === "text"){
resultStr += token[1];
}else if(token[0] === "name"){
//如果是name类型,那么就直接使用它的值,
//使用lookup防止是对象取值的形式
resultStr += data[token[1]];
}else if(token[0] === "#"){
//稍后处理
}
}
return resultStr;
}
index.html文件:
<div class="container">
</div>
<script src="/xuni/bundle.js"></script>
<script>
var templateStr = `<h1>我考了{{n.a.b}}分,好{{mood}}啊</h1>`;
var data = {
n:{
a:{
b:100
}
},
mood:"激动"
};
// 调用
var inx = templateEngine.render(templateStr, data);
var container = document.getElementsByClassName("container")[0];
container.innerHTML = inx;
console.log(inx);
</script>
注:可以看到data里面以对象嵌套形式的数据并没有取出来,所以我们要先解决此类问题。
(2)编写从对象中识别字符串函数(lookUp.js):
lookUp.js函数功能:可以在dataObj对象中,寻找用连续点符号的keyName属性
比如:dataObj是
{
a:{
b:{
c:100
}
}
}
那么lookup(dataObj,a.b.c)的结果就是100
/*
功能是:可以在dataObj对象中,寻找用连续点符号的keyName属性
比如:dataObj是
{
a:{
b:{
c:100
}
}
}
那么lookup(dataObj,a.b.c)的结果就是100
* */
export default function lookup(dataObj,keyName){
// console.log(dataObj,keyName);
// 看看keyName中有没有点符号
if(keyName.indexOf(".") !== -1 && keyName!='.'){
//将其装换为数组
var keys = keyName.split('.');
//temp存放这个嵌套对象
var temp = dataObj;
for(let i = 0;i<keys.length;i++){
//从嵌套对象中一层一层查找
temp = temp[keys[i]];
}
return temp;
}
return dataObj[keyName];
};
修改renderTemplate.js 函数
/*
函数的功能是让tokens数组变为dom字符串
#号标记的tokens,需要递归处理它的下标为2的小数组
*/
import lookup from "./lookup";
import parseArray from "./parseArray"
export default function renderTemplate(tokens, data){
// console.log(data);
// 结果字符串
var resultStr = "";
// 遍历tokens
for(let i = 0;i<tokens.length;i++){
let token = tokens[i];
// 查看类型
if(token[0] === "text"){
resultStr += token[1];
}else if(token[0] === "name"){
//如果是name类型,那么就直接使用它的值,
//使用lookup防止是对象取值的形式
resultStr += lookup(data,token[1]);
}else if(token[0] === "#"){
//处理递归
}
}
return resultStr;
}
(3)处理"#"类型函数(parseArray.js):
创建一个parseArray.js函数,处理数组。结合renderTemplate实现递归。此函数接收两个参数一个是token一个是data(token=tokens[i])。
import lookup from "./lookup"
import renderTemplate from "./renderTemplate";
/*
* 处理数组,结合renderTemplate实现递归
* 注意:这个函数收的参数是token!而不是tokens
* token = tokens[i]
* 这个函数要递归调用renderTemplate函数,调用多少次?根据data数组的长度
* */
export default function parseArray(token,data){
//从#类型中 根据token[1]的值取不同的数据
//token[1]指的是 #类型嵌套数组中第二个值,根据此值利用lookUp函数向data中取值
var v = lookup(data,token[1]);
console.log("-------------");
console.log(v);
console.log("++++++++++");
//结果字符串
var resultStr = "";
//便利V数组,v一定是数组
//下面的循环是一个比较难思考的循环
//它是遍历数据,而不是遍历tokens.数组中的数据有几条,就要遍历几条。
//token[2]指的是 #类型 的数组中嵌套的数组
console.log(token[2]);
for(let i = 0;i<v.length;i++){
resultStr += renderTemplate(token[2],{
//这里要考虑到数据是简单类型的只有一个.的情况
/**
*
var templateStr = `
<ul>
{{#arr}}
<li>{{.}}</li>
{{/arr}}
</ul>
`;
var data = {
arr:["A","B","C"]
};
* */
//现在是这个数据的小对象,是v[i]的展开,就是v[i]本身
...v[i],
//补充一个.属性
'.':v[i]
});
}
return resultStr;
}
注意点:
- var v = lookup(data,token[1]); token[1]是取嵌套数组中#后面的下一个值。
根据此值和data数据传入到lookUp函数中我们得到 v 的值。v一定是数组。
- token[2]指的是 #类型 的数组中嵌套的数组。
- for循环中遍历数组,根据数据的长度我们调用renderTemplate函数向模板字符串中添加数据。
renderTemplate.js函数:
/*
函数的功能是让tokens数组变为dom字符串
#号标记的tokens,需要递归处理它的下标为2的小数组
*/
import lookup from "./lookup";
import parseArray from "./parseArray"
export default function renderTemplate(tokens, data){
// console.log(data);
// 结果字符串
var resultStr = "";
// 遍历tokens
for(let i = 0;i<tokens.length;i++){
let token = tokens[i];
// 查看类型
if(token[0] === "text"){
resultStr += token[1];
}else if(token[0] === "name"){
//如果是name类型,那么就直接使用它的值,
//使用lookup防止是对象取值的形式
resultStr += lookup(data,token[1]);
}else if(token[0] === "#"){
resultStr += parseArray(token,data);
}
}
return resultStr;
}
(4)最终实现:
index.js(入口文件):
import parseTemplateToTokens from './parseTemplateToTokens.js'
import renderTemplate from './renderTemplate.js';
import lookup from "./lookup"
//全局提供templateEngine对象
window.templateEngine = {
//渲染方法
render(templateStr, data) {
var tokens = parseTemplateToTokens(templateStr);
console.log(tokens);
// 调用renderTemplate函数,让tokens数组变为dom字符串
var domStr = renderTemplate(tokens,data);
return domStr;
}
};
renderTemplate.js函数: 函数的功能是让tokens数组变为dom字符串,#号标记的tokens,需要递归处理它的下标为2的小数组。
/*
函数的功能是让tokens数组变为dom字符串
#号标记的tokens,需要递归处理它的下标为2的小数组
*/
import lookup from "./lookup";
import parseArray from "./parseArray"
export default function renderTemplate(tokens, data){
// console.log(data);
// 结果字符串
var resultStr = "";
// 遍历tokens
for(let i = 0;i<tokens.length;i++){
let token = tokens[i];
// 查看类型
if(token[0] === "text"){
resultStr += token[1];
}else if(token[0] === "name"){
//如果是name类型,那么就直接使用它的值,
//使用lookup防止是对象取值的形式
resultStr += lookup(data,token[1]);
}else if(token[0] === "#"){
resultStr += parseArray(token,data);
}
}
return resultStr;
}
lookUp.js函数:功能是:可以在dataObj对象中,寻找用连续点符号的keyName属性(用来处理数据)
/*
功能是:可以在dataObj对象中,寻找用连续点符号的keyName属性
比如:dataObj是
{
a:{
b:{
c:100
}
}
}
那么lookup(dataObj,a.b.c)的结果就是100
* */
export default function lookup(dataObj,keyName){
// console.log(dataObj,keyName);
// 看看keyName中有没有点符号
if(keyName.indexOf(".") !== -1 && keyName!='.'){
//将其装换为数组
var keys = keyName.split('.');
//temp存放这个嵌套对象
var temp = dataObj;
for(let i = 0;i<keys.length;i++){
//从嵌套对象中一层一层查找
temp = temp[keys[i]];
}
return temp;
}
return dataObj[keyName];
};
parseArray.js函数: 处理数组,结合renderTemplate实现递归
import lookup from "./lookup"
import renderTemplate from "./renderTemplate";
/*
* 处理数组,结合renderTemplate实现递归
* 注意:这个函数收的参数是token!而不是tokens
* token = tokens[i]
* 这个函数要递归调用renderTemplate函数,调用多少次?根据data数组的长度
* */
export default function parseArray(token,data){
//从#类型中 根据token[1]的值取不同的数据
//token[1]指的是 #类型嵌套数组中第二个值,根据此值利用lookUp函数向data中取值
var v = lookup(data,token[1]);
console.log("-------------");
console.log(v);
console.log("++++++++++");
//结果字符串
var resultStr = "";
//便利V数组,v一定是数组
//下面的循环是一个比较难思考的循环
//它是遍历数据,而不是遍历tokens.数组中的数据有几条,就要遍历几条。
//token[2]指的是 #类型 的数组中嵌套的数组
console.log(token[2]);
for(let i = 0;i<v.length;i++){
resultStr += renderTemplate(token[2],{
//这里要考虑到数据是简单类型的只有一个.的情况
/**
*
var templateStr = `
<ul>
{{#arr}}
<li>{{.}}</li>
{{/arr}}
</ul>
`;
var data = {
arr:["A","B","C"]
};
* */
//现在是这个数据的小对象,是v[i]的展开,就是v[i]本身
...v[i],
//补充一个.属性
'.':v[i]
});
}
return resultStr;
}
注:代码地址。
Mustache完结撒花。