1 Star 1 Fork 0

rainbow / myvue

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

说明

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页面内操作 菜单编辑

关于更新

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

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

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

MIT License Copyright (c) 2021 rainbow Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

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

发行版

暂无发行版

贡献者

全部

近期动态

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

搜索帮助