JFinal自定义模板指令AjaxPortal-实现页面区域异步加载与刷新

jfinal自定义模板指令.png

项目背景一个页面上关联了多个子表的信息,需要同时在一个界面上读取出来,如果是单纯的读取显示没有任何交互的话,可以直接后台读取数据,前端页面循环渲染显示就OK,但是项目需求是需要与页面上子表数据有CURD操作交互,看下图:

前提:项目里不使用自带数据加载和刷新功能的table。就使用普通的table,也不使用Vue.js这种前端框架。


点击打开gif图看效果:

http://www.xiaomuedu.com/ueditor/jsp/upload/image/20180527/1527414814138022575.gif


需要在一个界面上实现各子表的增删改查,单个Table的数据区域Html片段自行更新,就需要用到AjaxPortal模式。

AjaxPortal模式简介

使用ajax加载Html片段Append到指定的DIV区域,完成局部刷新效果。

实现细节:

1、JavaScript 基于Jquery封装ajax加载Html片段的工具库

/**
 * 自动Ajax加载内容的Portal
 */
;(function($){
    $.extend($.fn, {
	ajaxPortal:function(replaceBody,url){
		return this.each(function(){
			var portal=$(this);
			var l_url="";
			if(url){
				l_url=url;
			}else{
				l_url=portal.data("url")
			}
			if(l_url.indexOf("?")!=-1){
				l_url=l_url+"&t="+new Date().getTime();
			}else{
				l_url=l_url+"?t="+new Date().getTime();
			}
			var autoload=portal.data("autoload");
			if(autoload==undefined){
				autoload=true;
			}
			if((replaceBody==undefined&&autoload)||(replaceBody!=undefined)){
				$.get(l_url,function(html){
					if(replaceBody){
						portal.empty().html(html);
					}else{
						portal.append(html);
					}
					
			});
					
			}
		});
	}
});
})(jQuery);


2、上面js库搞定后,在没有自定义JFinal模板引擎指令之前,是可以直接使用html的,代码如下:

<div data-ajaxportal data-url="你需要加载html片段的具体action地址" id="myAjaxPortal"></div>

3、上面Html标签写完 页面上调用一下js就能实现自动加载html片段了

$("#myAjaxPortal").ajaxPortal();


JFinal自定义指令扩展之后 可以不写html了,先来看看 自定义指令如何调用

<!-- 发展数据加载 -->
#ajaxPortal("你的action Url","project_growth_portal")
<!-- 大事记加载 -->
#ajaxPortal("你的action Url","project_thingrecord_portal")
<!-- 细节谈加载 -->
#ajaxPortal("你的action Url","project_detail_portal")


说明:一共有三个参数的,第一个是URL地址,第二个参数是给这个DIV Portal设置一个ID,第三个是指定是否默认自动执行加载

经过封装可以实现,一个参数的时候默认自动加载 ID不要,两个参数的时候 指定了ID和URL 默认自动加载 三个参数就是完全自己决定是否自动执行加载。

上代码吧:

import java.io.IOException;
import com.jfinal.template.Directive;
import com.jfinal.template.Env;
import com.jfinal.template.expr.ast.Expr;
import com.jfinal.template.expr.ast.ExprList;
import com.jfinal.template.io.Writer;
import com.jfinal.template.stat.ParseException;
import com.jfinal.template.stat.Scope;

public class AjaxPortalDirective extends Directive {
	
	private Expr portalIdExpr;
	private Expr urlExpr;
	private Expr autoLoadExpr;
	private int paraNum;
	
	public void setExprList(ExprList exprList) {
		this.paraNum = exprList.length();
		if (paraNum > 3) {
			throw new ParseException("Wrong number parameter of #ajaxPortal directive, three parameters allowed at most", location);
		}
		
		if (paraNum == 1) {
			this.urlExpr  = exprList.getExpr(0);
		} else if (paraNum == 2) {
			this.urlExpr  = exprList.getExpr(0);
			this.portalIdExpr = exprList.getExpr(1);
		} else if (paraNum == 3) {
			this.urlExpr  = exprList.getExpr(0);
			this.portalIdExpr = exprList.getExpr(1);
			this.autoLoadExpr = exprList.getExpr(2);
		}
	}
	
	public void exec(Env env, Scope scope, Writer writer) {
		if (paraNum == 0) {
			outputNothing(env, writer);
		} else if (paraNum == 1) {
			outputNormalAjaxPortal(env, scope, writer);
		} else if (paraNum == 2) {
			outputNormalAjaxPortalWithPortalId(env, scope, writer);
		} else if (paraNum == 3) {
			outputFullAjaxPortal(env, scope, writer);
		}
	}
	/**
	 * 输出空字符
	 * @param env
	 * @param writer
	 */
	private void outputNothing(Env env, Writer writer) {
		
	}
	/**
	 * 输出自动加载的仅指定Url的ajaxPortal代码
	 * @param env
	 * @param scope
	 * @param writer
	 */
	private void outputNormalAjaxPortal(Env env,Scope scope, Writer writer) {
		Object value=this.urlExpr.eval(scope);
		if(value!=null){
			try {
				writer.write("<div data-ajaxportal data-url='");
				writer.write(value.toString());
				writer.write("'></div>");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
	}
	/**
	 * 输出自动加载的带有portalId和url的ajaxPortal代码
	 * @param env
	 * @param scope
	 * @param writer
	 */
	private void outputNormalAjaxPortalWithPortalId(Env env,Scope scope, Writer writer) {
		Object url=this.urlExpr.eval(scope);
		Object portalId=this.portalIdExpr.eval(scope);
		if(url!=null&&portalId!=null){
			try {
				writer.write("<div data-ajaxportal data-url='");
				writer.write(url.toString());
				writer.write("' id='");
				writer.write(portalId.toString());
				writer.write("'></div>");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
	}
	/**
	 * 输出带有portalId和url的ajaxPortal代码
	 * 可以设置是否自动加载
	 * @param env
	 * @param scope
	 * @param writer
	 */
	private void outputFullAjaxPortal(Env env,Scope scope, Writer writer) {
		Object url=this.urlExpr.eval(scope);
		Object portalId=this.portalIdExpr.eval(scope);
		Object autoload=this.autoLoadExpr.eval(scope);
		if(url!=null&&portalId!=null&&autoload!=null){
			try {
				writer.write("<div data-ajaxportal data-autoload='");
				writer.write(autoload.toString());
				writer.write("' data-url='");
				writer.write(url.toString());
				writer.write("' id='");
				writer.write(portalId.toString());
				writer.write("'></div>");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
	}
	
	
	
}


总结:自定义指令可以配合HTML和JS 完成很多强大功能做出很好的用户体验。

这就是AjaxPortal自定义指令的代码,文章里发的是截图,如果需要全部demo源码,请关注【JFinal学院】公众号:jfinalxueyuan。

回复:ajaxportal 关键词 获取源码下载地址。


希望得到您的转发分享与关注,打造JFinal学院-JFinal社区自己的学院。

image.png

JFinal学院QQ群:362557641 JFinal学院

————————————————————————————————

如果还不明白,可以微信联系我:

image.png


评论区

山东小木

2018-05-27 18:02

@jfinal 我自定义指令配合js实现了ajaxPortal

lyh061619

2018-05-27 19:34

不错哦。

JFinal

2018-05-27 21:18

很高端的玩法,点赞收藏,感谢分享

JFinal

2018-05-27 22:05

有个小建议,writer.write 方法可以调用多次,避免用加号来连接字符串,可以提升性能

因为 jfinal enjoy 的 writer 内部是全程使用缓冲区的,会避免整个过程内存分配,大大在提升性能

山东小木

2018-05-27 22:09

@JFinal 恩 项目里测试实现 直接就连接字符串了 改成多次调用的试过了没问题

JFinal

2018-05-27 22:13

@山东小木 setExprList 的 if 可以再省点代码,可去掉所有 null 的赋值,例如:

if (paraNum == 1) {
this.urlExpr = exprList.getExpr(0);
} else if (paraNum == 2) {
this.urlExpr = exprList.getExpr(0);
this.portalIdExpr = exprList.getExpr(1);
} else if (paraNum == 3) {
this.urlExpr = exprList.getExpr(0);
this.portalIdExpr = exprList.getExpr(1);
this.autoLoadExpr = exprList.getExpr(2);
}


outputNothing() 这个方法内部可以留空,什么也不写,因为 writer.write("") 等价于啥也不输出

山东小木

2018-05-27 22:25

@JFinal 改过了
writer.write(autoload.toString());
writer.write("' data-url='");
writer.write(url.toString());
writer.write("' id='");
writer.write(portalId.toString());
链式调用好点儿吧?

JFinal

2018-05-27 22:43

@山东小木 Writer 一开始是用的 java.io.Writer ,后来改成自己的带有缓冲区的设计 com.jfinal.template.io.Writer,沿用了 java 的方法原型

北流家园网

2018-06-28 11:51

楼主有更新吗?

热门分享

扫码入社