1 Star 1 Fork 0

rainbow / myvue

加入 Gitee
与超过 600 万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README.md

说明

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

<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('&amp;',"&");
        // 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);
}

部分页面预览(暗黑版,眼睛不好,见谅)

登陆实例 用户列表 自定义插件1 tab页面内操作 菜单编辑

关于更新

项目还在不断更新状态,但大体逻辑基本不会变动,由于工作等原因,更新较慢,望谅解!

所有的一切都是轻且快,而实际表现也很惊喜,开发本该如此优雅

希望大家玩的愉快,不玩初心!

点评 ( 0 )

你可以在登录后,发表评论

简介

类似小程序的开源前端开发框架 myvue 展开 收起
JavaScript 等 3 种语言
MIT
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
JavaScript
1
https://gitee.com/wujizhou/myvue.git
git@gitee.com:wujizhou/myvue.git
wujizhou
myvue
myvue
master

搜索帮助