JeeSite 4.0 說說前端的那些事

引言

一個不得不說的話題,通過近幾年的發展,Web前端開發已經不是一個新有的崗位了,前端技術發展很是迅速,技術更新換代也很快,對於前端工程師來講是一個很大的挑戰「掙扎期」。javascript

從統計來看,中級前端的待遇是略高於中級後端的。這對於中小企業、創業公司來講組建一個專有的前端團隊仍是很一件很不容易的事情,無形中增長了人力成本, 話說招前端工程師簡單,但能招聘到合適的前端工程師來講,是一件很是不容易的事情。css

爲了解決這個事情,中小企業、創業公司都在思考一個問題,作企業應用軟件,若是不去組建專門的前端團隊,能有一個很好的開發平臺,很好的框架,讓後端工程師具有一些基本的前端知識,就能夠去作出很漂亮的界面就行了。html

這個想法很好,可是你會說,可能嗎,會一點基礎前端就能作好嗎?專業的事情仍是有專業的人來作,先後端分離是趨勢,表現邏輯分離意義很大。沒有絕對完美的事情,儘管種種誘惑,惟心自問合適本身嗎?我不否定,這還要針對產品、針對項目來選擇解決方案。但JeeSite的中心思想是快速快發,快速交付,控制成本,對於一個想快速交付項目來講不見得是一件好事。前端

重口難調,也許你不贊同這些見解,做者歡迎提問,固然你也能夠將JeeSite徹底做爲服務端代碼,快速提供數據接口,自由實現或選型一套前端UI。java

好了,既然是奔着快速交付,控制成原本的,咱們就依這個角度去思考方案:web

  • 第一,技術選型 Spring MVC + Beetl + jQuery + Bootstrap,優點很明顯,很少說,下面章節簡要說下;
  • 第二,開發一些經常使用函數庫,如:字符串工具類,集合工具類,映射轉換工具類,配置工具類,權限用戶工具類等;
  • 第三,封裝一些經常使用表單控件參考Spring MVC的form標籤,實現更便捷的輸入框、下拉框、單選、複選等,自動進行數據綁定;
  • 第四,封裝一些經常使用表單組件,如:多級樹結構選擇組件,列表選擇組件,文件上傳組件,驗證碼生成組件等等;
  • 第五,封裝一些經常使用JS類庫,如:動態加載,對話框,消息框,加載框,JS模板,Ajax,格式化,動態Tab等待;
  • 第六,封裝一個JS數據表格組件DataGrid,分頁,排序,多表頭,分組,子表,凍結,小計,合計,編輯行,樹表表格等;
  • 第七,豐富例子,如:Box盒子、表單佈局、柵格佈局、圖表等等

模板語言界定符選擇

Beetl模板語言相似JS語言和習俗,只須要將Beetl語言放入定界符號裏便可,如默認的是<% %>,那JeeSite是怎樣選擇的呢:ajax

設想定義:<% %>算法

優勢:jsp標準定界符,比較容易被理解,是後端運行的語法json

缺點:html後綴的模板,不能和html標籤混用,不然IDE會提示語法錯誤後端

設想定義:@ 回車符

優勢:簡單

缺點:多行beetl語法時,比較麻煩,而且會出現多餘的不少空格空行

設想定義:[ ]、[@ ]、[@ ]

有點:能夠和html混用

缺點:與js的[]衝突,必須使用\轉義

**設想定義:[@ @]、[# #]、# #、@ @**

優勢:基本沒有標示符衝突

缺點:感官、閱讀、寫法稍微差點

設想定義:<!--# -->、<!--: -->

優勢:使用html註釋,沒有標示符衝突

缺點:使用IDE高亮時,沒有寫代碼的感受,像是在寫註釋

最終選擇:<% %>

通過上述分析,最終仍是迴歸默認,使用jsp標準定界符<%%>來做爲模板語言的定界符,一方同比較容易被理解,明確是後端運行的語法,另外一方面衝突少,邊界比較好界定

寫一個通用佈局的頁面

<% layout('/layouts/default.html', {title: '菜單管理', libs: ['validate'], bodyClass: ''}){ %>
<div class="main-content">
	<div class="box box-main">
		<div class="box-header with-border">
			<div class="box-title">
				<i class="fa icon-book-open"></i> 菜單管理
			</div>
			<div class="box-tools pull-right">
				<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>
			</div>
		</div>
		<div class="box-body">
			
		</div>
		<div class="box-footer">
			
		</div>
	</div>
</div>
<% } %>

調用默認佈局 /layouts/default.html,自動引入頁面頭部和尾部內容,經過參數設置要加載的css和js類庫,參數以下:

title參數: 設置頁面的標題名字

libs參數: 設置頁面要引入的css和js類庫,支持類庫以下:

默認引入:layer、select二、WdatePicker

  • zTree:樹結構控件
  • tabPage:動態頁籤插件
  • dataGrid:數據表格組件
  • validate:表單驗證組件
  • inputmask:表單格式化工具
  • fileupload:文件上傳插件
  • ueditor:富文本編輯器控件

bodyClass參數: 設置body的class屬性值

定義經常使用函數庫

經常使用工具類導入

如下工具類可經過@類型快速調用,如:${@Global.getConfig('key')}

  • Global:全局配置類,全局常量,讀取屬性文件參數值等
  • EncodeUtils:封裝各類格式的編碼解碼工具類,HEX、Base6四、HTML、URL、XSS過濾、SQL過濾等
  • ListUtils:List經常使用工具類,繼承Apache的ListUtils,New工具、快速提取屬性值、類型轉換等
  • MapUtils:Map經常使用工具類,繼承Apache的MapUtils,New工具、Map與Bean互轉等
  • SetUtils:Set經常使用工具類,繼承Apache的SetUtils,New工具等
  • IdGenerate:封裝各類生成惟一性ID算法的工具類,生成LongUUID,StringUUID,Code生成等
  • ByteUtils:字節轉換工具
  • DateUtils:日期工具類,繼承Apache的DateUtils
  • NumberUtils:BigDecimal工具類,繼承Apache的NumberUtils類
  • ObjectUtils:對象操做工具類,繼承Apache的ObjectUtils類
  • StringUtils:字符串工具類,繼承Apache的StringUtils類
  • TimeUtils:時間計算工具類,xx天xx時xx分xx秒,剛剛,xx秒,xx分鐘,xx小時前、xx天前
  • WorkDayUtils:工做日計算工具類,計算日期直接的工做日等
  • BeanMapper:簡單封裝Dozer,對象數據映射
  • JaxbMapper:Jaxb實現XML與Java Object的轉換
  • JsonMapper:簡單封裝Jackson,實現Json與Java Object的轉換
  • ClassUtils:Class掃描工具類,根據接口查詢類,根據繼承查詢類等
  • ReflectUtils:反射工具類,方便進行getter/setter方法, 訪問私有變量, 調用私有方法
  • ModuleUtils:模塊工具類,方便獲取系統模塊信息
  • UserUtils:用戶工具類,方便獲取進行用戶及相關信息

如下是Beetl函數及擴展函數

  • date:返回一個java.util.Date類型的變量,如 date() 返回一個當前時間(對應java的java.util.Date); ${date( "2011-1-1" , "yyyy-MM-dd" )} 返回指定日期
  • print:打印一個對象 print(user.name);
  • println:打印一個對象以及回車換行符號,回車換號符號使用的是模板自己的,而不是本地系統的.若是僅僅打印一個換行符,則直接調用println() 便可
  • nvl:函數nvl,若是對象爲null,則返回第二個參數,不然,返回本身 nvl(user,"不存在")
  • isEmpty:判斷變量或者表達式是否爲空,變量不存在,變量爲null,變量是空字符串,變量是空集合,變量是空數組,此函數都將返回true
  • isNotEmpty:同上,判斷對象是否不爲空
  • has:變量名爲參數,判斷是否存在此全局變量,如 has(userList),相似於1.x版本的exist("userList"),但不須要輸入引號了
  • assert:若是表達式爲false,則拋出異常
  • trim:截取數字或者日期,返回字符,如trim(12.456,2)返回"12.45",trim(date,'yyyyy')返回"2017"
  • trunc:截取數字,保留指定的小數位,如trunc(12.456,2) 輸出是12.45.不推薦使用,由於處理float有問題,兼容緣由保留了
  • decode:一個簡化的if else 結構,如 decode(a,1,"a=1",2,"a=2","不知道了")},若是a是1,這decode輸出"a=1",若是a是2,則輸出"a==2", 若是是其餘值,則輸出"不知道了"
  • debug:在控制檯輸出debug指定的對象以及所在模板文件以及模板中的行數,如debug(1),則輸出1 [在3行@/org/beetl/core/lab/hello.txt],也能夠輸出多個,如debug("hi",a),則輸出hi,a=123,[在3行@/org/beetl/core/lab/hello.txt]
  • range:接收三個參數,初始值,結束值,還有步增(能夠不須要,則默認爲1),返回一個Iterator,經常使用於循環中,如for(var i in range(1,5)) {print(i)},將依次打印1234.
  • flush:強制io輸出。
  • pageCtx:僅僅在web開發中,設置一個變量,而後能夠在頁面渲染過程當中,調用此api獲取,如pageCtx("title","用戶添加頁面"),在其後任何地方,能夠pageCtx("title") 獲取該變量
  • cookie:返回指定的cookie對象 ,如var userCook = cookie("user"), allCookies = cookie();
  • isBlank:判斷對象是不是一個空字符串,${isBlank('str')}
  • isNotBlank:判斷對象是否不是一個空字符串,${isBlank('str')}
  • toJson:將對象轉Json字符串,${toJson(Object)}
  • fromJson:將Json字符串轉換爲對象,${fromJson(Object)}
  • hasPermi:判斷是否有改權限;單個權限驗證:${hasPermi('sys:user:edit')};多個AND關係:${hasPermi('sys:user:view,sys:user:edit', 'and')}; 多個OR關係:${hasPermi('sys:user:view,sys:user:edit', 'or')}
  • cookie:獲取cookie值,${cookie(name, isRemove)}

數據類型格式化

日期格式化:

Today is ${date,dateFormat="yyyy-MM-dd"}
Today is ${date,dateFormat}
若是date爲日期類型可簡寫:
${date,「yyyy-MM-dd」}

數值格式化:

Salary is ${salary,numberFormat="##.##"}

基本控件封裝(相似Spring MVC表單標籤)

form 表單標籤

生成一個form標籤,支持指定model屬性,相似SpringMVC的<form:form modelAttribute=""/>標籤的屬性,自動給表單內的控件綁定屬性值
<#form:form id="inputForm" model="${user}" action="${ctx}/sys/user" method="POST" class="form-horizontal">
    表單內容
</#form:form>
支持上傳文件:
<#form:form id="inputForm" model="${user}" action="${ctx}/sys/user" method="POST" enctype="multipart/form-data" class="form-horizontal">
    表單內容
</#form:form>

控件屬性:

var p = {

	// 標籤參數
	id: id!,					// 表單ID
	model: model!,				// 綁定Model對象,例如:${user!}
	action: action!,			// 表單請求地址
	method: method!,			// 請求方法,默認 post
	enctype: enctype!,			// 發送以前進行數據編碼,上傳文件時指定:multipart/form-data
	
};

input 輸入框標籤

自動綁定form:form上指定的model下的userName屬性,相似SpringMVC的<form:input path=""/>標籤的屬性
<#form:input path="userName" maxlength="100" class="form-control required "/>
日期格式化:
<#form:input path="userName" maxlength="100" dataFormat="date" class="form-control required "/>
數值格式化:
<#form:input path="userName" maxlength="100" dataFormat="number" class="form-control required "/>
不自動綁定,把path改成name就能夠:
<#form:input name="userName" value="${user.userName}" maxlength="100" class="form-control required "/>

控件屬性:

var p = {

	// 標籤參數
	id: id!,					// 元素ID,若是不填寫,則與name相同
	path: path!,				// 綁定form上model中屬性的值
	name: name!,				// 元素名稱,不填寫
	value: value!,				// 元素值
	
	type: type!'text',			// 元素的類型,默認text
	
	dataFormat: dataFormat!'',	// 數據格式化,支持以下值:
								// date: 日期;
								// datetime: 日期時間;
								// number: 數值類型,保留2位小數
	
};

select 下拉框標籤

根據字典類型設置下拉數據:
<#form:select path="userType" dictType="sys_user_type" class="form-control required " />
增長一個空白選項:
<#form:select path="roleType" dictType="sys_role_type" blankOption="true" class="form-control " />
多選下拉列表:
<#form:select path="roleType" dictType="sys_role_type" multiple="true" class="form-control " />
手動設置下拉框值,相似SrpingMVC的<form:options items="" itemLabel="" itemValue=""/>標籤的屬性:
<#form:select path="moduleCodes" items="${moduleList}" itemLabel="moduleName" itemValue="moduleCode" class="form-control required" />

控件屬性:

var p = {

	// 標籤參數
	id: id!,					// 元素ID,若是不填寫,則與name相同
	path: path!,				// 綁定form上model中屬性的值
	name: name!,				// 元素名稱,不填寫
	value: value!,				// 元素值
	
	dictType: dictType!,		// 字典類型,從字典裏獲取,自動設置items、itemLabel、itemValue
	
	items: items![],			// 列表數據,可接受對象集合,如:List<DictData>
	itemLabel: itemLabel!'',	// 指定列表數據中的什麼屬性名做爲option的標籤名
	itemValue: itemValue!'',	// 指定列表數據中的什麼屬性名做爲option的value值
	
	multiple: multiple!'false', // 是否爲多選框
	
	blankOption: @ObjectUtils.toBoolean(blankOption!false), // 是否默認有個空白選擇項目
	
};

radio 輸入框標籤

相似<#form:select/>標籤的使用方法
<#form:radio path="menuType" dictType="sys_menu_type" class="form-control required" />

控件屬性:

var p = {

	// 標籤參數
	id: id!,					// 元素ID,若是不填寫,則與name相同
	path: path!,				// 綁定form上model中屬性的值
	name: name!,				// 元素名稱,不填寫
	value: value!,				// 元素值
	
	dictType: dictType!,		// 字典類型,從字典裏獲取,自動設置items、itemLabel、itemValue
	
	items: items!([]),			// 列表數據,可接受對象集合,如:List<DictData>
	itemLabel: itemLabel!'',	// 指定列表數據中的什麼屬性名做爲option的標籤名
	itemValue: itemValue!'',	// 指定列表數據中的什麼屬性名做爲option的value值
	
};

checkbox 複選框標籤

相似<#form:select/>標籤的使用方法,後臺接受moduleCodes爲字符串,選擇多個自動使用「,」分隔,相比SpringMVC必須是List方便的多
<#form:checkbox path="moduleCodes" items="${moduleList}" itemLabel="moduleName" itemValue="moduleCode" class="form-control required" />
生成一個複選框按鈕,後臺接受replaceFile爲Global.YES或Global.NO值:
<#form:checkbox path="replaceFile" label="是否替換現有文件" class="form-control"/>

控件屬性:

var p = {

	// 標籤參數
	id: id!,					// 元素ID,若是不填寫,則與name相同
	path: path!,				// 綁定form上model中屬性的值
	name: name!,				// 元素名稱,不填寫
	value: value!,				// 元素值
	
	dictType: dictType!'',		// 字典類型,從字典裏獲取,自動設置items、itemLabel、itemValue
	
	items: items!([]),			// 列表數據,可接受對象集合,如:List<DictData>
	itemLabel: itemLabel!'',	// 指定列表數據中的什麼屬性名做爲option的標籤名
	itemValue: itemValue!'',	// 指定列表數據中的什麼屬性名做爲option的value值
	
	label: label!,				// 只有一個複選按鈕的狀況下設置
	
};

textarea 文本域標籤

<#form:textarea path="remarks" rows="3" maxlength="200" class="form-control"/>

控件屬性:

var p = {

	// 標籤參數
	id: id!,					// 元素ID,若是不填寫,則與name相同
	path: path!,				// 綁定form上model中屬性的值
	name: name!,				// 元素名稱,不填寫
	value: value!,				// 元素值
	
};

hidden 隱藏域標籤

<#form:hidden path="menuCode" />

控件屬性:

var p = {
	
	// 標籤參數
	id: id!,					// 元素ID,若是不填寫,則與name相同
	path: path!,				// 綁定form上model中屬性的值
	name: name!,				// 元素名稱,不填寫
	value: value!,				// 元素值
	
	type: type!'hidden',		// 元素的類型,默認hidden
	
};

表單組件封裝

treeselect 樹結構選擇

封裝layer+zTree實現樹結構選擇組件,使用場景如:部門選擇,行政區劃選擇,欄目列表選擇等

<#form:treeselect id="parent" title="上級菜單"
    	name="parent.id" value="${menu.parent.id!}"
    	labelName="parent.menuName" labelValue="${menu.parent.menuName!}"
    	url="${ctx}/sys/menu/treeData?excludeCode=${menu.menuCode}&sysCode=${menu.sysCode}&isShowCode=2"
    	class="" allowClear="true" canSelectRoot="true" canSelectParent="true"/>

組件屬性:

var p = {
	
		// 標籤參數
		id: id!,					// 元素ID
		
		name: name!,				// 隱藏域名稱
		value: value!,				// 隱藏域值
		
		labelName: labelName!,		// 標籤框名稱
		labelValue: labelValue!,	// 標籤框值
		
		class: class!'',			// 標籤框的CSS類名
		placeholder: placeholder!,	// 標籤框的預期值的提示信息
		dataMsgRequired: thisTag.attrs['data-msg-required'],	// 必填錯誤提示信息
		
		btnClass: btnClass!,		// 標籤框後面的按鈕CSS類名
		
		title: title!'選項',			// 對話框標題
		boxWidth: boxWidth!300, 		// 對話框寬度,默認300像素
		boxHeight: boxHeight!400,		// 對話框高度,默認400像素
		
		url: url!,					// 樹結構,數據源地址 [{id, pid, name}]
		
		readonly: @ObjectUtils.toBoolean(readonly!false),		// 是否只讀模式
		
		allowInput: @ObjectUtils.toBoolean(allowInput!false),	// 是否容許label框輸入
		allowClear: @ObjectUtils.toBoolean(allowClear!true),	// 是否容許清空選擇內容
		
		checkbox: @ObjectUtils.toBoolean(checkbox!false),	// 是否顯示覆選框,是否支持多選,若是設置canSelectParent=true則返回父節點數據
		expandLevel: @ObjectUtils.toInteger(expandLevel!(-1)),		// 默認展開層次級別(默認:若是有1個根節點,則展開一級節點,不然不展開)
		
		canSelectRoot: @ObjectUtils.toBoolean(canSelectRoot!false),		// 能夠選擇跟節點
		canSelectParent: @ObjectUtils.toBoolean(canSelectParent!false),	// 能夠選擇父級節點
		
		returnFullName: @ObjectUtils.toBoolean(returnFullName!false),	// 是否返回全路徑,包含全部上級信息,以 returnFullNameSplit 參數分隔
		returnFullNameSplit: returnFullNameSplit!'/',					// 是否返回全路徑,的分隔符,默認「/」
		
	};

iconselect 圖標選擇

<#form:iconselect path="menuIcon" class=""/>

組件屬性:

var p = {
	
	// 標籤參數
	id: id!,					// 元素ID,若是不填寫,則與name相同
	path: path!,				// 綁定form上model中屬性的值
	name: name!,				// 元素名稱,不填寫
	value: value!,				// 元素值
	
	class: class!'',			// 隱藏域和標籤框的CSS類名
	
};

validcode 驗證碼

<#form:validcode name="validCode" isRequired="true" isRemote="true" />

組件屬性:

var p = {

	id: id!name,				// 驗證碼輸入框ID
	name: name!,				// 驗證碼輸入框名稱(必填)
	
	isRequired: @ObjectUtils.toBoolean(isRequired!true),	// 是否必填,默認必填
	dataMsgRequired: thisTag.attrs['data-msg-required'],	// 必填錯誤提示信息
	
	isRemote: @ObjectUtils.toBoolean(isRemote!true),		// 是否支持實時遠程驗證
	dataMsgRemote: thisTag.attrs['data-msg-remote'],		// 必填錯誤提示信息
	
	isLazy: @ObjectUtils.toBoolean(isLazy!false),			// 是否懶加載驗證碼圖片,原noRefresh參數

};

listselect 列表選擇

<#form:listselect id="userSelect" title="用戶"
	url="${ctx}/sys/user/userSelect?userType=${role.userType}" allowClear="false" 
	checkbox="true" itemCode="userCode" itemName="userName"/>

組件屬性:

var p = {

	// 標籤參數
	id: id!,					// 元素ID
	
	path: path!,				// 綁定form上model中屬性的值
	name: name!,				// 隱藏域名稱
	value: value!,				// 隱藏域值
	
	labelPath: labelPath!,		// 綁定form上model中屬性的值
	labelName: labelName!,		// 標籤框名稱
	labelValue: labelValue!,	// 標籤框值
	
	class: class!'',			// 標籤框的CSS類名
	placeholder: placeholder!,	// 標籤框的預期值的提示信息
	dataMsgRequired: thisTag.attrs['data-msg-required'],	// 必填錯誤提示信息
	
	btnClass: btnClass!,		// 標籤框後面的按鈕CSS類名
	
	title: title!'選項',			// 對話框標題
	boxWidth: boxWidth!'$(top.window).width() - 100', 		// 對話框寬度
	boxHeight: boxHeight!'$(top.window).height() - 100',	// 對話框高度 
	
	url: url!,					// 樹結構,數據源地址 [{id, pid, name}]
	
	readonly: @ObjectUtils.toBoolean(readonly!false),		// 是否只讀模式
	
	allowInput: @ObjectUtils.toBoolean(allowInput!false),	// 是否容許label框輸入
	allowClear: @ObjectUtils.toBoolean(allowClear!true),	// 是否容許清空選擇內容
	
	checkbox: @ObjectUtils.toBoolean(checkbox!false),	// 是否顯示覆選框,是否支持多選,若是設置canSelectParent=true則返回父節點數據
	
	itemCode: itemCode!,	// 選擇後結果集中的Code屬性名,返回到隱藏域的值
	itemName: itemName!,	// 選擇後結果集中的Name屬性名,返回到輸入框的值
	
};

fileupload 文件上傳

一、文件上傳:
<#form:fileupload id="upload1" bizKey="${user.id}" bizType="user_upload1"
	uploadType="all" class="required" readonly="false"/>
後臺代碼:FileUploadUtils.saveFileUpload(user.getId(), "user_upload1");

二、圖片上傳:
<#form:fileupload id="upload2" bizKey="${user.id}" bizType="user_upload2"
	uploadType="image" class="required" readonly="false"/>
後臺代碼:FileUploadUtils.saveFileUpload(user.getId(), "user_upload2");

三、返回路徑:
<#form:fileupload id="upload3" returnPath="true"
	filePathInputId="upload3Path" fileNameInputId="upload3Name"
	uploadType="image" readonly="false" maxUploadNum="3" isMini="false"/>
<#form:input name="upload3Path" class="form-control"/>
<#form:input name="upload3Name" class="form-control"/>

組件屬性:

var p = {

	// 標籤參數
	id: id!,					// 元素ID
	
	bizKey: bizKey!,			// 業務表的主鍵值(與附件關聯的業務數據)
	bizType: bizType!,			// 業務表的上傳類型(全網惟一,推薦格式:實體名_上傳類型,例如,文章圖片:article_photo)
	
	returnPath: @ObjectUtils.toBoolean(returnPath!false), 	// 是不是返回文件路徑到輸入框(默認false),可將路徑直接保存到某個字段裏
	filePathInputId: filePathInputId!,	// 設置文件URL存放的輸入框的ID,當returnPath爲true的時候,返回文件URL到這個輸入框
	fileNameInputId: fileNameInputId!,	// 設置文件名稱存放的輸入框的ID,當returnPath爲true的時候,返回文件名稱到這個輸入框
	
	uploadType: uploadType!'',			// 上傳文件類型:all、file、image、media,若不設置,則自動根據上傳文件後綴獲取
	class: class!'',					// 標籤框的CSS類名,設置 required 加入必填驗證
	readonly: @ObjectUtils.toBoolean(readonly!false),		// 是否只讀模式,只讀模式下爲查看模式,只容許下載
	
	allowSuffixes: allowSuffixes!'', 	// 容許上傳的後綴,前臺的限制,不能超越file.*AllowSuffixes的設置,例如:.jpg,.png,
	maxUploadNum: @ObjectUtils.toInteger(maxUploadNum!300),		// 多文件下容許最多上傳幾個,默認300個,設置-1表明不限制
	
	imageMaxWidth: @ObjectUtils.toInteger(imageMaxWidth!1024),	// 圖片壓縮,最大寬度(uploadType爲image生效),設置-1表明不作任何處理
	imageMaxHeight: @ObjectUtils.toInteger(imageMaxHeight!768),	// 圖片壓縮,最大寬度(uploadType爲image生效),設置-1表明不作任何處理
	
	isLazy: @ObjectUtils.toBoolean(isLazy!false),				// 設置爲ture須要點擊上傳按鈕才上傳文件,不然選擇後就直接上傳
	
	isMini: @ObjectUtils.toBoolean(isMini!false),				// 是不是精簡上傳窗口,無邊距,無邊框
	
	preview: preview!'',										// 是否顯示預覽按鈕,接受參數:weboffice
	
};

imageclip 圖片裁剪

<img id="avatarImg" class="profile-user-img img-responsive img-circle"
    src="${@user.getAvatarUrl().replaceFirst('/ctxPath', ctxPath)}">
<#form:imageclip name="imageBase64" btnText="修改頭像" btnClass="btn-block"
	imageId="avatarImg" imageDefaultSrc="${ctxStatic+'/images/user1.jpg'}"
	circle="true"/>
後臺代碼:
// 若是設置了頭像,則保存頭像
if (StringUtils.isNotBlank(imageBase64)){
	if ("EMPTY".equals(imageBase64)){
		user.setAvatar(StringUtils.EMPTY);
	}else{
		String imageUrl = "avatar/"+user.getUserCode()
				+"."+FileUtils.getFileExtensionByImageBase64(imageBase64);
		String fileName = Global.getUserfilesBaseDir(imageUrl);
		FileUtils.writeToFileByImageBase64(fileName, imageBase64);
		user.setAvatar(Global.USERFILES_BASE_URL + imageUrl);
	}
}

組件屬性:

var p = {

	// 標籤參數
	id: id!,					// 元素ID,若是不填寫,則與name相同
	path: path!,				// 綁定form上model中屬性的值
	name: name!,				// 元素名稱,不填寫
	value: value!,				// 元素值
	
	class: class!'',			// 隱藏域的CSS類名
	
	btnText: btnText!'選擇圖片',	// 按鈕的名字
	btnClass: btnClass!'',		// 按鈕的CSS類名
	
	imageId: imageId!'',					// 裁剪後base64返回到img的id
	imageDefaultSrc: imageDefaultSrc!'',	// 圖片默認地址,清除後使用地址
	
	circle: circle!'false', 	// 是否圓形圖片
	
};

ueditor 富文本在線編輯器

<#form:ueditor name="text" maxlength="10000" height="200" class="required"
	simpleToolbars="false" readonly="false" outline="false"/>

組件屬性:

var p = {

	// 標籤參數
	id: id!,				// 元素ID,若是不填寫,則與name相同
	path: path!,			// 綁定form上model中屬性的值
	name: name!,			// 元素名稱,不填寫
	value: value!,			// 元素值
	
	class: class!'',		// 標籤框的CSS類名,設置 required 加入必填驗證
	
	maxlength: maxlength!'',	// 編輯器最大輸入字數,爲空表明無限制
	height: height!'200',		// 編輯器的高度,默認200
	
	simpleToolbars: @ObjectUtils.toBoolean(simpleToolbars!false), // 是不是簡單的工具條
	
	readonly: @ObjectUtils.toBoolean(readonly!false), 	// 是否只讀模式
	
	outline: @ObjectUtils.toBoolean(outline!false), 	// 大綱視圖
	
	options: options!'',	// UE附加選項,逗號隔開。
	
};

封裝通用JavaScript方法

/**
 * 輸出日誌
 */
log(msg);

/**
 * 輸出錯誤日誌
 */
error(msg);

/**
 * URL 編碼
 */
js.encodeUrl(url);

/**
 * URL 解碼
 */
js.decodeUrl(url);

/**
 * 獲得 IE 版本,若是是IE返回:IE版本號,不然返回:false
 * if (js.ie && js.ie <= 8){ alert('瀏覽器版本太低') }
 */
js.ie;

/**
 * 安全取值,複雜類型或嵌套類型時,取不到屬性中的屬性時不拋出異常
 * js.val(jsonObj, 'user.office.name');
 */
js.val(jsonObj, attrName);

/**
 * 返回HashCode惟一值(默認忽略大小寫)
 * @param str 要獲取的字符串HashCode值
 * @param caseSensitive 是否大小寫敏感(默認false)
 * @usage js.hashCode(str);
 */
js.hashCode(str, caseSensitive);

/**
 * 異步加載文件,loadFile v1.0
 * js.loadFile(file文件路徑, callback成功回調, error失敗回調)
 * js.loadFile('js/test.js',function(){},function(data){});
 * js.loadFile(['js/test.js','css/test.css'],function(){},function(data){});
 */
js.loadFile(file, callback, error);

/**
 * 打開一個Window窗體
 */
js.windowOpen(url, name, width, height);

/**
 * 關閉當前Window窗體
 */
js.windowClose();

/**
 * 給URL地址添加參數,若是原來有參數則用&前綴,若是沒有則用?前綴
 */
js.addParam(url, params);

/**
 * 獲取URL地址的參數
 */
js.getParam(paramName, url);

/**
 * 查看Object的內容,手機調試用
 * @param obj
 */
js.alertObj(obj);

/**
 * 獲取字典標籤
 * js.getDictLabel(${@DictUtils.getDictListJson('sys_menu_type')}, val, '未知', true)
 */
js.getDictLabel(dictListJson, value, defaultValue, inCss);

/////////////////////////////////////// message dialog

/**
 * 顯示加載框
 * @param message 加載框提示信息
 * @param ignoreMessageIfExists 若是已經有加載框如今,則忽略message信息的設置
 * @usage js.loading('正在保存...');
 */
js.loading(message, ignoreMessageIfExists);

/**
 * 關閉加載框
 * @param timeout 關閉延遲時間
 * @param forceClose 是否強制關閉
 * @usage js.closeLoading(1000, true);
 */
js.closeLoading(timeout, forceClose);

/**
 * 獲得layer對話框對象
 * js.layer.msg();
 */
js.layer;

/**
 * 顯示提示框
 * @param message 提示消息
 * @param title 提示標題
 * @param type 提示類型(success、error、warning、info)
 * @param timeout 自動關閉毫秒(默認4000毫秒)
 */
js.showMessage(message, title, type, timeout);

/**
 * 顯示錯誤提示框
 */
js.showErrorMessage(responseText);

/**
 * 關閉提示框
 */
js.closeMessage();

/**
 * 提示對話框
 * @param message 提示消息
 * @param options 對話框選項
 * @param closed 對話框關閉回調方法
 * @usage js.alert('你好!', function(){})
 * @usage js.alert('你好!', {icon: 2}, function(){})
 */
js.alert(message, options, closed);

/**
 * 確認對話框
 * @param message 確認信息
 * @param urlOrFun 確認後的跳轉的地址,或調用的方法
 * @param data 若是urlOrFun是地址,該參數是調用地址的參數信息
 * @param callback 執行ajax的回調方法,若是爲空,則直接經過location=urlOrFun跳轉。
 * @param dataType 返回數據類型(默認json)
 * @param async 是否異步(默認true)
 * @param loadingMessage 調用loading(loadingMessage)的提示信息。
 * @usage js.confirm('確認刪除嗎?', '$ctx/biz/delete?id=123', function(data){alert('刪除成功')}, 'json', true, '正在刪除...');
 * @usage js.confirm('確認刪除嗎?', '$ctx/biz/delete', {id: '123'}, function(data){alert('刪除成功')}, 'json', true, '正在刪除...');
 * @usage js.confirm('確認刪除嗎?', function(data){alert('刪除成功')});
 */
js.confirm(message, urlOrFun, data, callback, dataType, async, loadingMessage);

/////////////////////////////////////// js template

/**
 * 根據js模板生成代碼,使用laytpl引擎
 * @param id 模板ID
 * @param data 模板數據(可選)
 * @param callback 若是填寫,則爲異步渲染
 * @usage 
 * 		模板格式: <sc ript id="dempTpl" type="text/template">//<!--
 * 					 這裏寫模塊內容...
 * 				//--></sc ript>
 * 		調用方法: js.template('dempTpl', data);
 * 		模版語法:
 * 			輸出一個普通字段,不轉義html:   {{ d.field }}
 * 			輸出一個普通字段,並轉義html:   {{= d.field }}
 * 			JavaScript腳本: {{# JavaScript statement }}
 */
js.template(id, data, callback);

/////////////////////////////////////// ajax form

/**
 * AJAX 提交
 * js.ajaxSubmit('/sys/user/save', {param: 1}, function(data){})
 */
js.ajaxSubmit(url, data, callback, dataType, async, message);

/**
 * AJAX 提交表單(支持文件上傳)
 * js.ajaxSubmitForm($(form), function(data){})
 */
js.ajaxSubmitForm(formJqueryObj, callback, dataType, async, message);

/////////////////////////////////////// string

/**
 * String兩邊去空格
 */
js.trim(str);

/**
 * String的startWith
 */
js.startWith(str, start);

/**
 * String的endWith
 */
js.endWith(str, end);

/**
 * 截取字符串,區別漢字和英文
 */
js.abbr(name, maxLength);

/////////////////////////////////////// number

/**
 * 格式化數值
 * @param num 待格式化的樹
 * @param cent 保留小數位數
 * @param isThousand 是否進行千分位格式化
 */
js.formatNumber(num, cent, isThousand);

/**
 * 金額格式化(千位符,小數四捨五入)金額每隔三位加一個逗號
 * @param s 要格式化的數值
 * @param n 小數位數
 */
js.formatMoney(s, n);

/**
 * 數值前補零
 */
js.numberPad(num, n);

/////////////////////////////////////// date

/**
 * 日期格式化
 * @param date 日期 new Date()
 * @param f 格式化字符串 yyyy-MM-dd HH:mm:ss
 */
js.formatDate(date, f);

/**
 * 字符串轉爲日期
 * @param date
 */
js.parseDate(date);

/**
 * 日期加減
 * @param date
 * @param dadd 天數
 */
js.addDate(date, dadd);

/**
 * 快速選擇日期方法
 * @param type 1今日,2本週,3本月,4本季度,5上月
 * @param beginDateId 開始日期控件的ID
 * @param endDateId	 結束日期控件的ID
 */
js.quickSelectDate(type, beginDateId, endDateId);

/////////////////////////////////////// cookie

/**
 * cookie 操做
 * @param name Cookie名稱
 * @param value Cookie值,填寫表示設置,不填寫表示獲取
 * @parma options:{expires:7} 若是是數字,則expires單位爲天。
 */
js.cookie(name, value, options);

/////////////////////////////////////// tabPage

/**
 * 獲得TabPage對象
 */
js.tabPage;

/**
 * 初始化TAB頁面
 * @param id
 */
js.initTabPage(id, options);

/**
 * 添加TAB頁面
 * @param $this 		點擊的對象
 * @param title 		提示標題
 * @param url	 		訪問的路徑
 * @param closeable	 	是否有關閉按鈕
 * @param refresh 		打開後是否刷新從新加載
 */
js.addTabPage($this, title, url, closeable, refresh);

/**
 * 獲取當前TAB頁面
 * @param currentTabCallback(contents, contentWindow) 當前頁面回調方法,傳入當前tab頁面的contents和contentWindow
 */
js.getCurrentTabPage(currentTabCallback);

/**
 * 獲取當前頁面的上一個TAB頁面,並激活上級頁面
 * @param preTabCallback(contents, contentWindow) 傳入上一個tab頁面的contents和contentWindow
 * @param isCloseCurrentTab 是否關閉當前頁籤
 */
js.getPrevTabPage(preTabCallback, isCloseCurrentTab);

/**
 * 關閉當前TAB頁面,並激活上級頁面
 * @param preTabCallback(contents, contentWindow) 關閉前的回調方法,傳入上一個tab頁面的contents和contentWindow
 */
js.closeCurrentTabPage(preTabCallback);

封裝數據表格組件DataGrid

數據表格是一個必不可少的元素,在選擇這個選型的時候嘗試了不少開源組件,最終選擇jqGrid,只是由於它接近經典思惟,用着還算順手,最主要的是碰見什麼問題均可以自行解決和修復問題,有人說jqGrid很差看,這不要緊這徹底而已自行編寫CSS改造它,下面看看一個簡單的例子:

<#form:form id="searchForm" model="${config}" action="${ctx}/sys/config/listData" method="post" class="form-inline "
		data-page-no="${parameter.pageNo}" data-page-size="${parameter.pageSize}" data-order-by="${parameter.orderBy}">
	參數名稱:<#form:input path="configName" maxlength="100" class="form-control" />
	參數鍵名:<#form:input path="configKey_like" maxlength="100" class="form-control" />
	<button type="submit" class="btn btn-primary btn-sm">查詢</button>
	<button type="reset" class="btn btn-default btn-sm">重置</button>
</#form:form>
<table id="dataGrid"></table>
<div id="dataGridPage"></div>
// 初始化DataGrid對象
$('#dataGrid').dataGrid({
    // 查詢數據表單
    searchForm: $('#searchForm'),
	// 設置數據表格列
	columnModel: [ 
		{header:'參數名稱', name:'configName', index:'a.config_name', width:200, formatter: function(val, obj, row, act){
			return '<a href="${ctx}/sys/config/form?id='+row.id+'" class="btnList" data-title="編輯參數">'+val+'</a>';
		}},
		{header:'參數鍵名', name:'configKey', index:'a.config_key', width:200},
		{header:'參數鍵值', name:'configValue', sortable:false, width:260, classes:"nowrap"},
		{header:'操做', name:'actions', width:100, sortable:false, title:false, formatter: function(val, obj, row, act){
			var actions = [];
			<% if(hasPermi('sys:config:edit')){ %>
				actions.push('<a href="${ctx}/sys/config/form?id='+row.id+'" class="btnList" title="編輯參數"><i class="fa fa-pencil"></i></a>&nbsp;');
			<% } %>
			<% if(hasPermi('sys:config:delete')){ %>
				actions.push('<a href="${ctx}/sys/config/delete?id='+row.id+'" class="btnList" title="刪除參數" data-confirm="確認要刪除該參數嗎?"><i class="fa fa-trash-o"></i></a>&nbsp;');
			<% } %>
			return actions.join('');
		}}
	],
	// 加載成功後執行事件
	ajaxSuccess: function(data){
		
	}
});

是否是比你使用foreach方便的多,封裝後名字叫dataGrid,這只是展現了冰山一角,它支持全部jqGrid參數,即簡化了代碼編寫,又不失功能

提供豐富的演示例子

  • AdminLTE 2.4
  • Bootstrap 3.3
  • Layer 3.0
  • My97DatePicker 4.8
  • jQurey Select2 4.0
  • jQurey Validation 1.16
  • jQurey zTree API 3.5
  • jQurey zTree Demo 3.5
  • jQuery jqGrid 4.7
相關文章
相關標籤/搜索