enjoy标签扩展-for循环中按照数量分组渲染#group

1.在自己的代码中创建包 com.jfinal.template.stat.ast;
2.创建类 For,具体代码如下:

package com.jfinal.template.stat.ast;

import com.jfinal.template.Env;
import com.jfinal.template.expr.ast.Expr;
import com.jfinal.template.expr.ast.ForCtrl;
import com.jfinal.template.expr.ast.Logic;
import com.jfinal.template.io.Writer;
import com.jfinal.template.stat.Ctrl;
import com.jfinal.template.stat.Scope;

import java.util.Iterator;

public class For extends Stat {
    private ForCtrl forCtrl;
    private Stat stat;
    private Stat _else;

    public For(ForCtrl forCtrl, StatList statList, Stat _else) {
        this.forCtrl = forCtrl;
        this.stat = statList.getActualStat();
        this._else = _else;
    }

    public void exec(Env env, Scope scope, Writer writer) {
        scope = new Scope(scope);
        // 将forCtrl往group中传递
        scope.setLocal("forCtrl",this.forCtrl);
        if (this.forCtrl.isIterator()) {
            this.forIterator(env, scope, writer);
        } else {
            this.forLoop(env, scope, writer);
        }

    }

    private void forIterator(Env env, Scope scope, Writer writer) {
        Ctrl ctrl = scope.getCtrl();
        Object outer = scope.get("for");
        ctrl.setLocalAssignment();
        ForIteratorStatus forIteratorStatus = new ForIteratorStatus(outer, this.forCtrl.getExpr().eval(scope), this.location);
        ctrl.setWisdomAssignment();
        scope.setLocal("for", forIteratorStatus);
        Iterator<?> it = forIteratorStatus.getIterator();
        String itemName = this.forCtrl.getId();
        while(it.hasNext()) {
            // 将it往group中传递
            scope.setLocal("forIterator",it);
            scope.setLocal(itemName, it.next());
            this.stat.exec(env, scope, writer);
            forIteratorStatus.nextState();
            if (ctrl.isJump()) {
                if (ctrl.isBreak()) {
                    ctrl.setJumpNone();
                    break;
                }

                if (!ctrl.isContinue()) {
                    return;
                }

                ctrl.setJumpNone();
            }
        }

        if (this._else != null && forIteratorStatus.getIndex() == 0) {
            this._else.exec(env, scope, writer);
        }

    }

    private void forLoop(Env env, Scope scope, Writer writer) {
        Ctrl ctrl = scope.getCtrl();
        Object outer = scope.get("for");
        ForLoopStatus forLoopStatus = new ForLoopStatus(outer);
        scope.setLocal("for", forLoopStatus);
        Expr init = this.forCtrl.getInit();
        Expr cond = this.forCtrl.getCond();
        Expr update = this.forCtrl.getUpdate();
        ctrl.setLocalAssignment();
        init.eval(scope);

        for(; cond == null || Logic.isTrue(cond.eval(scope)); update.eval(scope)) {
            ctrl.setWisdomAssignment();
            this.stat.exec(env, scope, writer);
            ctrl.setLocalAssignment();
            forLoopStatus.nextState();
            if (ctrl.isJump()) {
                if (ctrl.isBreak()) {
                    ctrl.setJumpNone();
                    break;
                }

                if (!ctrl.isContinue()) {
                    ctrl.setWisdomAssignment();
                    return;
                }

                ctrl.setJumpNone();
            }
        }

        ctrl.setWisdomAssignment();
        if (this._else != null && forLoopStatus.getIndex() == 0) {
            this._else.exec(env, scope, writer);
        }

    }
}


3.编写分组标签GroupDirective代码:

import com.jfinal.template.Directive;
import com.jfinal.template.Env;
import com.jfinal.template.TemplateException;
import com.jfinal.template.expr.ast.Expr;
import com.jfinal.template.expr.ast.ExprList;
import com.jfinal.template.expr.ast.ForCtrl;
import com.jfinal.template.io.Writer;
import com.jfinal.template.stat.Scope;
import com.jfinal.template.stat.ast.ForIteratorStatus;

import java.util.Iterator;

/**
 * 分组标签
 */
public class GroupDirective extends Directive {

    private Expr groupNumExpr;

    public GroupDirective() {

    }

    @Override
    public void exec(Env env, Scope scope, Writer writer) {
        if (groupNumExpr == null) {
            stat.exec(env, scope, writer);
        } else {
            Object groupNumObj = this.groupNumExpr.eval(scope);
            if (!(groupNumObj instanceof Integer groupNum)) {
                throw new TemplateException("group的第一个参数必须为int类型", this.location);
            }

            Object outer = scope.get("for");
            if (outer instanceof ForIteratorStatus) {
                forIterator(env, scope, writer, groupNum, 0);
            } else {
                forLoop(env, scope, writer, groupNum);
            }
        }
    }

    private void forIterator(Env env, Scope scope, Writer writer, Integer groupNum, Integer flag) {
        this.stat.exec(env, scope, writer);
        ForIteratorStatus outer = (ForIteratorStatus) scope.get("for");
        if (flag < groupNum - 1) {
            Iterator<?> it = (Iterator<?>) scope.get("forIterator");
            if (it.hasNext()) {
                ForCtrl forCtrl = (ForCtrl) scope.get("forCtrl");
                scope.setLocal(forCtrl.getId(), it.next());
                scope.set("forIterator", it);
                scope.setLocal("for", outer);
                flag++;
                forIterator(env, scope, writer, groupNum, flag);
            }
        }
    }

    private void forLoop(Env env, Scope scope, Writer writer, Integer groupNum) {
        this.stat.exec(env, scope, writer);
    }


    // ExprList 代表指令参数表达式列表
    public void setExprList(ExprList exprList) {
        int paraNum = exprList.length();
        if (paraNum == 0) {
            this.groupNumExpr = null;
        } else {
            this.groupNumExpr = exprList.getExpr(0);
        }
    }

    public boolean hasEnd() {
        return true;
    }
}



4.配置类中扩展#group指令

addDirective("group", GroupDirective.class);


5.编写模版代码举例:

#set(test=[1,2,3,4,5,6,7,8,9])
#for(item : test)
<div style="width:100%">
    #group(4)
    <span style="padding-right:10px">#(item)</span>
    #end
</div>
#end


6.最终渲染结果如下:

image.png

评论区

JFinal

2023-11-28 18:13

能扩展 #for 指令那必然是对 enjoy 原理有很深理解,这个扩展很有深度,谢谢分享

这个需求如果没有扩展确实还不太好实现

JFinal

2023-11-28 18:25

刚刚用 enjoy 现有指令实现了,你试一下:

public static void main(String[] args) {
String t = "#set(test=[1,2,3,4,5,6,7,8,9])" +
"#for(item : test)" +
"#if( for.index % 4 == 0 ) <div style='width:100%'>\n #end" +
"\t\t<span style='padding-right:10px'>#(item)</span>\n" +
"#if( for.count % 4 == 0 || for.last) </div>\n #end" +
"#end";

Engine.use().getTemplateByString(t).render(System.out);
}

JFinal

2023-11-28 18:26

这里的两处关键:#for 指令中的第一个 if :
#if( for.index % 4 == 0 )

第二个 if
#if( for.count % 4 == 0 || for.last)

灵活用好 enjoy 现有功能,一般来说都可以实现, enjoy code enjoy life

北流家园网

2023-11-29 14:10

为什么不使用CSS来分组呢?flex搞定一切

热门分享

扫码入社