Just be simple and elegant !
特点: 轻量(只要nginx) 快速(受够了vue) 模块根据依赖加载(layui) 模板带缓存 即开即用 即时渲染 易于控制
我是一个java,php,js开发者 ,随着技术的日渐累积 和 市场环境的日益更新(前端机器性能越来越高,前端日益发展), 逐渐萌生了站在巨人(layui,nginx,springboot,...)的肩膀上 做自己的前后端开发框架的决心, 从jquery/zeptjs/一众ui库到 avalonjs/layuijs/vue,从java/delphi/php/go再到java,发现最适合自己的开发为 : java做后端,php/...中间件,js前端 ,这里只讲下本次的主题:后台的前端开发框架.
开发环境下, 及时查看需配置nginx且开启ssi 或者 构建为纯静态 查看 , 打包后为纯静态
主要采用 layui(模块化)+nginx(容器 + ssi,为了代码复用) + 自定义layui插件等,推一波layui(好看又实用) ,采用自定义的模板解析更新机制,并考虑到模板缓存问题 .
大体流程为: 加载后台主体js和html,需要加载页面时(例如点击菜单)先查看模板缓存(没有就去nginx请求模板), 再去后端(如java)请求初始化数据,填充模板,最后渲染数据 .
所有的一切追求都是轻且快,而实际表现也很惊喜
# 预处理ssi标签等
gulp dist
# 生成纯静态文件
gulp prod
分为3大标签: tpl , lay , js
exports = {
data: { //初始化数据
...
}
use:[], //依赖的layui模板
init: //渲染模板前的逻辑
after: //渲染模板后的逻辑
}
菜单管理页 /menu/index.html
<tpl>
<div class="layui-card" id="body">
<!--# include virtual="/lib/jump-top.html" -->
<!-- <div class="layui-card-header">{{ d.title }}</div> -->
<div class="layui-card-body">
{{ d.headTip }}
<form class="layui-form layui-form-pane" lay-filter="js-form">
<input type="text" class="hide" name="unAutoSubmit" />
<!-- {:token()} -->
<div class="layui-inline">
<!-- <label for="jsf-kword" class="layui-form-label">关键词</label> -->
<div class="layui-input-inline" style="width: 200px;">
<input type="text" id="jsf-kword" name="kword" class="layui-input" lay-require="true" required placeholder="菜单名">
</div>
</div>
<!--# include virtual="/tpl/form-search.html" -->
</form>
<table id="demo" lay-filter="fDemo"></table>
</div>
</div>
</tpl>
<lay>
<script type="text/html" id="toolbarDemo">
<div class="block clearfix">
<div class="layui-btn-group">
<!--# include virtual="/tpl/a-add-parent.html" -->
<!--# include virtual="/tpl/a-dels-check.html" -->
</div>
<a data-parent="0" class="{{# if( d.where.parent == 0 ){ }} hide {{# } }} layui-btn layui-btn-warm layui-btn-sm js-parent" title="最上级"><i class="fa fa-reply"></i></a>
</div>
</script>
<script type="text/html" id="barDemo">
<div class="layui-btn-group">
<a data-href="{{ layui.rb.path }}/detail" data-params='"id":{{ d.id }}' class="layui-btn layui-btn-sm ajax-layer" title="查看详情"><i class="layui-icon layui-icon-username"></i>{{ L('detail') }}</a>
<!--# include virtual="/tpl/a-edit.html" -->
<!--# include virtual="/tpl/a-del-check.html" -->
</div>
</script>
<script type="text/html" id="iconTpl">
<i class="{{ d.icon }}"></i>
</script>
<script type="text/html" id="nameTpl">
{{# if ( d.level < 3 ){ }}
<a class="layui-table-link" data-params='"parent":{{ d.id }}'>{{ d.id }}</a>
{{# }else{ }} {{ d.id }}
{{# } }}
</script>
<script type="text/html" id="showTpl">
<form class="layui-form">
<input type="checkbox" data-id="{{ d.id }}" class="layer-msg no-refresh" data-field="show" {{# if(d.show){ }} checked {{# } }}
lay-skin="switch">
</form>
</script>
</lay>
<js>
<!--# include virtual="/menu/index.js" -->
</js>
上面html片段只是一些html,这里不看了
/menu/index.js
exports = {
data: {
title: '菜单管理',
parent: 0,
headTip: "最多3级菜单,一级菜单名字不要改会自动国际化,点击带 .列单元格编辑",
},
use:["rb","form","table2","moment","jquery"],
init: function(rb) {
rb.path = "menu";
rb.controller = "api_menu";
// 模板解析前的运行代码
rb.log("index init");
if( this.data.headTip ) {
this.data.headTip = rb.getHtmlHeadTip( this.data.headTip );
}
console.log(this);
// 获取后端数据
// this.param 地址栏请求参数
// 封装数据到
},
after: function(rb,form,table) {
// 页面渲染完后执行的代码
// form init
rb.setWhere = function() {
rb.where.kword = $("#jsf-kword").val() || '';
}
// table init
rb.where = {
parent : this.data.parent
,field: 'sort'
,order: 'asc'
};
// table render
rb.table = table.render($.extend(rb.table_config,{
url: layui.cache.apiPath + rb.controller + "/index"
,where: rb.where
,initSort: {
field: 'sort',type: 'asc'
}
,cols: [[
{checkbox: true} //,LAY_CHECKED: true
,{field: 'id', title: 'ID', minWidth: 60,templet: '#nameTpl',style:'cursor:pointer',event:'go',sort:true}
,{field: 'name', title: L('menu')+' .',edit: 'text'}
,{field: 'icon', title: L('icon')+' .',edit: 'text',templet: '#iconTpl'}
,{field: 'url', title: L('url')+' .',edit: 'text'}
,{field: 'params', title: L('url-para')+' .',edit: 'text'}
,{field: 'show', title: L('show'), width: 60,templet:'#showTpl'}
,{field: 'sort',title: L('sort')+' .',align:'right',minWidth:60,edit: 'text',sort:true}
,{align:'left',title: L('op'),width:185,toolbar: '#barDemo'}
]]
}));
// table a go
$("#body").on("click",".js-parent",function(e) {
rb.where.parent = $(this).data('parent') || 0;
rb.reloadTable(rb.where);
});
table.on('tool(fDemo)', function(obj) {
// console.log(obj);
var data = obj.data;
if(obj.event === 'go') {
var params = obj.tr.find('a').data('params') || '';
if(params) {
rb.where = $.extend(rb.where,JSON.parse('{' + params + '}'));
rb.reloadTable(rb.where);
}
}
});
<!--# include virtual="/lib/table-extra.js" -->
}
}
上面js/html片段只是一些html/js,这里不看了
rb.js rb是自定义的一些快捷方法
;layui.define(['layer','scojs','util','notice','table2excel'],function (exports){
"use strict";
var layer = layui.layer
,$ = layui.jquery
,notice = layui.notice
,device = layui.device();
// 外部接口
var rb = {
alert : function (msg,type){ //scojs message box
msg = undefined == msg ? '' : msg;
type = type || false;
$.scojs_message(msg, type ? $.scojs_message.TYPE_OK : $.scojs_message.TYPE_ERROR);
},
… 其他方法
};
rb.log('rb',L('init'));
exports('rb',rb);
});
加载主体(如首页/登陆/..)后:
主体js大体如下:
index.js
// use strict;
var loading = false;
var loadingIdx;
var initTabs = [];
var initPages = [];
var themes = {
'df' : '#23262e',
'blue': '#29d',
'cyan':'#6f7c85',
'gray':'#eee',
'green' :'#009688',
'orange':'#FFB800',
'red':'#ff5722',
};
layui.cache.tab_welcome = {
title:'<i class="fa fa-desktop"></i>',
id:'iframe0'
};
layui.use(['table2','layer','form','laytpl','element','tabrightmenu','rb'],function (){
var layer = layui.layer
,$ = layui.jquery
,el = layui.element
,form = layui.form
,laytpl = layui.laytpl
,rb = layui.rb
,table = layui.table2
;
…
rb.check();
var apiPath = layui.cache.apiPath;
var index = rb.loading();
rb.log("index","init");
// 请求菜单 + 添加菜单
rb.log("get menu ----------> ");
$.post(apiPath+'api_menu/ajax', function(data) {
…
//获取模板代码 , 如点击菜单触发
$.get(url, function(tpl,status,xhr) {
if(layui.cache.rainbow.cacheTpl){
rb.setCacheTpl(url,tpl);
}
handleMenu(tpl,params,id,ops);
});
...
// 处理前端服务器url 请求
function handleMenu(tpl,params,id,ops){
var lay = rb.getTplByTagName(tpl,"lay");
var js = rb.getTplByTagName(tpl,"js");
tpl = rb.getTplByTagName(tpl,"tpl");
lay = lay ? rb.replaceByTagName(lay,'lay') : '';
js = js ? rb.replaceByTagName(js,'js') : '';
tpl = tpl ? rb.replaceByTagName(tpl,'tpl') : '';
if($.trim(js)){ //有js代码
try {
// js = js.replaceAll('&',"&");
// console.log("js",js);
var exports = eval(js);
exports = $.extend(true, exports, {data:{},_d:{},_params:""});
} catch(e) {
rb.log("模板js解析出错",e);
}
// console.log("exports: ", exports);
if(exports.data) {
// 请求的参数
exports.params = params;
if('string' == typeof exports.use) {
exports.use = [ exports.use ];
}
layui.use(exports.use,function() {
var modules = [];
$.each(exports.use,function(i,el) {
modules.push(layui[el]);
});
// console.log("modules",modules);
try{
exports.init.apply(exports,modules);
} catch(e) {
rb.log("模板js运行出错",e);return;
}
try{
laytpl(tpl).render(exports.data, function(html) {
ops.content = html + lay;
console.log(ops);
rb.tabChangePage(id,ops);
exports.after.apply(exports,modules);
});
} catch (e) {
rb.log("模板渲染出错",e);return;
}
});
}
}else{
ops.content = tpl;
rb.tabChangePage(id,ops);
}
}
// app table2 rb...ok sort by alpha
var _langs = {
// un type
// ADMIN MENU
"CMS":"CMS",
"IMG":"图库",
"MALL":"商城",
"OAUTH":"OAUTH",
"OTHER":"其他",
"SYS":"系统",
"USER":"用户",
….
// 要替换的话里面必须要有{key},否则不认,{key}在两头的可用LL
function L(k,key=''){
var ret = _langs[k],reg;
if(ret == undefined){ //未设置
ret = k;
}else{
if(/\{key\}/.test(ret)){ // 需要替换
if(typeof key == 'string' || typeof key == 'number'){
reg= RegExp('{key}' , "g" );
ret = ret.replace(reg,L(key));
}else{
for(var k in key){
reg= RegExp('{'+k+'}' , "g" );
ret = ret.replace(reg,L(key[k]));
}
}
}
}
return ret;
// return _langs[k] || k;
}
function Lnull(k){
return _langs[k] || '';
}
function LL(k,dif=' ',add=''){
// if(rainbow.lang == 'en') add = ' ';
return k.trim().split(dif).map(function(item){
return L(item);
}).join(add);
}
项目还在不断更新状态,但大体逻辑基本不会变动,由于工作等原因,更新较慢,望谅解!
所有的一切都是轻且快,而实际表现也很惊喜,开发本该如此优雅
希望大家玩的愉快,不玩初心!
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。