一個不得不說的話題,通過近幾年的發展,Web前端開發已經不是一個新有的崗位了,前端技術發展很是迅速,技術更新換代也很快,對於前端工程師來講是一個很大的挑戰「掙扎期」。javascript
從統計來看,中級前端的待遇是略高於中級後端的。這對於中小企業、創業公司來講組建一個專有的前端團隊仍是很一件很不容易的事情,無形中增長了人力成本, 話說招前端工程師簡單,但能招聘到合適的前端工程師來講,是一件很是不容易的事情。css
爲了解決這個事情,中小企業、創業公司都在思考一個問題,作企業應用軟件,若是不去組建專門的前端團隊,能有一個很好的開發平臺,很好的框架,讓後端工程師具有一些基本的前端知識,就能夠去作出很漂亮的界面就行了。html
這個想法很好,可是你會說,可能嗎,會一點基礎前端就能作好嗎?專業的事情仍是有專業的人來作,先後端分離是趨勢,表現邏輯分離意義很大。沒有絕對完美的事情,儘管種種誘惑,惟心自問合適本身嗎?我不否定,這還要針對產品、針對項目來選擇解決方案。但JeeSite的中心思想是快速快發,快速交付,控制成本,對於一個想快速交付項目來講不見得是一件好事。前端
重口難調,也許你不贊同這些見解,做者歡迎提問,固然你也能夠將JeeSite徹底做爲服務端代碼,快速提供數據接口,自由實現或選型一套前端UI。java
好了,既然是奔着快速交付,控制成原本的,咱們就依這個角度去思考方案:web
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
bodyClass參數: 設置body的class屬性值
如下工具類可經過@類型快速調用,如:${@Global.getConfig('key')}
如下是Beetl函數及擴展函數
數據類型格式化
日期格式化:
Today is ${date,dateFormat="yyyy-MM-dd"} Today is ${date,dateFormat} 若是date爲日期類型可簡寫: ${date,「yyyy-MM-dd」}
數值格式化:
Salary is ${salary,numberFormat="##.##"}
生成一個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 };
自動綁定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位小數 };
根據字典類型設置下拉數據: <#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), // 是否默認有個空白選擇項目 };
相似<#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值 };
相似<#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!, // 只有一個複選按鈕的狀況下設置 };
<#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!, // 元素值 };
<#form:hidden path="menuCode" />
控件屬性:
var p = { // 標籤參數 id: id!, // 元素ID,若是不填寫,則與name相同 path: path!, // 綁定form上model中屬性的值 name: name!, // 元素名稱,不填寫 value: value!, // 元素值 type: type!'hidden', // 元素的類型,默認hidden };
封裝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!'/', // 是否返回全路徑,的分隔符,默認「/」 };
<#form:iconselect path="menuIcon" class=""/>
組件屬性:
var p = { // 標籤參數 id: id!, // 元素ID,若是不填寫,則與name相同 path: path!, // 綁定form上model中屬性的值 name: name!, // 元素名稱,不填寫 value: value!, // 元素值 class: class!'', // 隱藏域和標籤框的CSS類名 };
<#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參數 };
<#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屬性名,返回到輸入框的值 };
一、文件上傳: <#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 };
<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', // 是否圓形圖片 };
<#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附加選項,逗號隔開。 };
/** * 輸出日誌 */ 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);
數據表格是一個必不可少的元素,在選擇這個選型的時候嘗試了不少開源組件,最終選擇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> '); <% } %> <% 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> '); <% } %> return actions.join(''); }} ], // 加載成功後執行事件 ajaxSuccess: function(data){ } });
是否是比你使用foreach方便的多,封裝後名字叫dataGrid,這只是展現了冰山一角,它支持全部jqGrid參數,即簡化了代碼編寫,又不失功能