JeeSite 4.0 说说前端的那些事
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
引言
一個(gè)不得不說的話題,經(jīng)過近幾年的發(fā)展,Web前端開發(fā)已經(jīng)不是一個(gè)新有的崗位了,前端技術(shù)發(fā)展非常迅速,技術(shù)更新?lián)Q代也很快,對(duì)于前端工程師來說是一個(gè)很大的挑戰(zhàn)“掙扎期”。
從統(tǒng)計(jì)來看,中級(jí)前端的待遇是略高于中級(jí)后端的。這對(duì)于中小企業(yè)、創(chuàng)業(yè)公司來說組建一個(gè)專有的前端團(tuán)隊(duì)還是很一件很不容易的事情,無形中增加了人力成本, 話說招前端工程師簡(jiǎn)單,但能招聘到合適的前端工程師來說,是一件非常不容易的事情。
為了解決這個(gè)事情,中小企業(yè)、創(chuàng)業(yè)公司都在思考一個(gè)問題,做企業(yè)應(yīng)用軟件,如果不去組建專門的前端團(tuán)隊(duì),能有一個(gè)很好的開發(fā)平臺(tái),很好的框架,讓后端工程師具備一些基本的前端知識(shí),就可以去做出很漂亮的界面就好了。
這個(gè)想法很好,但是你會(huì)說,可能嗎,會(huì)一點(diǎn)基礎(chǔ)前端就能做好嗎?專業(yè)的事情還是有專業(yè)的人來做,前后端分離是趨勢(shì),表現(xiàn)邏輯分離意義很大。沒有絕對(duì)完美的事情,盡管種種誘惑,唯心自問合適自己?jiǎn)?#xff1f;我不否認(rèn),這還要針對(duì)產(chǎn)品、針對(duì)項(xiàng)目來選擇解決方案。但JeeSite的中心思想是快速快發(fā),快速交付,控制成本,對(duì)于一個(gè)想快速交付項(xiàng)目來說不見得是一件好事。
重口難調(diào),也許你不贊同這些看法,作者歡迎提問,當(dāng)然你也可以將JeeSite完全作為服務(wù)端代碼,快速提供數(shù)據(jù)接口,自由實(shí)現(xiàn)或選型一套前端UI。
好了,既然是奔著快速交付,控制成本來的,我們就依這個(gè)角度去思考方案:
- 第一,技術(shù)選型 Spring MVC + Beetl + jQuery + Bootstrap,優(yōu)勢(shì)很明顯,不多說,下面章節(jié)簡(jiǎn)要說下;
- 第二,開發(fā)一些常用函數(shù)庫,如:字符串工具類,集合工具類,映射轉(zhuǎn)換工具類,配置工具類,權(quán)限用戶工具類等;
- 第三,封裝一些常用表單控件參考Spring MVC的form標(biāo)簽,實(shí)現(xiàn)更便捷的輸入框、下拉框、單選、復(fù)選等,自動(dòng)進(jìn)行數(shù)據(jù)綁定;
- 第四,封裝一些常用表單組件,如:多級(jí)樹結(jié)構(gòu)選擇組件,列表選擇組件,文件上傳組件,驗(yàn)證碼生成組件等等;
- 第五,封裝一些常用JS類庫,如:動(dòng)態(tài)加載,對(duì)話框,消息框,加載框,JS模板,Ajax,格式化,動(dòng)態(tài)Tab等待;
- 第六,封裝一個(gè)JS數(shù)據(jù)表格組件DataGrid,分頁,排序,多表頭,分組,子表,凍結(jié),小計(jì),合計(jì),編輯行,樹表表格等;
- 第七,豐富例子,如:Box盒子、表單布局、柵格布局、圖表等等
模板語言界定符選擇
Beetl模板語言類似JS語言和習(xí)俗,只需要將Beetl語言放入定界符號(hào)里即可,如默認(rèn)的是<% %>,那JeeSite是怎樣選擇的呢:
設(shè)想定義:<% %>
優(yōu)點(diǎn):jsp標(biāo)準(zhǔn)定界符,比較容易被理解,是后端運(yùn)行的語法
缺點(diǎn):html后綴的模板,不能和html標(biāo)簽混用,否則IDE會(huì)提示語法錯(cuò)誤
設(shè)想定義:@ 回車符
優(yōu)點(diǎn):簡(jiǎn)單
缺點(diǎn):多行beetl語法時(shí),比較麻煩,并且會(huì)出現(xiàn)多余的很多空格空行
設(shè)想定義:[ ]、[@ ]、[@ ]
有點(diǎn):可以和html混用
缺點(diǎn):與js的[]沖突,必須使用\轉(zhuǎn)義
**設(shè)想定義:[@ @]、[# #]、# #、@ @**
優(yōu)點(diǎn):基本沒有標(biāo)示符沖突
缺點(diǎn):感官、閱讀、寫法稍微差點(diǎn)
設(shè)想定義:<!--# -->、<!--: -->
優(yōu)點(diǎn):使用html注釋,沒有標(biāo)示符沖突
缺點(diǎn):使用IDE高亮?xí)r,沒有寫代碼的感覺,像是在寫注釋
最終選擇:<% %>
經(jīng)過上述分析,最終還是回歸默認(rèn),使用jsp標(biāo)準(zhǔn)定界符<%%>來作為模板語言的定界符,一方同比較容易被理解,明確是后端運(yùn)行的語法,另一方面沖突少,邊界比較好界定
寫一個(gè)通用布局的頁面
<% 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> <% } %>調(diào)用默認(rèn)布局 /layouts/default.html,自動(dòng)引入頁面頭部和尾部?jī)?nèi)容,通過參數(shù)設(shè)置要加載的css和js類庫,參數(shù)如下:
title參數(shù): 設(shè)置頁面的標(biāo)題名字
libs參數(shù): 設(shè)置頁面要引入的css和js類庫,支持類庫如下:
默認(rèn)引入:layer、select2、WdatePicker
- zTree:樹結(jié)構(gòu)控件
- tabPage:動(dòng)態(tài)頁簽插件
- dataGrid:數(shù)據(jù)表格組件
- validate:表單驗(yàn)證組件
- inputmask:表單格式化工具
- fileupload:文件上傳插件
- ueditor:富文本編輯器控件
bodyClass參數(shù): 設(shè)置body的class屬性值
定義常用函數(shù)庫
常用工具類導(dǎo)入
以下工具類可通過@類型快速調(diào)用,如:${@Global.getConfig('key')}
- Global:全局配置類,全局常量,讀取屬性文件參數(shù)值等
- EncodeUtils:封裝各種格式的編碼解碼工具類,HEX、Base64、HTML、URL、XSS過濾、SQL過濾等
- ListUtils:List常用工具類,繼承Apache的ListUtils,New工具、快速提取屬性值、類型轉(zhuǎn)換等
- MapUtils:Map常用工具類,繼承Apache的MapUtils,New工具、Map與Bean互轉(zhuǎn)等
- SetUtils:Set常用工具類,繼承Apache的SetUtils,New工具等
- IdGenerate:封裝各種生成唯一性ID算法的工具類,生成LongUUID,StringUUID,Code生成等
- ByteUtils:字節(jié)轉(zhuǎn)換工具
- DateUtils:日期工具類,繼承Apache的DateUtils
- NumberUtils:BigDecimal工具類,繼承Apache的NumberUtils類
- ObjectUtils:對(duì)象操作工具類,繼承Apache的ObjectUtils類
- StringUtils:字符串工具類,繼承Apache的StringUtils類
- TimeUtils:時(shí)間計(jì)算工具類,xx天xx時(shí)xx分xx秒,剛剛,xx秒,xx分鐘,xx小時(shí)前、xx天前
- WorkDayUtils:工作日計(jì)算工具類,計(jì)算日期直接的工作日等
- BeanMapper:簡(jiǎn)單封裝Dozer,對(duì)象數(shù)據(jù)映射
- JaxbMapper:Jaxb實(shí)現(xiàn)XML與Java Object的轉(zhuǎn)換
- JsonMapper:簡(jiǎn)單封裝Jackson,實(shí)現(xiàn)Json與Java Object的轉(zhuǎn)換
- ClassUtils:Class掃描工具類,根據(jù)接口查詢類,根據(jù)繼承查詢類等
- ReflectUtils:反射工具類,方便進(jìn)行g(shù)etter/setter方法, 訪問私有變量, 調(diào)用私有方法
- ModuleUtils:模塊工具類,方便獲取系統(tǒng)模塊信息
- UserUtils:用戶工具類,方便獲取進(jìn)行用戶及相關(guān)信息
以下是Beetl函數(shù)及擴(kuò)展函數(shù)
- date:返回一個(gè)java.util.Date類型的變量,如 date() 返回一個(gè)當(dāng)前時(shí)間(對(duì)應(yīng)java的java.util.Date); ${date( "2011-1-1" , "yyyy-MM-dd" )} 返回指定日期
- print:打印一個(gè)對(duì)象 print(user.name);
- println:打印一個(gè)對(duì)象以及回車換行符號(hào),回車換號(hào)符號(hào)使用的是模板本身的,而不是本地系統(tǒng)的.如果僅僅打印一個(gè)換行符,則直接調(diào)用println() 即可
- nvl:函數(shù)nvl,如果對(duì)象為null,則返回第二個(gè)參數(shù),否則,返回自己 nvl(user,"不存在")
- isEmpty:判斷變量或者表達(dá)式是否為空,變量不存在,變量為null,變量是空字符串,變量是空集合,變量是空數(shù)組,此函數(shù)都將返回true
- isNotEmpty:同上,判斷對(duì)象是否不為空
- has:變量名為參數(shù),判斷是否存在此全局變量,如 has(userList),類似于1.x版本的exist("userList"),但不需要輸入引號(hào)了
- assert:如果表達(dá)式為false,則拋出異常
- trim:截取數(shù)字或者日期,返回字符,如trim(12.456,2)返回"12.45",trim(date,'yyyyy')返回"2017"
- trunc:截取數(shù)字,保留指定的小數(shù)位,如trunc(12.456,2) 輸出是12.45.不推薦使用,因?yàn)樘幚韋loat有問題,兼容原因保留了
- decode:一個(gè)簡(jiǎn)化的if else 結(jié)構(gòu),如 decode(a,1,"a=1",2,"a=2","不知道了")},如果a是1,這decode輸出"a=1",如果a是2,則輸出"a==2", 如果是其他值,則輸出"不知道了"
- debug:在控制臺(tái)輸出debug指定的對(duì)象以及所在模板文件以及模板中的行數(shù),如debug(1),則輸出1 [在3行@/org/beetl/core/lab/hello.txt],也可以輸出多個(gè),如debug("hi",a),則輸出hi,a=123,[在3行@/org/beetl/core/lab/hello.txt]
- range:接收三個(gè)參數(shù),初始值,結(jié)束值,還有步增(可以不需要,則默認(rèn)為1),返回一個(gè)Iterator,常用于循環(huán)中,如for(var i in range(1,5)) {print(i)},將依次打印1234.
- flush:強(qiáng)制io輸出。
- pageCtx:僅僅在web開發(fā)中,設(shè)置一個(gè)變量,然后可以在頁面渲染過程中,調(diào)用此api獲取,如pageCtx("title","用戶添加頁面"),在其后任何地方,可以pageCtx("title") 獲取該變量
- cookie:返回指定的cookie對(duì)象 ,如var userCook = cookie("user"), allCookies = cookie();
- isBlank:判斷對(duì)象是否是一個(gè)空字符串,${isBlank('str')}
- isNotBlank:判斷對(duì)象是否不是一個(gè)空字符串,${isBlank('str')}
- toJson:將對(duì)象轉(zhuǎn)Json字符串,${toJson(Object)}
- fromJson:將Json字符串轉(zhuǎn)換為對(duì)象,${fromJson(Object)}
- hasPermi:判斷是否有改權(quán)限;單個(gè)權(quán)限驗(yàn)證:${hasPermi('sys:user:edit')};多個(gè)AND關(guān)系:${hasPermi('sys:user:view,sys:user:edit', 'and')}; 多個(gè)OR關(guān)系:${hasPermi('sys:user:view,sys:user:edit', 'or')}
- cookie:獲取cookie值,${cookie(name, isRemove)}
數(shù)據(jù)類型格式化
日期格式化:
Today is ${date,dateFormat="yyyy-MM-dd"} Today is ${date,dateFormat} 如果date為日期類型可簡(jiǎn)寫: ${date,“yyyy-MM-dd”}數(shù)值格式化:
Salary is ${salary,numberFormat="##.##"}基本控件封裝(類似Spring MVC表單標(biāo)簽)
form 表單標(biāo)簽
生成一個(gè)form標(biāo)簽,支持指定model屬性,類似SpringMVC的<form:form modelAttribute=""/>標(biāo)簽的屬性,自動(dòng)給表單內(nèi)的控件綁定屬性值 <#form:form id="inputForm" model="${user}" action="${ctx}/sys/user" method="POST" class="form-horizontal">表單內(nèi)容 </#form:form> 支持上傳文件: <#form:form id="inputForm" model="${user}" action="${ctx}/sys/user" method="POST" enctype="multipart/form-data" class="form-horizontal">表單內(nèi)容 </#form:form>控件屬性:
var p = {// 標(biāo)簽參數(shù)id: id!, // 表單IDmodel: model!, // 綁定Model對(duì)象,例如:${user!}action: action!, // 表單請(qǐng)求地址method: method!, // 請(qǐng)求方法,默認(rèn) postenctype: enctype!, // 發(fā)送之前進(jìn)行數(shù)據(jù)編碼,上傳文件時(shí)指定:multipart/form-data};input 輸入框標(biāo)簽
自動(dòng)綁定form:form上指定的model下的userName屬性,類似SpringMVC的<form:input path=""/>標(biāo)簽的屬性 <#form:input path="userName" maxlength="100" class="form-control required "/> 日期格式化: <#form:input path="userName" maxlength="100" dataFormat="date" class="form-control required "/> 數(shù)值格式化: <#form:input path="userName" maxlength="100" dataFormat="number" class="form-control required "/> 不自動(dòng)綁定,把path改為name就可以: <#form:input name="userName" value="${user.userName}" maxlength="100" class="form-control required "/>控件屬性:
var p = {// 標(biāo)簽參數(shù)id: id!, // 元素ID,如果不填寫,則與name相同path: path!, // 綁定form上model中屬性的值name: name!, // 元素名稱,不填寫value: value!, // 元素值type: type!'text', // 元素的類型,默認(rèn)textdataFormat: dataFormat!'', // 數(shù)據(jù)格式化,支持如下值:// date: 日期;// datetime: 日期時(shí)間;// number: 數(shù)值類型,保留2位小數(shù)};select 下拉框標(biāo)簽
根據(jù)字典類型設(shè)置下拉數(shù)據(jù): <#form:select path="userType" dictType="sys_user_type" class="form-control required " /> 增加一個(gè)空白選項(xiàng): <#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 " /> 手動(dòng)設(shè)置下拉框值,類似SrpingMVC的<form:options items="" itemLabel="" itemValue=""/>標(biāo)簽的屬性: <#form:select path="moduleCodes" items="${moduleList}" itemLabel="moduleName" itemValue="moduleCode" class="form-control required" />控件屬性:
var p = {// 標(biāo)簽參數(shù)id: id!, // 元素ID,如果不填寫,則與name相同path: path!, // 綁定form上model中屬性的值name: name!, // 元素名稱,不填寫value: value!, // 元素值dictType: dictType!, // 字典類型,從字典里獲取,自動(dòng)設(shè)置items、itemLabel、itemValueitems: items![], // 列表數(shù)據(jù),可接受對(duì)象集合,如:List<DictData>itemLabel: itemLabel!'', // 指定列表數(shù)據(jù)中的什么屬性名作為option的標(biāo)簽名itemValue: itemValue!'', // 指定列表數(shù)據(jù)中的什么屬性名作為option的value值multiple: multiple!'false', // 是否為多選框blankOption: @ObjectUtils.toBoolean(blankOption!false), // 是否默認(rèn)有個(gè)空白選擇項(xiàng)目};radio 輸入框標(biāo)簽
類似<#form:select/>標(biāo)簽的使用方法 <#form:radio path="menuType" dictType="sys_menu_type" class="form-control required" />控件屬性:
var p = {// 標(biāo)簽參數(shù)id: id!, // 元素ID,如果不填寫,則與name相同path: path!, // 綁定form上model中屬性的值name: name!, // 元素名稱,不填寫value: value!, // 元素值dictType: dictType!, // 字典類型,從字典里獲取,自動(dòng)設(shè)置items、itemLabel、itemValueitems: items!([]), // 列表數(shù)據(jù),可接受對(duì)象集合,如:List<DictData>itemLabel: itemLabel!'', // 指定列表數(shù)據(jù)中的什么屬性名作為option的標(biāo)簽名itemValue: itemValue!'', // 指定列表數(shù)據(jù)中的什么屬性名作為option的value值};checkbox 復(fù)選框標(biāo)簽
類似<#form:select/>標(biāo)簽的使用方法,后臺(tái)接受moduleCodes為字符串,選擇多個(gè)自動(dòng)使用“,”分隔,相比SpringMVC必須是List方便的多 <#form:checkbox path="moduleCodes" items="${moduleList}" itemLabel="moduleName" itemValue="moduleCode" class="form-control required" /> 生成一個(gè)復(fù)選框按鈕,后臺(tái)接受replaceFile為Global.YES或Global.NO值: <#form:checkbox path="replaceFile" label="是否替換現(xiàn)有文件" class="form-control"/>控件屬性:
var p = {// 標(biāo)簽參數(shù)id: id!, // 元素ID,如果不填寫,則與name相同path: path!, // 綁定form上model中屬性的值name: name!, // 元素名稱,不填寫value: value!, // 元素值dictType: dictType!'', // 字典類型,從字典里獲取,自動(dòng)設(shè)置items、itemLabel、itemValueitems: items!([]), // 列表數(shù)據(jù),可接受對(duì)象集合,如:List<DictData>itemLabel: itemLabel!'', // 指定列表數(shù)據(jù)中的什么屬性名作為option的標(biāo)簽名itemValue: itemValue!'', // 指定列表數(shù)據(jù)中的什么屬性名作為option的value值label: label!, // 只有一個(gè)復(fù)選按鈕的情況下設(shè)置};textarea 文本域標(biāo)簽
<#form:textarea path="remarks" rows="3" maxlength="200" class="form-control"/>控件屬性:
var p = {// 標(biāo)簽參數(shù)id: id!, // 元素ID,如果不填寫,則與name相同path: path!, // 綁定form上model中屬性的值name: name!, // 元素名稱,不填寫value: value!, // 元素值};hidden 隱藏域標(biāo)簽
<#form:hidden path="menuCode" />控件屬性:
var p = {// 標(biāo)簽參數(shù)id: id!, // 元素ID,如果不填寫,則與name相同path: path!, // 綁定form上model中屬性的值name: name!, // 元素名稱,不填寫value: value!, // 元素值type: type!'hidden', // 元素的類型,默認(rèn)hidden};表單組件封裝
treeselect 樹結(jié)構(gòu)選擇
封裝layer+zTree實(shí)現(xiàn)樹結(jié)構(gòu)選擇組件,使用場(chǎng)景如:部門選擇,行政區(qū)劃選擇,欄目列表選擇等
<#form:treeselect id="parent" title="上級(jí)菜單"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 = {// 標(biāo)簽參數(shù)id: id!, // 元素IDname: name!, // 隱藏域名稱value: value!, // 隱藏域值labelName: labelName!, // 標(biāo)簽框名稱labelValue: labelValue!, // 標(biāo)簽框值class: class!'', // 標(biāo)簽框的CSS類名placeholder: placeholder!, // 標(biāo)簽框的預(yù)期值的提示信息dataMsgRequired: thisTag.attrs['data-msg-required'], // 必填錯(cuò)誤提示信息btnClass: btnClass!, // 標(biāo)簽框后面的按鈕CSS類名title: title!'選項(xiàng)', // 對(duì)話框標(biāo)題boxWidth: boxWidth!300, // 對(duì)話框?qū)挾?#xff0c;默認(rèn)300像素boxHeight: boxHeight!400, // 對(duì)話框高度,默認(rèn)400像素url: url!, // 樹結(jié)構(gòu),數(shù)據(jù)源地址 [{id, pid, name}]readonly: @ObjectUtils.toBoolean(readonly!false), // 是否只讀模式allowInput: @ObjectUtils.toBoolean(allowInput!false), // 是否允許label框輸入allowClear: @ObjectUtils.toBoolean(allowClear!true), // 是否允許清空選擇內(nèi)容checkbox: @ObjectUtils.toBoolean(checkbox!false), // 是否顯示復(fù)選框,是否支持多選,如果設(shè)置canSelectParent=true則返回父節(jié)點(diǎn)數(shù)據(jù)expandLevel: @ObjectUtils.toInteger(expandLevel!(-1)), // 默認(rèn)展開層次級(jí)別(默認(rèn):如果有1個(gè)根節(jié)點(diǎn),則展開一級(jí)節(jié)點(diǎn),否則不展開)canSelectRoot: @ObjectUtils.toBoolean(canSelectRoot!false), // 可以選擇跟節(jié)點(diǎn)canSelectParent: @ObjectUtils.toBoolean(canSelectParent!false), // 可以選擇父級(jí)節(jié)點(diǎn)returnFullName: @ObjectUtils.toBoolean(returnFullName!false), // 是否返回全路徑,包含所有上級(jí)信息,以 returnFullNameSplit 參數(shù)分隔returnFullNameSplit: returnFullNameSplit!'/', // 是否返回全路徑,的分隔符,默認(rèn)“/”};iconselect 圖標(biāo)選擇
<#form:iconselect path="menuIcon" class=""/>組件屬性:
var p = {// 標(biāo)簽參數(shù)id: id!, // 元素ID,如果不填寫,則與name相同path: path!, // 綁定form上model中屬性的值name: name!, // 元素名稱,不填寫value: value!, // 元素值class: class!'', // 隱藏域和標(biāo)簽框的CSS類名};validcode 驗(yàn)證碼
<#form:validcode name="validCode" isRequired="true" isRemote="true" />組件屬性:
var p = {id: id!name, // 驗(yàn)證碼輸入框IDname: name!, // 驗(yàn)證碼輸入框名稱(必填)isRequired: @ObjectUtils.toBoolean(isRequired!true), // 是否必填,默認(rèn)必填dataMsgRequired: thisTag.attrs['data-msg-required'], // 必填錯(cuò)誤提示信息isRemote: @ObjectUtils.toBoolean(isRemote!true), // 是否支持實(shí)時(shí)遠(yuǎn)程驗(yàn)證dataMsgRemote: thisTag.attrs['data-msg-remote'], // 必填錯(cuò)誤提示信息isLazy: @ObjectUtils.toBoolean(isLazy!false), // 是否懶加載驗(yàn)證碼圖片,原noRefresh參數(shù)};listselect 列表選擇
<#form:listselect id="userSelect" title="用戶"url="${ctx}/sys/user/userSelect?userType=${role.userType}" allowClear="false" checkbox="true" itemCode="userCode" itemName="userName"/>組件屬性:
var p = {// 標(biāo)簽參數(shù)id: id!, // 元素IDpath: path!, // 綁定form上model中屬性的值name: name!, // 隱藏域名稱value: value!, // 隱藏域值labelPath: labelPath!, // 綁定form上model中屬性的值labelName: labelName!, // 標(biāo)簽框名稱labelValue: labelValue!, // 標(biāo)簽框值class: class!'', // 標(biāo)簽框的CSS類名placeholder: placeholder!, // 標(biāo)簽框的預(yù)期值的提示信息dataMsgRequired: thisTag.attrs['data-msg-required'], // 必填錯(cuò)誤提示信息btnClass: btnClass!, // 標(biāo)簽框后面的按鈕CSS類名title: title!'選項(xiàng)', // 對(duì)話框標(biāo)題boxWidth: boxWidth!'$(top.window).width() - 100', // 對(duì)話框?qū)挾萣oxHeight: boxHeight!'$(top.window).height() - 100', // 對(duì)話框高度 url: url!, // 樹結(jié)構(gòu),數(shù)據(jù)源地址 [{id, pid, name}]readonly: @ObjectUtils.toBoolean(readonly!false), // 是否只讀模式allowInput: @ObjectUtils.toBoolean(allowInput!false), // 是否允許label框輸入allowClear: @ObjectUtils.toBoolean(allowClear!true), // 是否允許清空選擇內(nèi)容checkbox: @ObjectUtils.toBoolean(checkbox!false), // 是否顯示復(fù)選框,是否支持多選,如果設(shè)置canSelectParent=true則返回父節(jié)點(diǎn)數(shù)據(jù)itemCode: itemCode!, // 選擇后結(jié)果集中的Code屬性名,返回到隱藏域的值itemName: itemName!, // 選擇后結(jié)果集中的Name屬性名,返回到輸入框的值};fileupload 文件上傳
1、文件上傳: <#form:fileupload id="upload1" bizKey="${user.id}" bizType="user_upload1"uploadType="all" class="required" readonly="false"/> 后臺(tái)代碼:FileUploadUtils.saveFileUpload(user.getId(), "user_upload1");2、圖片上傳: <#form:fileupload id="upload2" bizKey="${user.id}" bizType="user_upload2"uploadType="image" class="required" readonly="false"/> 后臺(tái)代碼:FileUploadUtils.saveFileUpload(user.getId(), "user_upload2");3、返回路徑: <#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 = {// 標(biāo)簽參數(shù)id: id!, // 元素IDbizKey: bizKey!, // 業(yè)務(wù)表的主鍵值(與附件關(guān)聯(lián)的業(yè)務(wù)數(shù)據(jù))bizType: bizType!, // 業(yè)務(wù)表的上傳類型(全網(wǎng)唯一,推薦格式:實(shí)體名_上傳類型,例如,文章圖片:article_photo)returnPath: @ObjectUtils.toBoolean(returnPath!false), // 是否是返回文件路徑到輸入框(默認(rèn)false),可將路徑直接保存到某個(gè)字段里filePathInputId: filePathInputId!, // 設(shè)置文件URL存放的輸入框的ID,當(dāng)returnPath為true的時(shí)候,返回文件URL到這個(gè)輸入框fileNameInputId: fileNameInputId!, // 設(shè)置文件名稱存放的輸入框的ID,當(dāng)returnPath為true的時(shí)候,返回文件名稱到這個(gè)輸入框uploadType: uploadType!'', // 上傳文件類型:all、file、image、media,若不設(shè)置,則自動(dòng)根據(jù)上傳文件后綴獲取class: class!'', // 標(biāo)簽框的CSS類名,設(shè)置 required 加入必填驗(yàn)證readonly: @ObjectUtils.toBoolean(readonly!false), // 是否只讀模式,只讀模式下為查看模式,只允許下載allowSuffixes: allowSuffixes!'', // 允許上傳的后綴,前臺(tái)的限制,不能超越file.*AllowSuffixes的設(shè)置,例如:.jpg,.png,maxUploadNum: @ObjectUtils.toInteger(maxUploadNum!300), // 多文件下允許最多上傳幾個(gè),默認(rèn)300個(gè),設(shè)置-1代表不限制imageMaxWidth: @ObjectUtils.toInteger(imageMaxWidth!1024), // 圖片壓縮,最大寬度(uploadType為image生效),設(shè)置-1代表不做任何處理imageMaxHeight: @ObjectUtils.toInteger(imageMaxHeight!768), // 圖片壓縮,最大寬度(uploadType為image生效),設(shè)置-1代表不做任何處理isLazy: @ObjectUtils.toBoolean(isLazy!false), // 設(shè)置為ture需要點(diǎn)擊上傳按鈕才上傳文件,否則選擇后就直接上傳isMini: @ObjectUtils.toBoolean(isMini!false), // 是否是精簡(jiǎn)上傳窗口,無邊距,無邊框preview: preview!'', // 是否顯示預(yù)覽按鈕,接受參數(shù):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"/> 后臺(tái)代碼: // 如果設(shè)置了頭像,則保存頭像 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 = {// 標(biāo)簽參數(shù)id: id!, // 元素ID,如果不填寫,則與name相同path: path!, // 綁定form上model中屬性的值name: name!, // 元素名稱,不填寫value: value!, // 元素值class: class!'', // 隱藏域的CSS類名btnText: btnText!'選擇圖片', // 按鈕的名字btnClass: btnClass!'', // 按鈕的CSS類名imageId: imageId!'', // 裁剪后base64返回到img的idimageDefaultSrc: imageDefaultSrc!'', // 圖片默認(rèn)地址,清除后使用地址circle: circle!'false', // 是否圓形圖片};ueditor 富文本在線編輯器
<#form:ueditor name="text" maxlength="10000" height="200" class="required"simpleToolbars="false" readonly="false" outline="false"/>組件屬性:
var p = {// 標(biāo)簽參數(shù)id: id!, // 元素ID,如果不填寫,則與name相同path: path!, // 綁定form上model中屬性的值name: name!, // 元素名稱,不填寫value: value!, // 元素值class: class!'', // 標(biāo)簽框的CSS類名,設(shè)置 required 加入必填驗(yàn)證maxlength: maxlength!'', // 編輯器最大輸入字?jǐn)?shù),為空代表無限制height: height!'200', // 編輯器的高度,默認(rèn)200simpleToolbars: @ObjectUtils.toBoolean(simpleToolbars!false), // 是否是簡(jiǎn)單的工具條readonly: @ObjectUtils.toBoolean(readonly!false), // 是否只讀模式outline: @ObjectUtils.toBoolean(outline!false), // 大綱視圖options: options!'', // UE附加選項(xiàng),逗號(hào)隔開。};封裝通用JavaScript方法
/*** 輸出日志*/ log(msg);/*** 輸出錯(cuò)誤日志*/ error(msg);/*** URL 編碼*/ js.encodeUrl(url);/*** URL 解碼*/ js.decodeUrl(url);/*** 得到 IE 版本,如果是IE返回:IE版本號(hào),否則返回:false* if (js.ie && js.ie <= 8){ alert('瀏覽器版本過低') }*/ js.ie;/*** 安全取值,復(fù)雜類型或嵌套類型時(shí),取不到屬性中的屬性時(shí)不拋出異常* js.val(jsonObj, 'user.office.name');*/ js.val(jsonObj, attrName);/*** 返回HashCode唯一值(默認(rèn)忽略大小寫)* @param str 要獲取的字符串HashCode值* @param caseSensitive 是否大小寫敏感(默認(rèn)false)* @usage js.hashCode(str);*/ js.hashCode(str, caseSensitive);/*** 異步加載文件,loadFile v1.0* js.loadFile(file文件路徑, callback成功回調(diào), error失敗回調(diào))* js.loadFile('js/test.js',function(){},function(data){});* js.loadFile(['js/test.js','css/test.css'],function(){},function(data){});*/ js.loadFile(file, callback, error);/*** 打開一個(gè)Window窗體*/ js.windowOpen(url, name, width, height);/*** 關(guān)閉當(dāng)前Window窗體*/ js.windowClose();/*** 給URL地址添加參數(shù),如果原來有參數(shù)則用&前綴,如果沒有則用?前綴*/ js.addParam(url, params);/*** 獲取URL地址的參數(shù)*/ js.getParam(paramName, url);/*** 查看Object的內(nèi)容,手機(jī)調(diào)試用* @param obj*/ js.alertObj(obj);/*** 獲取字典標(biāo)簽* js.getDictLabel(${@DictUtils.getDictListJson('sys_menu_type')}, val, '未知', true)*/ js.getDictLabel(dictListJson, value, defaultValue, inCss);/// message dialog/*** 顯示加載框* @param message 加載框提示信息* @param ignoreMessageIfExists 如果已經(jīng)有加載框現(xiàn)在,則忽略message信息的設(shè)置* @usage js.loading('正在保存...');*/ js.loading(message, ignoreMessageIfExists);/*** 關(guān)閉加載框* @param timeout 關(guān)閉延遲時(shí)間* @param forceClose 是否強(qiáng)制關(guān)閉* @usage js.closeLoading(1000, true);*/ js.closeLoading(timeout, forceClose);/*** 得到layer對(duì)話框?qū)ο? js.layer.msg();*/ js.layer;/*** 顯示提示框* @param message 提示消息* @param title 提示標(biāo)題* @param type 提示類型(success、error、warning、info)* @param timeout 自動(dòng)關(guān)閉毫秒(默認(rèn)4000毫秒)*/ js.showMessage(message, title, type, timeout);/*** 顯示錯(cuò)誤提示框*/ js.showErrorMessage(responseText);/*** 關(guān)閉提示框*/ js.closeMessage();/*** 提示對(duì)話框* @param message 提示消息* @param options 對(duì)話框選項(xiàng)* @param closed 對(duì)話框關(guān)閉回調(diào)方法* @usage js.alert('你好!', function(){})* @usage js.alert('你好!', {icon: 2}, function(){})*/ js.alert(message, options, closed);/*** 確認(rèn)對(duì)話框* @param message 確認(rèn)信息* @param urlOrFun 確認(rèn)后的跳轉(zhuǎn)的地址,或調(diào)用的方法* @param data 如果urlOrFun是地址,該參數(shù)是調(diào)用地址的參數(shù)信息* @param callback 執(zhí)行ajax的回調(diào)方法,如果為空,則直接通過location=urlOrFun跳轉(zhuǎn)。* @param dataType 返回?cái)?shù)據(jù)類型(默認(rèn)json)* @param async 是否異步(默認(rèn)true)* @param loadingMessage 調(diào)用loading(loadingMessage)的提示信息。* @usage js.confirm('確認(rèn)刪除嗎?', '$ctx/biz/delete?id=123', function(data){alert('刪除成功')}, 'json', true, '正在刪除...');* @usage js.confirm('確認(rèn)刪除嗎?', '$ctx/biz/delete', {id: '123'}, function(data){alert('刪除成功')}, 'json', true, '正在刪除...');* @usage js.confirm('確認(rèn)刪除嗎?', function(data){alert('刪除成功')});*/ js.confirm(message, urlOrFun, data, callback, dataType, async, loadingMessage);/// js template/*** 根據(jù)js模板生成代碼,使用laytpl引擎* @param id 模板ID* @param data 模板數(shù)據(jù)(可選)* @param callback 如果填寫,則為異步渲染* @usage * 模板格式: <sc ript id="dempTpl" type="text/template">//<!--* 這里寫模塊內(nèi)容...* //--></sc ript>* 調(diào)用方法: js.template('dempTpl', data);* 模版語法:* 輸出一個(gè)普通字段,不轉(zhuǎn)義html: {{ d.field }}* 輸出一個(gè)普通字段,并轉(zhuǎn)義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);/*** 截取字符串,區(qū)別漢字和英文*/ js.abbr(name, maxLength);/// number/*** 格式化數(shù)值* @param num 待格式化的樹* @param cent 保留小數(shù)位數(shù)* @param isThousand 是否進(jìn)行千分位格式化*/ js.formatNumber(num, cent, isThousand);/*** 金額格式化(千位符,小數(shù)四舍五入)金額每隔三位加一個(gè)逗號(hào)* @param s 要格式化的數(shù)值* @param n 小數(shù)位數(shù)*/ js.formatMoney(s, n);/*** 數(shù)值前補(bǔ)零*/ js.numberPad(num, n);/// date/*** 日期格式化* @param date 日期 new Date()* @param f 格式化字符串 yyyy-MM-dd HH:mm:ss*/ js.formatDate(date, f);/*** 字符串轉(zhuǎn)為日期* @param date*/ js.parseDate(date);/*** 日期加減* @param date* @param dadd 天數(shù)*/ js.addDate(date, dadd);/*** 快速選擇日期方法* @param type 1今日,2本周,3本月,4本季度,5上月* @param beginDateId 開始日期控件的ID* @param endDateId 結(jié)束日期控件的ID*/ js.quickSelectDate(type, beginDateId, endDateId);/// cookie/*** cookie 操作* @param name Cookie名稱* @param value Cookie值,填寫表示設(shè)置,不填寫表示獲取* @parma options:{expires:7} 如果是數(shù)字,則expires單位為天。*/ js.cookie(name, value, options);/// tabPage/*** 得到TabPage對(duì)象*/ js.tabPage;/*** 初始化TAB頁面* @param id*/ js.initTabPage(id, options);/*** 添加TAB頁面* @param $this 點(diǎn)擊的對(duì)象* @param title 提示標(biāo)題* @param url 訪問的路徑* @param closeable 是否有關(guān)閉按鈕* @param refresh 打開后是否刷新重新加載*/ js.addTabPage($this, title, url, closeable, refresh);/*** 獲取當(dāng)前TAB頁面* @param currentTabCallback(contents, contentWindow) 當(dāng)前頁面回調(diào)方法,傳入當(dāng)前tab頁面的contents和contentWindow*/ js.getCurrentTabPage(currentTabCallback);/*** 獲取當(dāng)前頁面的上一個(gè)TAB頁面,并激活上級(jí)頁面* @param preTabCallback(contents, contentWindow) 傳入上一個(gè)tab頁面的contents和contentWindow* @param isCloseCurrentTab 是否關(guān)閉當(dāng)前頁簽*/ js.getPrevTabPage(preTabCallback, isCloseCurrentTab);/*** 關(guān)閉當(dāng)前TAB頁面,并激活上級(jí)頁面* @param preTabCallback(contents, contentWindow) 關(guān)閉前的回調(diào)方法,傳入上一個(gè)tab頁面的contents和contentWindow*/ js.closeCurrentTabPage(preTabCallback);封裝數(shù)據(jù)表格組件DataGrid
數(shù)據(jù)表格是一個(gè)必不可少的元素,在選擇這個(gè)選型的時(shí)候嘗試了很多開源組件,最終選擇jqGrid,只是因?yàn)樗咏?jīng)典思維,用著還算順手,最主要的是遇見什么問題都可以自行解決和修復(fù)問題,有人說jqGrid不好看,這沒關(guān)系這完全而已自行編寫CSS改造它,下面看看一個(gè)簡(jiǎn)單的例子:
<#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}">參數(shù)名稱:<#form:input path="configName" maxlength="100" class="form-control" />參數(shù)鍵名:<#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對(duì)象 $('#dataGrid').dataGrid({// 查詢數(shù)據(jù)表單searchForm: $('#searchForm'),// 設(shè)置數(shù)據(jù)表格列columnModel: [ {header:'參數(shù)名稱', 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="編輯參數(shù)">'+val+'</a>';}},{header:'參數(shù)鍵名', name:'configKey', index:'a.config_key', width:200},{header:'參數(shù)鍵值', 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="編輯參數(shù)"><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="刪除參數(shù)" data-confirm="確認(rèn)要?jiǎng)h除該參數(shù)嗎?"><i class="fa fa-trash-o"></i></a> ');<% } %>return actions.join('');}}],// 加載成功后執(zhí)行事件ajaxSuccess: function(data){} });是不是比你使用foreach方便的多,封裝后名字叫dataGrid,這只是展示了冰山一角,它支持所有jqGrid參數(shù),即簡(jiǎn)化了代碼編寫,又不失功能
提供豐富的演示例子
- 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
轉(zhuǎn)載于:https://my.oschina.net/thinkgem/blog/1561129
總結(jié)
以上是生活随笔為你收集整理的JeeSite 4.0 说说前端的那些事的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 麻省理工18年春软件构造课程阅读02“J
- 下一篇: 怎么让HTML的属性横着排,css标签怎