js模板引擎渐进--each改进(6)

 

上一篇,我们实现了简单的 each 渲染处理,以最简单的方式,但是在实际的使用中,我们的需求远远没有那么简单。

这里我们对实际需求做出对应的调整,这是一个渐进的过程,经过一次次改进才能达到最终效果。

1.解决多层嵌套问题:

要解决多层嵌套问题,主要考虑 :

a.遍历主体。 即我要遍历的数组是什么呢?在前一篇,我们直接写死 “data”,默认 data 就是数组,但是当要进行多层次嵌套是,我们是不确定接下来要遍历的主体会是什么命名,所以,笔者一开始想到的是通过代码 在   {each}   里多加一个值,作为深层次遍历的数组对象  ,像这样:{each data.value}    ,这里的 data.value  就是下一层遍历的主体(数组)。

这样子 ,case:'}'   这里我们将这样处理:

 case "}":
                        isvarcode = false;
                        var varvalue = varcode.join("");
                        if(varvalue.indexOf("each")==0)
                        {
                            var eachInfo = varvalue.split(' ');
                            resultcode.push("for (var index in "+eachInfo[1]+") {var value = "+eachInfo[1]+"[index];");
                        }
                        else if(varvalue==="/each")
                        {
                            resultcode.push(" }");
                        }else{
                            varvalue = varvalue.replace("$index","index").replace("$value","value");
                            resultcode.push(" result.push(" + varvalue + ") ;");
                        }
                        varcode=[];

                        break;

 

 varvalue.split(' ');  这里按照 空格拆分,那第二个就是表示 将要遍历的主体,我们将它当作 代码内容保存即可。

这样,对应的,我们的模板改成这样:

<h3>{data.key}</h3><ul>{each data.value}<li>{$index}:{$value.name}</li>{/each}</ul>

然后处理后传入:

{key:"this is key",value:[{name:"name1"},{name:"name2"},{name:"name3"},{name:"name4"}]}

得到:

<h3>this is key</h3><ul><li>0:name1</li><li>1:name2</li><li>2:name3</li><li>3:name4</li></ul>

 

b.每一层 的 index 和 value 区分问题。正常我们写循环嵌套时,我们每一层的 index 值一般应该要不同,不然像 js 会有作用域提升问题,而如果是静态语言(c#/java)的话,重名根本是不允许的,所以,我们这里需要对index/value 进行不同层次要名称不同处理才行。

既然要自动处理的,那笔者便想到了用一个外部变量  eachIndex   保存顺序,然后每一层的 index  就变成  index_eachIndex,每深入一层,这个 eachIndex就要 +1,即遇到 each 指令的话,将做如下处理:

if(varvalue.indexOf("each")==0)
                        {
                            var eachInfo = varvalue.split(' ');
                            resultcode.push("for (var index_"+eachIndex+" in "+eachInfo[1]+") {var value_"+eachIndex+" = "+eachInfo[1]+"[index_"+eachIndex+"];");
                            eachIndex++;
                        }

那么新的问题随之而来:我怎么知道我后面拼接的变量用的是当前层的 index/value 呢?

其实这个好解决,因为每一次遇到 each 时,我们的 eachIndex  都会 +1 ,那么在当前层使用的 index 就是 index_(eachIndex-1)。所以如果在拼接的代码中遇到需要用到当层次的 index/value 时,如下处理即可:

varvalue = varvalue.replace("$index","index_"+(eachIndex-1)).replace("$value","value_"+(eachIndex-1));
                            resultcode.push(" result.push(" + varvalue + ") ;");

以下给出方法的代码:

function Template2code(template) {
            var resultcode = [];

            resultcode.push("function func(data) { var result=[];");

            var tempcode = [];
            var varcode = [];
            var isvarcode = false;
            var eachIndex = 0;

            for (var key in template) {
                var value = template[key];

                switch (value) {

                    case "\"":
                        if (isvarcode) {
                            varcode.push("\\\"")
                        }
                        else {
                            tempcode.push("\\\"");
                            
                        }

                        break;
                    case "{":
                        isvarcode = true;
                        resultcode.push(" result.push(\"" + tempcode.join("") + "\") ;");
                        tempcode=[];
                        break;
                    case "}":
                        isvarcode = false;
                        var varvalue = varcode.join("");
                        if(varvalue.indexOf("each")==0)
                        {
                            var eachInfo = varvalue.split(' ');
                            resultcode.push("for (var index_"+eachIndex+" in "+eachInfo[1]+") {var value_"+eachIndex+" = "+eachInfo[1]+"[index_"+eachIndex+"];");
                            eachIndex++;
                        }
                        else if(varvalue==="/each")
                        {   eachIndex--;
                            resultcode.push(" }");
                        }else{
                            varvalue = varvalue.replace("$index","index_"+(eachIndex-1)).replace("$value","value_"+(eachIndex-1));
                            resultcode.push(" result.push(" + varvalue + ") ;");
                        }
                        varcode=[];

                        break;

                    default:
                        if (isvarcode) {
                            varcode.push(value)
                        }
                        else {
                            tempcode.push(value);
                        }
                }
            }
            resultcode.push(" result.push(\"" + tempcode.join("") + "\") ;");
            resultcode.push("return result.join(\"\");}")
            return resultcode.join("");
        }

模板改成这样:

<h3>{data.key}</h3><ul>{each data.value}<li><p>{$index}:{$value.name}</p><p><dl>{each $value.record}<dd>{$value}</dd>{/each}</dl></p></li>{/each}</ul>

传入的数据:

{ key: "this is key", value: [{ name: "name1",record:[1111,2222,3333] },{ name: "name2",record:[1111,2222,3333] },{ name: "name3",record:[1111,2222,3333] }] }

渲染结果:

<h3>this is key</h3><ul><li><p>0:name1</p><p><dl><dd>1111</dd><dd>2222</dd><dd>3333</dd></dl></p></li><li><p>1:name2</p><p><dl><dd>1111</dd><dd>2222</dd><dd>3333</dd></dl></p></li><li><p>2:name3</p><p><dl><dd>1111</dd><dd>2222</dd><dd>3333</dd></dl></p></li></ul>

 

2.解决下层引用上层的问题:

嵌套的问题解决了,但是我们有时候在下一层还想引用上一层的变量或者数据呢,这种情况很常见吧。

在上面解决嵌套问题时,我们使用了自动生成 index/value  的方式来避免不同层 index/value 重名问题,但是我们使用的是自动生成的方式,在模板部分只能使用 $index/$value 表示,在模板层面无法区分 是哪一个层级,处理时虽然使用了自动拼接 eachIndex 区分了,但生成器生成的内容在模板是不知道的,没法引用,所以,我们前面的解决方法貌似就这样白费了。这种情况很正常,探索就是不断发现问题的过程。

 

这时候,笔者就想到了,如果我们在模板中指定 我们自己需要的  index/value  的名称,那在嵌套的子层要引用了上一层的变量,那直接使用自定义的 index/value  名称即可。

灵感,往往就是在你遇到死胡同时蹦出。

我们将 each 指令改成 这样一个形式:{each index,value data}  ,第一个 each 用于区分这个指令,而 index,value对应这一层级的下标和值,而 data 为循环主体,其中除了 开头的 each,后面的都是可以根据具体的数据情况自定义名称的。

最后我们将方法改成如下:

function Template2code(template) {
            var resultcode = [];

            resultcode.push("function func(data) { var result=[];");

            var tempcode = [];
            var varcode = [];
            var isvarcode = false;
            var eachIndex = 0;

            for (var key in template) {
                var value = template[key];
                console.log(value);
                switch (value) {
                    case "\n":
                        if (isvarcode) {
                            varcode.push(" ")
                        }
                        else {
                            tempcode.push(" ");

                        }

                        break;
                    case "\"":
                        if (isvarcode) {
                            varcode.push("\\\"")
                        }
                        else {
                            tempcode.push("\\\"");

                        }

                        break;
                    case "{":
                        isvarcode = true;
                        resultcode.push(" result.push(\"" + tempcode.join("") + "\") ;");
                        tempcode = [];
                        break;
                    case "}":
                        isvarcode = false;
                        var varvalue = varcode.join("");
                        if (varvalue.indexOf("each") == 0) {
                            // each index,value arr  
                            var eachInfo = varvalue.split(' ');
                            if(eachInfo.length!=3) throw "each 参数无效:each index,value arr";
                            var itemInfo = eachInfo[1].split(',');
                            if(itemInfo.length!=2) throw "each 参数无效:each index,value arr";

                            resultcode.push("for (var " + itemInfo[0] + " in " + eachInfo[2] + ") {var " + itemInfo[1] + " = " + eachInfo[2] + "[" + itemInfo[0] + "];");
                            
                        }
                        else if (varvalue === "/each") {
                            resultcode.push(" }");
                        } else {
                            resultcode.push(" result.push(" + varvalue + ") ;");
                        }
                        varcode = [];

                        break;

                    default:
                        if (isvarcode) {
                            varcode.push(value)
                        }
                        else {
                            tempcode.push(value);
                        }
                }
            }
            resultcode.push(" result.push(\"" + tempcode.join("") + "\") ;");
            resultcode.push("return result.join(\"\");}")
            return resultcode.join("");
        }

模板改成这样:

<h3 class="classvalue">{data.key}</h3><ul>{each index_0,value_0 data.value}<li><p>{index_0}:{value_0.name}</p><p><dl>{each index_1,value_1 value_0.record}<dd>{value_0.name}{value_1.key}:{each index_2,value_2 value_1.value}[{value_2}]{/each}</dd>{/each}</dl></p></li>{/each}</ul>

 

传入数据:

{

key: "this is key", value: [{ name: "name1", record: [{ key: "语文", value: [89, 90, 78, 99] }, { key: "数学", value: ["89", "100", "78", "99"] }, { key: "英语", value: [78, 88, 96, 99] }] }, { name: "name2", record: [{ key: "语文", value: [89, 90, 78, 99] }, { key: "数学", value: [89, 100, 78, 99] }, { key: "英语", value: [78, 88, 96, 99] }] }]

}

 

渲染的结果:

<h3 class="classvalue">this is key</h3><ul><li><p>0:name1</p><p><dl><dd>name1语文:[89][90][78][99]</dd><dd>name1数学:[89][100][78][99]</dd><dd>name1英语:[78][88][96][99]</dd></dl></p></li><li><p>1:name2</p><p><dl><dd>name2语文:[89][90][78][99]</dd><dd>name2数学:[89][100][78][99]</dd><dd>name2英语:[78][88][96][99]</dd></dl></p></li></ul>

 

 

至此each 的循环处理算是结束了,接下来我们处理  if-else if-else

有了 each  经验  ,if 的处理简单多了。

 

目录:

js模板引擎渐进--前言

js模板引擎渐进--区别js代码和html字符串(1)

js模板引擎渐进--生成最简单的function(2)

js模板引擎渐进--区别js代码和html字符串2(3)

js模板引擎渐进--改进字符串拼接方式(4)

js模板引擎渐进--each/for(5)

js模板引擎渐进--each改进(6)

js模板引擎渐进--if/else(7)

js模板引擎渐进--处理需要输出 { 或者 } 的情况(8)

js模板引擎渐进--代码改进封装(9)

js模板引擎渐进--后记

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值