# myvue
**Repository Path**: wujizhou/myvue
## Basic Information
- **Project Name**: myvue
- **Description**: 类似小程序的开源前端开发框架 myvue
- **Primary Language**: JavaScript
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2021-03-12
- **Last Updated**: 2021-09-12
## Categories & Tags
**Categories**: Uncategorized
**Tags**: JavaScript
## README
## 说明
> 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
- tpl: html模板/layui模板
- lay: 部分layui模板
- js : 当前页面的逻辑,这里为核心,主体加载后执行详见下面的 解析机制:
```
exports = {
data: { //初始化数据
...
}
use:[], //依赖的layui模板
init: //渲染模板前的逻辑
after: //渲染模板后的逻辑
}
```
> 菜单管理页 /menu/index.html
```
```
上面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);
}
}
});
}
}
```
上面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:'',
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);
}
}
```
### 国际化 _lang.js
```
// 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);
}
```
### 部分页面预览(暗黑版,眼睛不好,见谅)





### 关于更新
项目还在不断更新状态,但大体逻辑基本不会变动,由于工作等原因,更新较慢,望谅解!
所有的一切都是轻且快,而实际表现也很惊喜,开发本该如此优雅
> 希望大家玩的愉快,不玩初心!