EASY spa单页面版文档

    技术2022-07-11  124

    1.1.导入项目

    下载项目后进行解压使用IDEA、WebStorm、HBuilder等前端开发工具打开打开index.html点击右上角浏览器图标运行:

    注意: 必须以http://的形式访问,而不是file://的形式访问。

    1.2.项目结构

    |-assets | |-images // 图片 | |-js | |-main.js // 入口js | |-libs // 第三方库,echarts(图表)、layui | |-module // layui扩展模块,版本更新只用替换此目录 | |-img // 框架用到的图片 | |-admin.css // 框架核心样式 | |-admin.js // admin模块 | |-index.js // index模块 | |-******** // 其他扩展模块,不一一列举 |-components // html子页面 |-json // 模拟数据 |-index.html // 主页面

    main.js为入口js,上手使用项目前最好先看看它的说明。

    1.3.index.html结构说明

    <html> <head> <link rel="stylesheet" href="assets/libs/layui/css/layui.css"/> <link rel="stylesheet" href="assets/module/admin.css"/> </head> <body class="layui-layout-body"> <div class="layui-layout layui-layout-admin"> <!-- 头部 --> <div class="layui-header">...</div> <!-- 侧边栏 --> <div class="layui-side">...</div> <!-- 主体部分 --> <div class="layui-body">...</div> <!-- 底部 --> <div class="layui-footer">...</div> </div> <script type="text/javascript" src="assets/libs/layui/layui.js"></script> <script type="text/javascript" src="assets/js/main.js"></script> </body> </html>

    index.html就是这样固定的结构,一般不需要修改,只用在components下写子页面即可。

     

    1.4.添加一个菜单

    打开json/menus.json,在合适的位置添加一个菜单: {"name": "xx管理", "url": "#/xxx"} 在components下面新建一个xxx.html页面运行index.html,查看效果

    3.1.6版本开始菜单支持更丰富的写法:

    [{ "name": "xx管理", "url": "#/xxx" "show": false }, { "name": "百度", "url": "#/baidu", "iframe": "https://baidu.com" }, { "name": "layui", "url": "https://layui.com", "target": "_blank" }] show    false表示只注册路由,不显示在侧边栏iframe   表示用iframe打开一个标签target   表示当url不受路由控制时在新窗口打开链接

    注意: url以"#/"开头才会受路由控制,实现局部加载。

     

    1.5.main.js说明

    layui.config({ version: true, // 版本号配置为true可解决页面缓存问题 base: 'assets/module/' // 配置layui扩展模块目录 }).extend({ // 配置每个模块分别所在的目录 notice: 'notice/notice', steps: 'steps/steps' }).use(['index', 'admin'], function () { var $ = layui.jquery; var index = layui.index; var admin = layui.admin; // 加载侧边栏 admin.req('menus.json', function (res) { index.regRouter(res); // 注册路由 index.renderSide(res); // 渲染侧边栏 // 加载主页 index.loadHome({ url: '#/console/console', name: '<i class="layui-icon layui-icon-home"></i>' }); }); }); layui.config是告诉layui扩展模块所在目录layui.extend是配置每个模块具体位置,像admin.js、index.js这些没有子目录的不用配置version:true可解决模块js、html页面缓存的问题,也可以配置一个固定的版本号

    main.js的业务流程为先通过ajax加载菜单json,然后注册路由、渲染侧边栏、加载主页,至此框架即成功运行了。

    如果不是前后端分离的项目,base怎么配置加载模块都是404,建议这样配置:

    layui.config({ base: getProjectUrl() + 'assets/module/' }) /* 获取项目根路径 */ function getProjectUrl() { var layuiDir = layui.cache.dir; if (!layuiDir) { var js = document.scripts, last = js.length - 1, src; for (var i = last; i > 0; i--) { if (js[i].readyState === 'interactive') { src = js[i].src; break; } } var jsPath = src || js[last].src; layuiDir = jsPath.substring(0, jsPath.lastIndexOf('/') + 1); } return layuiDir.substring(0, layuiDir.indexOf('assets')); }

    getProjectUrl()方法原理是获取layui.js的全路径,并截取assets之前的路径,所以layui需要在assets目录下面, assets上一层需要是项目根路径,或者根据你的目录结构合理修改getProjectUrl方法,比如assets改成static。

     

    1.6.setter模块

    setter模块主要是用于给index模块和admin模块提供配置,可根据自己需要进行更改。

    参数:

    配置名默认说明baseServer'json/'接口地址,admin.req方法会自动加tableName'easyweb-spa'前端缓存用的存储表名pageTabsfalse是否开启多标签cacheTabtrue是否记忆TabopenTabCtxMenutrue是否开启Tab右键菜单maxTabNum20最多打开多少个tabviewPath'components'视图位置viewSuffix'.html'视图后缀defaultTheme 默认主题reqPutToPosttruereq请求put方法变成post,delete变get,并自动加_methodapiNoCachetrue配置为true后ajax请求json数据不会加版本号navArrow 侧边栏导航箭头,可选''(layui默认)、'arrow2'(箭头)、'arrow3'(加减号)closeFooterfalse是否关闭页脚tplOpen'{{'模板引擎边界符tplClose'}}'模板引擎边界符tabAutoRefreshfalse是否切换Tab自动刷新页面defaultLoading1默认的加载动画(只控制admin.showLoading的默认)

    方法:

    配置名默认getToken()获取tokenputToken(token)缓存tokenremoveToken()清除tokengetUser()获取当前登录的用户信息putUser(user)缓存当前登录的用户信息getUserAuths()获取用户所有权限getAjaxHeaders(requestUrl)ajax请求的统一headerajaxSuccessBefore(res, requestUrl)ajax请求结束后的统一预处理routerNotFound(r)路由不存在处理

    setter模块里面的配置都是默认配置,如果在主题界面修改了配置会以主题界面操作的为主,主题界面的操作保存在本地缓存中, 清除浏览器缓存就会以setter模块里面配置的为主。

    table需要在setter.js最下面用table.set实现自动传递header和预处理:

    layui.define(['table'], function (exports) { var setter = { }; /* table全局设置 */ var token = setter.getToken(); if (token && token.access_token) { layui.table.set({ headers: {'Authorization': 'Bearer ' + token.access_token}, parseData: function(res) { // 利用parseData实现预处理 if(res.code == 401) { setter.removeToken(); layui.layer.msg('登录过期', {icon: 2, anim: 6, time: 1500}, function () { location.replace('components/template/login/login.html'); }); } return res; } }); } exports('setter', setter); });

    dataGrid和treeTable组件是支持参数配置使用admin.ajax的发送请求的。

    或者使用$.ajaxSetup统一处理:

    $.ajaxSetup({ complete: function (xhr) { try { var res = JSON.parse(xhr.responseText); if (1131 === res.code || 1122 === res.code || 1120 === res.code) { // 登录过期 setter.removeToken(); layui.layer.msg('登录过期', {icon: 2, anim: 6, time: 1500}, function () { location.replace('components/template/login/login.html'); }); } } catch (e) { } } });

    注意: layui更新到2.5.6后模块名不能使用config,所以config.js现在改成了setter.js,请注意修改

    // 老版本只用把前面两行的config改成setter就可以了 layui.use(['setter'], function(){ var config = layui.setter; }); /* layui.use(['config'], function(){ var config = layui.config; }); */

     

    1.7.ID命名规范

    SPA单页面应用如果有重复的ID会出现问题,所有的页面都不能有重复的ID,因为是jQuery系的框架,id还是很常用的, 为了避免ID出现重复,强烈建议按照一定规范来命名。

    总体命名规则xxxXxxXxx

    第一个xxx   模块名,比如用户模块user第二个Xxx   功能描述,比如添加Add第三个Xxx   元素类型,比如按钮Btn

    例如页面是user.html,它的各个元素命名如下:

    按钮的命名

    <!-- 命名规则:xxxXxxBtn --> <button id="userAddBtn" class="layui-btn">添加</button> <button id="userEditBtn" class="layui-btn">修改</button> <button id="userDelBtn" class="layui-btn">删除</button>

    表格的命名

    <!-- 命名规则:xxxTable --> <table id="userTable" lay-filter=""userTable"></table> <!-- 表格上方搜索表单,命名规则:xxxTbSearchForm,id和lay-filter是非必须的 --> <form class="layui-form" id="userTbSearchForm" lay-filter="userTbSearchForm"> <!-- 输入框部分省略... --> <!-- 搜索提交按钮命名规则:xxxTbSearch --> <button class="layui-btn" lay-filter="userTbSearch" lay-submit>搜索</button> </form> <!-- 表格操作列,命名规则:xxxTbBar --> <script type="text/html" id="userTbBar"> <a class="layui-btn" lay-event="edit">修改</a> <a class="layui-btn" lay-event="del">删除</a> </script> <!-- 表格其他复杂列,例如switch状态开关等,命名规则:xxxTbXxx --> <script type="text/html" id="userTbState"> <input type="checkbox" lay-filter="userTbStateCk" value="{{d.userId}}" lay-skin="switch" lay-text="正常|锁定" {{d.state==0?'checked':''}}/> </script>

    一个页面有多个表格的命名

    <!-- 命名规则:xxxXxxTable --> <!-- 例如这是一个用户订单记录表 --> <table id="userOrderTable" lay-filter=""userOrderTable"></table> <!-- 表格操作列,命名规则:xxxXxxTbBar --> <script type="text/html" id="userOrderTbBar"> <a class="layui-btn" lay-event="edit">修改</a> <a class="layui-btn" lay-event="del">删除</a> </script>

    表单弹窗的命名

    <!-- 页面层弹窗命名规则:xxxEditDialog,非页面层可以忽略script --> <script type="text/html" id="userEditDialog"> <!-- 表单命名规则:xxxEditForm --> <form id="userEditForm" lay-filter="userEditForm" class="layui-form model-form"> <!-- 输入框部分省略... --> <!-- 提交按钮命名规则:xxxEditSubmit --> <button class="layui-btn" lay-filter="userEditSubmit" lay-submit>保存</button> </form> </script>

    页面其他弹窗的命名

    <!-- 例如这是一个查看详情弹窗 --> <!-- 页面层弹窗命名规则:xxxXxxDialog,非页面层可以忽略script --> <script type="text/html" id="userInfoDialog"> <!-- 表单命名规则:xxxXxxForm --> <form id="userInfoForm" lay-filter="userInfoForm" class="layui-form model-form"> <!-- 输入框部分省略... --> <!-- 提交按钮命名规则:xxxXxxSubmit --> <button class="layui-btn" lay-filter="userInfoSubmit" lay-submit>保存</button> </form> </script>

    表单里面的input建议少用id,只用name,取input的值通过监听表单提交来取,用input通过$('#xxxForm [name="xxx"]')来写。

    其他元素ID命名

    <!-- 命名规则:xxxXxxXxx,第一个xxx是模块名,第二个Xxx是功能描述,第三个Xxx是元素类型 --> <!-- 例如角色选择的下拉框 --> <select id="userRoleSel"></select> <!-- 例如备注的输入框 --> <input id="userCommentsEdt" />

    元素类型简写

    元素简写描述按钮类Btn<button>、.layui-btn等输入类的EdtEditText的简写,input、textarea等选择类的Sel下拉框、多选下拉框等表格Tableid="userTable"、id="userOrderTable"等表格附加组件Tbid="userTbBar"、id="userOrderTbBar"等弹窗Dialogid="userEditDialog、id="userInfoDialog"等表单Formid="userEditForm、id="userInfoForm"等表单提交按钮Submitid="userEditSubmit"、id="userInfoSubmit"等

    页面的命名

    <!-- 命名格式:xxxApp --> <div class="layui-fluid" id="userApp"> <!-- 省略页面内容...... --> </div>

    以上规则只是规范,非必须要求

     

    1.8.子页面模板语法

    在子页面首行增加<tpl/>标签即可开启模板引擎:

    <tpl/> <style> </style> <div class="layui-fluid"> {{# if(d.search.id==1){ }} <span>aaa</span> {{# }else{ }} <span>bbb</span> {{# } }} </div> <script> </script>

    用法与laytpl一致,边界符可以在setter.js中修改,d表示的是当前路由信息,例如访问 #/system/user/id=1/sex=男 它的路由信息为:

    { path: ["system", "user"], search: {id: 1, sex: "男"}, href: "/system/user/id=1/sex=男", refresh: false } path    路径数组search   参数列表refresh   如果是刷新触发的值为true

    也不一定只有d能用,比如获取layui版本号:{{layui.v}}

     

    2.1.批量注册路由

    index.regRouter([{ name: '用户管理', url: '#/system/user' // 路由关键字,必须要有#号 }]); // 嵌入iframe网页形式 index.regRouter([{ name: '百度一下', url: '#/baidu', iframe: 'https://baidu.com' }]); // 格式化数据,可以处理后端返回的menu.json格式 index.regRouter(res.data, function (d) { d.name = d.menuName; d.url = d.path; d.iframe = d.component; d.icon = d.menuIcon; d.show = !d.hide; d.subMenus = d.children; return d; });

    参数是一个数组,当你访问#/system/user时,就会打开一个“用户管理”标签页,“url”是路由关键字, 对应的页面地址是“components/system/user.html”,“components”和“.html”可以在setter模块中配置。

     

    2.2.加载默认主页

    index.loadHome({ url: '#/console/console1', name: '<i class="layui-icon layui-icon-home"></i>', loadSetting: true }); url         必填,主页路径,必须要有#号name       必填,Tab标题iframe      非必填,嵌入iframe网页形式loadSetting   非必填,是否恢复记忆的Tab

    只有调用了loadHome方法,路由模块才会真正开始工作。

     

    2.3.打开一个选项卡

    index.openNewTab({ name: '用户管理', url: '#/system/user' }); // 也可以加参数 index.openNewTab({ name: '用户管理', url: '#/system/user/id=1' }); // 打开一个iframe标签 index.openNewTab({ name: '百度一下', url: '#/baidu', iframe: 'https://baidu.com' }); name   选项卡的标题url     路由关键字,必须要有#号iframe  可选参数,打开一个iframe标签

    也可以使用<a href="#/system/user">XX</a>,这种写法必须保证“#/system/user”已经注册了路由,而“openNewTab()”会自动注册。

    注意:openNewTab方法只是注册临时路由,如果刷新页面,路由就会不存在了,

    如果想刷新页面也能使用,需要提前在main.js中的index.loadHome()方法之前注册路由, 或者在menus.json中配置,并且可以加show: false不在侧边栏中显示。

     

    2.4.关闭指定选项卡

    index.closeTab('#/system/user'); index.closeTab('/system/user'); index.closeTab('system/user');

    #/可写可不写,关闭当前tab可以用admin.closeThisTabs()或者ew-event="closeThisTabs"。

     

    2.5.跳到指定选项卡

    index.go('#/system/user'); index.go('/system/user'); index.go('system/user');

    前面#/可写可不写。

     

    2.6.修改Tab标题

    index.setTabTitle('Hello'); // 修改当前Tab标题文字,也支持单标签模式 index.setTabTitle('Hello', tabId); // 修改指定Tab标题文字 index.setTabTitleHtml('<span>Hello</span>'); // 修改整个标题栏的html,此方法只在单标签模式有效 index.setTabTitle(); // 单标签模式隐藏标题栏

    关闭多标签会自动生成一个标题栏,可用此方法修改标题栏,参数为undefined为隐藏标题栏。

     

    2.7.获取hash路径

    index.getHashPath('#/system/user'); index.getHashPath('#/system/user/id=1/name=aa');

    这两种hash最后返回的都是system/user,后面属于参数传递,不属于视图的路径。

     

    2.8.侧边栏手风琴折叠

    在layui-nav-tree上面增加lay-shrink="_all"配置即可展开菜单时收缩兄弟节点:

    <!-- 侧边栏 --> <div class="layui-side"> <div class="layui-side-scroll"> <ul class="layui-nav layui-nav-tree" lay-shrink="all"> ......省略其他部分 </ul> </div> </div>

    注意:是_all而不是all,在3.1.6版本之前是lay-accordion="true"。

     

    2.9.切换Tab自动刷新

    setter.js里面配置tabAutoRefresh: true即可开启。

     

    2.10.渲染侧边栏

    3.1.6版本开始在index模块封装了渲染侧边栏方法,不用自己写laytpl渲染:

    admin.req('menus.json', {}, function (res) { index.renderSide(res); // 渲染侧边栏 }, 'get');

    该方法还提供了灵活自定义操作,比如多系统模式,自定义要怎么插入渲染完的html:

    index.renderSide(res, $('#sideNav').html(), function(html, obj){ // html 是渲染后的内容 // obj.data 可获取处理后的数据,比如移除了show: false的数据 // obj.side 是侧边栏的dom,例如$(obj.side + '>.layui-nav').html(html) // obj.render() 可更新nav的渲染 }, '{{', '}}'); 参数一   必填,数据参数二   非必填,html模板参数三   非必填,hyml渲染完的自定义处理参数四   非必填,模板引擎边界符参数五   非必填,模板引擎边界符

    index.renderSide一般写在index.regRouter之后,index.regRouter还可以格式化数据 

     

    3.1.全部方法

    方法参数描述flexible(expand)true和false折叠/展开侧导航activeNav(url)a标签的href无#号设置侧导航栏选中refresh(url)url,可为空刷新指定Tab或当前TabcloseAllTabs()无关闭所有选项卡closeOtherTabs(url)url关闭除url外所有选项卡closeThisTabs(url)url,可为空关闭url或当前选项卡rollPage(d)left、right、auto滚动选项卡tabchangeTheme(theme,win,noCache,noChild) 切换主题lockScreen(url)见单独锁屏unlockScreen(isRemove)见单独解除锁屏   iframeAuto()无让当前的iframe弹层自适应高度closeThisDialog()无关闭当前iframe弹窗closeDialog(elem)dom选择器关闭elem元素所在的页面层弹窗open(option)同layer打开弹窗popupRight(option)同layer打开右侧弹窗getLayerData(index,key)见弹窗专题获取弹窗传递数据putLayerData(key,value,index)见弹窗专题弹窗传递数据reloadLayer(index,url,success)见弹窗专题刷新url方式弹窗alert(content,options,yes)同layer封装layer.alertconfirm(content,options,yes,cancel)同layer封装layer.confirmprompt(options,yes)同layer封装layer.prompttips(options)见admin模块高级增强layer.tipsmodelForm(layero,btnFilter,formFilter)见弹窗专题把弹窗自带按钮跟表单绑定一起getLayerIndex('#elem')jq选择器获取页面层弹窗index   req(url,data,success,method,option)见单独封装ajaxajax(option)同$.ajax封装ajax   showLoading(elem,type,opacity,size)见单独显示加载动画removeLoading(elem,fade,del)见单独移除加载动画btnLoading(elem,text,loading)见单独设置按钮为加载状态   putTempData(key,value,local)见单独缓存数据getTempData(key,local)见单独获取缓存数据putSetting(key,value) 修改配置信息recoverState() 恢复配置信息getPageHeight()无获取浏览器高度getPageWidth()无获取浏览器宽度chooseLocation(option)见admin模块高级地图选择位置cropImg(option)见admin模块高级裁剪图片   strToWin(str) 字符的parent.parent转对象openSideAutoExpand()无开启鼠标移入侧边栏自动展开openCellAutoExpand()无开启鼠标移入单元格超出自动展开   util.Convert_BD09_To_GCJ02(point)见admin模块高级百度地图坐标转高德地图坐标util.Convert_GCJ02_To_BD09(point)见admin模块高级高德地图坐标转百度地图坐标util.animateNum(elem,isThd,delay,grain)见admin模块高级动态数字util.deepClone(obj)见admin模块高级深度克隆对象util.fullTextIsEmpty(text)见admin模块高级判断富文本是否为空util.removeStyle(elem,options)见admin模块高级移除元素的styleutil.scrollTop(elem)见admin模块高级滚动到顶部util.tpl(html,data,openCode,closeCode)见admin模块高级模板解析   hasPerm(auth)权限判断当前登录的用户是否有权限renderPerm()无移除没有权限的dom元素

    使用示例:

    layui.use(['admin'], function () { var admin = layui.admin; var pageHeight = admin.getPageHeight(); // 获取浏览器高度 });

     

    3.2.弹窗相关方法

    open和popupRight方法:

    // 打开弹窗 admin.open({ type: 2, content: 'tpl-theme.html' }); // 打开右侧面板 admin.popupRight({ type: 2, content: 'tpl-theme.html' });

    这两个方法只是对layer.open进行了一层封装,参数和layer一样,查看layer文档。

    新增参数url:

    admin.open({ title: 'Hello', url: 'tpl-theme.html' }); admin.popupRight({ url: 'tpl-theme.html' });

    type:2, content:xxx这种是iframe类型的弹窗,使用url会通过ajax加载页面到弹窗中,而不是iframe嵌入。 当使用url方式的时候,弹窗页面应该是代码片段,而不是完整的html,如下所示:

    <style> * { color: red; } </style> <div class="layui-form model-form"> <button class="layui-btn" ew-event="closeDialog">关闭我</button> </div> <script> layui.use(['layer', 'form'], function () { var $ = layui.jquery; }); </script>

    页面不需要html、body这些东西,并且可以直接用<script>标签来写事件。

    admin.iframeAuto()方法:

    针对type:2的弹窗自适应弹窗高度,写在弹窗的子页面中,此方法是调用一次做一次高度自适应, 如果你用js动态修改了弹窗子页面的高度,需要再调用一次。

    admin.closeThisDialog():

    关闭当前iframe类型弹窗,针对type:2的弹窗,在弹窗的子页面调用即可关闭当前的iframe弹窗。

    admin.closeDialog('#xxx'):

    关闭非iframe类型的弹窗,调用需要传递弹窗页面里面任意一个的元素。

    关闭弹窗还可以使用ew-event操作:

    <!-- 关闭弹窗(智能) --> <button ew-event="closeDialog"></button> <!-- 关闭iframe类型的弹窗 --> <button ew-event="closeIframeDialog"></button> <!-- 关闭页面层的弹窗 --> <button ew-event="closePageDialog"></button>

    使用url方式更符合单页面,admin模块还封装了弹窗参数传递等更多方法,请到弹窗专题查看。

     

    3.3.加载层loading

    按钮loading:

    admin.btnLoading('#btn1'); // 设置按钮为loading状态 admin.btnLoading('#btn1', false); // 移除按钮的loading状态 admin.btnLoading('#btn1', ' 保存...'); // 设置按钮为loading状态,同时修改按钮文字

    页面加载层:

    admin.showLoading('#xxx'); // 在id为xxx的元素中显示加载层 admin.showLoading('#xxx', 1, '.8'); // 显示type为1、透明度为0.8的遮罩层 // 尺寸控制,提供有两种尺寸,默认是sm小型尺寸,还可以选md大型尺寸 admin.showLoading({ elem: '#xxx', type: 1, size: 'sm' }); 参数一 elem  非必填 元素选择器,不填为body参数二 type  非必填 动画类型(1 小球,2 魔方,3信号,4简约),默认1参数三 opacity非必填 透明度(0 - 1),默认不透明参数四 size  非必填  尺寸,默认sm

    移除加载动画:

    admin.removeLoading('#xxx'); admin.removeLoading('#xxx', true, true); 参数一  非必填 元素选择器,不填为body参数二  非必填 true是淡出效果,false直接隐藏,默认是true参数三  非必填 true是删除,false是隐藏不删除,默认是false

    页面载入的加载动画:

    <body class="page-no-scroll"> <!-- page-no-scroll这个不要忘了 --> <!-- 小球样式 --> <div class="page-loading"> <div class="ball-loader"> <span></span><span></span><span></span><span></span> </div> </div> <!-- 魔方样式 --> <div class="page-loading"> <div class="rubik-loader"></div> </div> <!-- 信号样式 --> <div class="page-loading"> <div class="signal-loader"> <span></span><span></span><span></span><span></span> </div> </div> <!-- 简约样式 --> <div class="page-loading"> <div class="layui-loader"> <i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i> </div> </div> <!-- 加sm是小型尺寸 --> <div class="page-loading"> <div class="signal-loader sm"> <span></span><span></span><span></span><span></span> </div> </div> </body>

    写在页面中需要在js中调用admin.removeLoading()移除加载动画。

     

    3.4.ajax封装

    req方法:

    admin.req('url', { username: 'admin', password: '123456' }, function(res){ alert(res.code + '-' + res.msg); }, 'get', { headers: {} }); 参数一   请求的url,前面会自动加setter.baseServer参数二   非必填,请求参数参数三   请求回调(网络错误也进此回调,404、403等)参数四   非必填,请求方式,get、post、put、delete等,默认get参数五   非必填,ajax的更多参数,如headers、dataType等

    req的这五个参数是自动像左补齐的,可以简写:

    // 无参数,get请求 admin.req('url', function(res){ console.log(res); }); // post提交 admin.req('url', function(res){ console.log(res); }, 'post'); admin.req('url', { username: 'xxx', password: '123456' }, function(res){ console.log(res); }, 'post'); // 参数使用JSON.stringify()会自动增加contentType为json admin.req('url', JSON.stringify(obj), function(res){ console.log(res); }, 'post'); // 相当于 admin.req('url', JSON.stringify(obj), function(res){ console.log(res); }, 'post', { contentType: 'application/json' }); // 参数使用表单序列化 admin.req('url', $('#demoForm').serialize(), function (res) { console.log(res); }, 'post', { contentType: 'application/x-www-form-urlencoded' });

    ajax方法,参数同$.ajax:

    admin.ajax({ url: 'url', data: {}, headers: {}, type: 'post', dataType: 'json', success: function(res){ alert(res.code + '-' + res.msg); } });

    自动传递header和预处理:

    在module/setter.js(原config.js)中通过下面两个方法操作:

    var setter = { // 自动传递header getAjaxHeaders: function (url) { var headers = []; headers.push({name: 'token', value: 'xxxxx'}); return headers; }, // 请求完成后预处理 ajaxSuccessBefore: function (res, url, obj) { if(res.code == 401) { alert('登录超时,请重新登录'); // obj.reload(); // 重新发起请求 // obj.update({}); // 修改res数据 // obj.xhr // ajax原始的xhr对象 return false; // 返回false阻止代码执行 } return true; } };

    req和ajax都实现了自动传递header、预处理、网络错误也回调到success(404、500等错误)。

     

    3.5.缓存操作putTempData

    admin.putTempData('key', 'value'); // sessionStorage存储 admin.putTempData('key'); // 不写value是删除 admin.putTempData('key', 'value', true); // localStorage存储 admin.putTempData('key', true); // 不写value是删除 admin.getTempData('key'); // 获取sessionStorage存储的key admin.getTempData('key', true); // 获取localStorage存储key admin.getTempData(); // 获取sessionStorage存储的全部数据 admin.getTempData(true); // 获取localStorage存储的全部数据

     

    3.6.锁屏功能

    admin.lockScreen(url); // 锁屏,url是锁屏页面地址,不填为默认地址 admin.unlockScreen(); // 解除锁屏(隐藏锁屏页面) admin.unlockScreen(true); // 移除锁屏页面,下次锁屏需要重新加载页面

    如果是自定义锁屏页面,页面不要包含head、body这些东西,只是代码片段,参考默认的锁屏页面。

     

    3.7.ew-event事件绑定

    使用示例:

    <a ew-event="fullScreen">全屏</a> <a ew-event="flexible">折叠导航</a> 事件描述flexible折叠侧导航refresh刷新主体部分closeThisTabs关闭当前选项卡closeOtherTabs关闭其他选项卡closeAllTabs关闭全部选项卡leftPage左滚动选项卡rightPage右滚动选项卡  closeDialog关闭当前弹窗(智能)closeIframeDialog关闭当前iframe层弹窗closePageDialog关闭当前页面层弹窗  theme打开主题设置弹窗note打开便签弹窗message打开消息弹窗psw打开修改密码弹窗logout退出登录  fullScreen全屏切换back浏览器后退lockScreen锁屏  open打开弹窗popupRight打开右侧弹窗

    ew-event属性可用于任何元素,不仅仅是a标签,theme、note等可以通过data-url属性配置对应的url, 还可以通过data-window="top"属性配置在父页面处理事件。

    <a ew-event="theme" data-url="xxx.html" data-window="parent">主题</a>

    自定义事件,添加下面代码即可,建议放在main.js中:

    admin.events.xxx = function(){ layer.msg($(this).text()); } <a ew-event="xxx">测试</a>

     

    3.8.open弹窗事件

    open和popupRight这两个事件是用来支持非js方式打开弹窗:

    <button ew-event="open" data-type="2" data-content="http://baidu.com">iframe弹窗</button> <button ew-event="open" data-type="1" data-url="form.html">页面弹窗</button> <button ew-event="open" data-type="1" data-content="#userForm">页面弹窗</button> <form id="userForm">......省略</form> <!-- 设置area和offset --> <button ew-event="open" data-type="1" data-content="Hello" data-area="80px,60px" data-offset="10px,10px">页面弹窗</button> <!-- popupRight一样的用法 --> <button ew-event="popupRight" data-type="2" data-url="http://baidu.com" data-title="百度一下,你就知道">右侧弹窗</button> <!-- function类型参数写法,success、end等 --> <button ew-event="open" data-type="1" data-content="Hello" data-success="onDialogSuccess">页面弹窗</button> <script> layui.use(['layer'], function(){ var layer = layui.layer; // 方法需要加window window.onDialogSuccess = function(){ layer.msg('弹窗被成功打开了'); }; }); </script> <!-- 加data-window="top"相当于top.layui.admin.open --> <button ew-event="open" data-type="2" data-content="http://baidu.com" data-window="top">iframe弹窗</button>

    layer支持的参数大部分都可以通过data属性来设置,数组类型用逗号分隔,function类型需要把作用域放在window对象下, 也可以直接写js比如data-success="layer.msg('打开了弹窗')"。

     

    3.9.logout事件

    <a ew-event="logout" data-url="login.html" data-ajax="api/logout" data-method="post" data-code="200" data-parse-data="return {code: res.status, msg: res.message}" data-confirm="false">退出登录</a> data-url        必填 退出登录后跳转的页面地址data-ajax     非必填 退出登录需要请求的ajax接口data-method      非必填 ajax请求方式,默认是deletedata-code     非必填 ajax返回成功的状态码,默认是0data-parse-data  非必填 处理接口返回的数据data-confirm    非必填 是否显示询问框,false表示直接退出不询问,默认true

     

    3.10.判断权限hasPerm

    通过admin.hasPerm(auth)可以控制按钮级别的权限隐藏:

    if(!admin.hasPerm('user:add')) { $('#btnUserAdd').remove(); } hasPerm方法需要通过setter.getUserAuths方法来获取全部权限setter.getUserAuths是通过setter.getUser方法从用户信息中获取权限的setter.getUser是从本地缓存中获取用户信息的,setter.putUser把用户信息放入缓存中

    在main.js中有获取用户信息并通过setter.putUser放入缓存中的写法。

    还可以通过加属性的方式来隐藏:

    <button perm-show="user:add">添加</button>

    perm-show可以用于任意元素,对于动态添加的元素调用admin.renderPerm()来更新渲染,比如表格应该写在done回调里面:

    table.render({ elem: '#userTable', url: '../../json/user.json', toolbar: ['<div>', '<button perm-show="user:add" lay-event="add" class="layui-btn">添加</button>', '<button perm-show="user:del" lay-event="del" class="layui-btn">删除</button>', '</div>'].join(''), cols: [[ {type: 'numbers'}, {field: 'username', title: '账号', sort: true}, {field: 'nickName', title: '用户名', sort: true}, {title: '操作', toolbar: '#userTbBar', align: 'center', minWidth: 200} ]], done: function() { admin.renderPerm(); } });

     

    4.1.文字提示

    鼠标滑过弹出tips,使用示例:

    <button lay-tips="大家好!">按钮</button> <button lay-tips="大家好!" lay-direction="2" lay-bg="#009788">按钮</button> <button lay-tips="大家好!" lay-offset="10px" lay-bgImg="linear-gradient(to right,#8510FF,#D025C2,#FF8B2D,#F64E2C)">按钮</button> <button lay-tips="大家好!" lay-offset="-10px,-10px" lay-padding="5px">按钮</button> lay-direction: 设置位置,1上面(默认)、2右边、3下面、4左边lay-bg: 设置背景颜色(包含箭头颜色,下面的背景图片不包含箭头)lay-offset: 设置偏移距离,(上,左)lay-padding:内间距lay-color:文字颜色lay-bgImg:背景图片,例如lay-bgImg="url(assets/images/head.jpg)"lay-fontSize:字体大小

    除了elem和text其他都是可选参数,还可以使用admin.tips()直接调用:

    admin.tips({ elem: '#btn', text: 'Hello', direction: 3, bg: '#803ed9', offset: '-10px,-10px', padding: '15px', color: '#eee', bgImg: 'linear-gradient(to right,#8510FF,#D025C2,#FF8B2D,#F64E2C)', fontSize: '18px', tipsMore: true, time: -1 });

     

    4.2.地图选择位置

    admin.chooseLocation({ needCity: true, onSelect: function (res) { layer.msg(JSON.stringify(res), {icon: 1}); } }); 参数默认描述title"选择位置"弹窗标题needCityfalse是否返回行政区,省市区默认不返回center定位当前城市地图默认的中心点defaultZoom11地图默认缩放级别pointZoom17选中时地图的缩放级别keywords无poi检索关键字,例如:建筑、写字楼pageSize30poi检索最大数量onSelect无选择回调mapJsUrl内置高德地图js的url 地图默认中心点参考值:[116.397428, 39.90923],经度,纬度地图url参考值:https://webapi.amap.com/maps?v=1.4.14&key=xxxxxxx返回结果说明: res.name; // 地点名称res.address; // 详细地址res.lat; // 纬度res.lng; // 经度res.city; // 城市,是一个对象res.city.province; // 省res.city.city; // 市res.city.district; // 区res.city.citycode; // 城市代码

    地图相关参数的详细介绍请前往高德地图API查看。

     

    4.3.裁剪图片

    admin.cropImg({ aspectRatio: 1/1, imgSrc: '../../assets/images/15367146917869444.jpg', onCrop: function (res) { // 返回的res是base64编码的裁剪后的图片 layer.msg('<img src="' + res + '" width="220px" height="220px"/>'); } }); 参数默认描述title"裁剪图片"弹窗标题aspectRatio1/1裁剪比例,例如:16/9imgSrc无要裁剪的图片,无则先弹出选择图片imgType'image/jpeg'裁剪的图片类型,非必填onCrop无裁剪完成回调limitSize不限制限制选择的图片大小acceptMime'image/*'限制选择的图片类型exts不限制限制选择的图片后缀 acceptMime参考值:'image/jpg, image/png'(只显示 jpg 和 png 文件)exts参考值:jpg|png|gif|bmp|jpeg

    后面三个参数配置可参考upload模块, 如果想单独在页面中使用图片裁剪功能请参考Cropper插件文档

     

    4.2.动画数字

    <h2 id="demoAnimNum1">12345</h2> <h2 id="demoAnimNum2">¥2373467.342353</h2> <h2 id="demoAnimNum3">上浮99.98%</h2> <script> layui.use(['admin'], function () { var $ = layui.jquery; var admin = layui.admin; admin.util.animateNum('#demoAnimNum1'); admin.util.animateNum('#demoAnimNum2'); admin.util.animateNum('#demoAnimNum3', true, 500, 100); }); </script> 参数一   需要动画的元素参数二   是否开启千分位,开启后每进千加逗号分隔参数三   动画间隔,默认500参数四   动画粒度,默认100

    此方法会智能过滤除数字外的字符,如果动态了修改了数字应该加$('#xx').data('num', '');重置一下。

     

    4.3.经纬度转换

    快速使用:

    // GCJ02转BD09 var point = admin.util.Convert_GCJ02_To_BD09({lat: 30.505674, lng: 114.40043}); console.log(point.lng + ',' + point.lat); // BD09转GCJ02 var point = admin.util.Convert_BD09_To_GCJ02({lat: 30.512004, lng: 114.405701}); console.log(point.lng + ',' + point.lat); 高德地图、腾讯地图以及谷歌中国区地图使用的是GCJ-02坐标系百度地图使用的是BD-09坐标系

    不同的坐标系之间会有几十到几百米的偏移,所以在开发基于地图的产品时,可以通过此方法修正不同坐标系之间的偏差, 详细了解国内各坐标系。

     

    4.4.深度克隆对象

    var o1 = {name: 'xxx', role: ['admin', 'user']}; var o2 = admin.util.deepClone(o1);

    对象型在参数传递时通常是引用传递,有时需要把对象克隆一份再传递,避免传递的参数被修改导致第二次传递出现问题。

     

    4.5.判断富文本是否为空

    admin.util.fullTextIsEmpty('<p><span>哈哈</span><img src="xxx.jpg"/>');

    判断规则,有文字,有img、audio、video、iframe等标签都属于不为空。

     

    4.6.移除指定style

    <div style="color: red;background-color: green;">Hello</div>

    像上面这样有多个内联样式style,如何只移除其中一个或多个呢:

    admin.util.removeStyle('background-color'); admin.util.removeStyle(['background-color', 'color']);

     

    4.7.模板引擎

    var html = admin.util.tpl('<p>{{d.name}}</p>', {name: 'xxx'}, '{{', '}}'); 参数一   模板内容参数二   填充数据参数三   非必填,边界符,默认{{参数四   非必填,边界符,默认}}

    它与laytpl使用方式一致,并且解决了laytpl对js注释支持不友好,laytpl模板中有js注释会导致最后渲染的内容有问题。

    加载独立页面:

    <div id="demo1"></div> <script> layui.use(['layer', 'admin'], function () { var $ = layui.jquery; var admin = layui.admin; admin.ajax({ url: 'xxx.html', dataType: 'html', success: function (html) { $('#demo1').html(admin.util.tpl(html, {name: 'xxx'})); } }); }); </script>

    独立页面xxx.html:

    <div>{{name}}</div> <script> layui.use(['layer'], function () { // 我可以加注释哦,laytpl不可以哦 layui.layer.msg('Hello 我被加载了'); }); </script>

     

    4.8.滚动到顶部

    admin.util.scrollTop(); // 主体部分滚动到顶部 admin.util.scrollTop('html,body'); // 自定义元素滚动到顶部 admin.util.scrollTop('#xxDiv'); // 自定义元素滚动到顶部

    由于spa版本多标签和单标签的滚动条所在元素都不一样,而且也不在body上, 所以封装了scrollTop方法可自动判断主体部分滚动条所在的元素。

     

    4.9.事件监听

    监听侧边栏折叠/展开:

    admin.on('flexible', function (d) { setTimeout(function () { myCharts1.resize(); }, 360); });

    一般用于更新echarts尺寸等,要延迟360毫秒再更新,因为折叠展开有个过渡效果。

    监听页面被卸载:

    admin.on('destroy(plugin/other/editor)', function () { tinymce.get('demoEditor').destroy(false); });

    括号里面是页面的路径地址,没有#号,可用于销毁定时器、组件等。

    监听页面进入前台:

    layui.admin.on('show(console/console)', function () { myCharts1.resize(); });

    括号里面是页面的路径地址,没有#号,一般用于更新echarts尺寸等,比如打开了两个标签页, 缩放屏幕大小再进入另一个标签页,echarts尺寸不会自动变化,可以监听页面进入前台并更新尺寸。

    其他事件监听:

    /* 监听tab切换事件 */ admin.on('tab', function (d) { // d.layId表示当前tab的url }); // 监听tab关闭事件 admin.on('tabDelete', function (d) { // d.layId表示当前tab的url }); /* 监听多系统切换事件 */ admin.on('nav', function (d) { // d.navId表示当前多系统的navId });

    实现刷新页面记忆折叠状态,在main.js增加:

    admin.on('flexible', function (d) { admin.putTempData('nav-expand', d.expand); }); var expand = admin.getTempData('nav-expand'); if (expand !== undefined) admin.flexible(expand);

     

    4.10.动态模板

    直接赋值数据:

    <script type="text/html" ew-tpl="['a','b','c']" data-done="layui.form.render()"> <div> {{# layui.each(d,function(i,item){ }} <div>{{item}}</div> {{# }); }} </div> </script> <!-- 也可以引用变量 --> <script id="userListTpl" type="text/html" ew-tpl="userList"> <div> {{# if(d){ }} <!-- 这里判断以下因为可能值还没定义 --> {{# layui.each(d,function(i,item){ }} <div>{{item}}</div> {{# }); }} {{# } }} </div> </script> <script> layui.use(['admin'], function() { window.userList = ['a', 'b', 'c']; // admin模块一加载会自动渲染,但userList还未定义,所以定义完要重新渲染 admin.renderTpl('#userListTpl'); }); </script>

    使用远程数据,注意要加引号'user.json':

    <script type="text/html" ew-tpl="'user.json'" data-method="post" data-where="{sex:'女'}" data-headers="{token: 'xxx'}"> <div> {{# layui.each(d.data,function(i,item){ }} <div>{{item.username}}</div> {{# }); }} </div> </script>

    通过ew-tpl来表示这是一个动态模板以及设置数据源,通过data-xxx配置其他参数:

    done   渲染完成后的回调url   远程数据的urlmethod   远程数据的请求方式where   远程数据的请求条件,也可以data-where="JSON.stringify({})"headers   远程数据的请求headercontent-type   如data-content-type="application/json;charset=UTF-8"

    注意远程数据url一定要加引号,加引号的好处你还可以这样使用:

    ew-tpl=" layui.setter.baseServer + '/user.json' "

    动态模板会在页面加载后自动渲染,如果要重新渲染:

    admin.renderTpl('#userListTpl'); // 参数为模板的jquery选择器

    使用例子,比如用户管理的搜索里面的性别下拉换成动态的:

    <!-- 表格工具栏 --> <form class="layui-form toolbar"> <div class="layui-form-item"> <div class="layui-inline"> <label class="layui-form-label">性 别:</label> <script type="text/html" ew-tpl="'../../json/sex.json'" data-done="layui.form.render('select');"> <div class="layui-input-inline"> <select name="sex"> <option value="">选择性别</option> {{# layui.each(d.data,function(i,item){ }} <option value="{{item.value}}">{{item.name}}</option> {{# }); }} </select> </div> </script> </div> </div> </form> <!-- 数据表格 --> <table id="userTable" lay-filter="userTable"></table>

    sex.json数据:

    {"code": 200, "data": [{"name": "男", "value": 0}, {"name": "女", "value": 1}]}

    注意这里有个小细节,select上面还有一个div,对于select的动态模板,建议select外面最好多一层,因为select会被layui美化, 外面不加一层当重新渲染模板的时候不能把layui美化的旧的select移除,另外ew-tpl="'sex.json'"这里先是双引号再是单引号,不要漏掉了。

     

     

    5.1.公共类

    类名(class)说明pull-left左浮动pull-right右浮动text-left内容居左text-center内容居中text-right内容居右inline-block设置display为inline-blockbg-white设置背景为白色layui-link设置a标签颜色为主题色layui-text.layui-text下面的a标签为蓝色  text-muted文字颜色为灰色text-success文字颜色为绿色,成功色text-warning文字颜色为黄色警告色text-danger文字颜色为红色危险色text-info文字颜色为蓝色信息色text-primary文字颜色为主题色

    以上是easyweb增加的公共类,当然也可以使用Layui公共类。

     

    5.2.组件样式

    类名(class)说明icon-btn带图标的按钮,会缩小边距icon-date在元素的右边加入日期的图标icon-search在元素的右边加入搜索的图标btn-circle圆形按钮,参见便签界面  arrow2设置侧边栏小三角为箭头图标,加在layui-nav上arrow3设置侧边栏小三角为加减号图标,加在layui-nav上  close-footer关闭页脚,加在body上hide-body-title全局隐藏单标签模式标题栏,加在body上  table-tool-mini数据表格工具栏mini样式,加在table父元素上full-table针对full-xxx的table的工具栏mini样式  mini-bar如果有滚动条,使用细的风格layui-form-select-top控制下拉框上弹出,加载select父元素上ew-tb-cell-ck数据表格里面checkboxew-field-groupeasyweb的字段集辅助类 <!-- 图标按钮 --> <button class="layui-btn icon-btn"><i class="layui-icon"></i>搜索</button> <!-- 日期图标 --> <input class="layui-input icon-date" type="text"/> <!-- 搜索图标 --> <input class="layui-input icon-search" type="text"/> <!-- 圆形按钮 --> <div class="btn-circle"> <i class="layui-icon layui-icon-add-1"></i> </div> <!-- 下拉框上弹出 --> <div class="layui-form-select-top"> <select>....</select> </div> <!-- 关闭页脚 --> <body class="layui-layout-body close-footer"> <!-- 表格工具栏mini样式 --> <div class="table-tool-mini full-table"> <table id="xxTable" lay-filter="xxTable"></table> </div> <!-- 字段集嵌套数据表格 --> <div class="ew-field-group"> <fieldset class="layui-elem-field"> <legend>我是标题</legend> </fieldset> <div class="ew-field-box"> <table id="demoFieldTb" lay-filter="demoFieldTb"></table> </div> </div>

      

     

    5.3.表单弹窗

    类名(class)说明model-form调整弹窗内的表单的间距使之更好看model-form-body表单内容部分,高度自适应,超过屏幕高度显示滚动条model-form-footer表单底部按钮部分,用于固定底部按钮layui-form-required表单必填项加红色星号

    表单弹窗示例:

    <script type="text/html" id="modelUser"> <form id="modelUserForm" lay-filter="modelUserForm" class="layui-form model-form"> <input name="userId" type="hidden"/> <div class="layui-form-item"> <label class="layui-form-label layui-form-required">账号</label> <div class="layui-input-block"> <input name="username" placeholder="请输入账号" class="layui-input"/> </div> </div> <div class="layui-form-item text-right"> <button class="layui-btn layui-btn-primary" type="button" ew-event="closePageDialog">取消</button> <button class="layui-btn" lay-filter="modelSubmitUser" lay-submit>保存</button> </div> </form> </script> <script> layui.use(['admin'],function(){ var admin = layui.admin; admin.open({ type: 1, title: '添加用户', content: $('#modelUser').html(), success: function (layero, dIndex) { // 表单的操作,事件绑定等都写在success回调里面 } }); }); </script>

    固定底部操作按钮示例:

    <script type="text/html" id="modelUser"> <form class="layui-form model-form no-padding" id="modelUserForm" lay-filter="modelUserForm"> <div class="model-form-body" style="max-height: 320px;"> <!-- 如果要超出屏幕才固定底部,不要写max-height --> <div class="layui-form-item"> <label class="layui-form-label">实习公司</label> <div class="layui-input-block"> <input name="companyName" class="layui-input"/> </div> </div> <!-- ......省略 --> </div> <div class="layui-form-item text-right model-form-footer"> <button class="layui-btn layui-btn-primary" type="button" ew-event="closePageDialog">取消</button> <button class="layui-btn" lay-filter="modelSubmitUser" lay-submit>保存</button> </div> </form> </script>

    固定底部按钮需要model-form-body和model-form-footer,普通表单弹窗只需要model-form

     

    5.4.表格工具栏

    类名(class)说明toolbar调整表格上面的表单间距使之更好看w-auto设置width:auto,用于重置一些有固定宽度表单元素mr0设置margin-right:0,用于重置一些表单元素的样式  form-search-show-expand点击了展开才显示出来form-search-expand表格搜索栏展开\折叠按钮默认样式 <!-- 表格顶部工具栏区域 --> <div class="layui-form toolbar"> <div class="layui-form-item"> <div class="layui-inline"> <label class="layui-form-label w-auto">账 号:</label> <div class="layui-input-inline mr0"> <input name="username" class="layui-input" type="text" placeholder="输入账号"/> </div> </div> <!-- 加了form-search-show-expand类在展开的时候才显示 --> <div class="layui-inline form-search-show-expand"> <label class="layui-form-label w-auto">用户名:</label> <div class="layui-input-inline mr0"> <input name="nickName" class="layui-input" type="text" placeholder="输入用户名"/> </div> </div> <div class="layui-inline"> <button class="layui-btn icon-btn" lay-filter="formSubSearchUser" lay-submit> <i class="layui-icon"></i>搜索 </button> <!-- 添加这个按钮可展开/折叠表单 --> <a class="layui-btn form-search-expand" search-expand> 展开 <i class="layui-icon layui-icon-down"></i> </a> </div> </div> </div> <!-- 表格 --> <table id="tableUser" lay-filter="tableUser"></table>

    移动端自动适配效果:

    表格搜索折叠/展开事件监听:

    <!-- 直接写js --> <a class="layui-btn" search-expand="d.expand?layer.msg('展开了'):layer.msg('折叠了')"> 展开 <i class="layui-icon layui-icon-down"></i> </a> <!-- 调用方法 --> <a class="layui-btn" search-expand="onExpandChange(d)"></a> <script> layui.use(['layer'], function () { window.onExpandChange = function(d){ console.log(d); // d包含d.expand,d.elem } }); </script>

     

    5.5.垂直选项卡

    只需要在layui-tab的基础上多加一个layui-tab-vertical类即可实现:

    <div class="layui-tab layui-tab-vertical"> <ul class="layui-tab-title"> <li class="layui-this">系统管理</li> <li>用户管理</li> <li>权限分配</li> </ul> <div class="layui-tab-content"> <div class="layui-tab-item layui-show">内容1</div> <div class="layui-tab-item">内容2</div> <div class="layui-tab-item">内容3</div> </div> </div>

    如果要修改选项卡标题的宽度:

    <!-- title和content两处地方都需要修改 --> <div class="layui-tab layui-tab-vertical"> <ul class="layui-tab-title" style="width: 200px;">......省略</ul> <div class="layui-tab-content" style="margin-left: 200px;">......省略</div> </div>

    如果要选项卡的标题在右侧,再多加一个layui-tab-vertical-right类即可:

    <div class="layui-tab layui-tab-vertical layui-tab-vertical-right"> <ul class="layui-tab-title" style="width: 200px;">......省略</ul> <div class="layui-tab-content" style="margin-right: 200px;">......省略</div> </div>

    选项卡的灰色分隔线的高度是标题区域的高度,如果当内容高度高于标题区域高度时想要分隔线的高度最大:

    <!-- 多加一个`layui-tab-vertical-full`类就可以了 --> <div class="layui-tab layui-tab-vertical layui-tab-vertical-full"> <ul class="layui-tab-title">......省略</ul> <div class="layui-tab-content">......省略</div> </div>

    垂直选项卡中使用栅格布局样式错位,在layui-row上加一些样式:

    <div class="layui-tab layui-tab-vertical"> <ul class="layui-tab-title"> <li class="layui-this">系统管理</li> <li>用户管理</li> </ul> <div class="layui-tab-content"> <div class="layui-tab-item layui-show">内容1</div> <div class="layui-tab-item"> <div class="layui-row" style="float: left;width: 100%;"> <div class="layui-col-md6"> 内容2 </div> <div class="layui-col-md6"> 内容使用栅格 </div> </div> </div> </div> </div>

     

    5.6.徽章扩展

    <span class="layui-badge layui-badge-green">绿色</span> <span class="layui-badge layui-badge-blue">蓝色</span> <span class="layui-badge layui-badge-red">红色</span> <span class="layui-badge layui-badge-yellow">黄色</span> <span class="layui-badge layui-badge-gray">灰色</span>

    用layui-badge-list包裹,会有更好的间距和尺寸:

    <div class="layui-badge-list"> <span class="layui-badge layui-badge-gray">很有想法的</span> <span class="layui-badge layui-badge-gray">专注设计</span> <span class="layui-badge layui-badge-gray">辣~</span> <span class="layui-badge layui-badge-gray">大长腿</span> <span class="layui-badge layui-badge-gray">川妹子</span> <span class="layui-badge layui-badge-gray">海纳百川</span> </div>

     

    5.7.下拉树单选

    <div id="demoSel" class="ew-xmselect-tree"></div>

    xmSelect下拉单选树增加一个ew-xmselect-tree可以有更好的样式。

     

    5.8.fixed方式select

    只需要在select的父元素上面增加class ew-select-fixed 即可:

    <div style="height: 80px;overflow: auto;" onscroll="layui.admin.hideFixedEl();"> <div class="ew-select-fixed"> <select name="ptTypeId"> <option value="">请选择</option> <option value="1">选项一</option> <option value="2">选项二</option> </select> </div> </div>

    fixed定位的select用在数据表格中不需要对表格做任何修改就可以显示出来,还可以用在带有滚动表的容器中,比如一个很长的表单弹窗, 一定高度后显示滚动条,里面select是无法越出滚动条容器显示的,使用fixed方式的select即可超出容器的滚动条显示, 使用了fixed定位后外层容器滚动select不会跟随滚动,可在容器上添加滚动时收起select。

     

    6.1.1.快速使用

    <!-- click模式触发 --> <div class="dropdown-menu"> <button class="layui-btn icon-btn"> Click me <i class="layui-icon layui-icon-drop"></i> </button> <ul class="dropdown-menu-nav"> <li><a>1st menu item</a></li> <li><a>2nd menu item</a></li> <li><a>3rd menu item</a></li> </ul> </div> <!-- hover模式触发,增加dropdown-hover即可 --> <div class="dropdown-menu dropdown-hover"> <button class="layui-btn icon-btn"> Hover me <i class="layui-icon layui-icon-drop"></i></button> <ul class="dropdown-menu-nav"> <li><a>1st menu item</a></li> <li><a>2nd menu item</a></li> <li><a>3rd menu item</a></li> </ul> </div> <script> layui.use(['dropdown'], function () { var dropdown = layui.dropdown; // 加载模块 }); </script>

     

    6.1.2.更多样式

    <!-- 标题及禁用样式 --> <div class="dropdown-menu dropdown-hover"> <button class="layui-btn icon-btn"> 更多样式 <i class="layui-icon layui-icon-drop"></i></button> <ul class="dropdown-menu-nav"> <li class="title">HEADER</li> <li><a><i class="layui-icon layui-icon-star-fill"></i>1st menu item</a></li> <li class="disabled"><a><i class="layui-icon layui-icon-template-1"></i>2nd menu item</a></li> <hr> <li class="title">HEADER</li> <li><a><i class="layui-icon layui-icon-set-fill"></i>3rd menu item</a></li> </ul> </div> <!-- 带小三角样式 --> <div class="dropdown-menu dropdown-hover"> <button class="layui-btn icon-btn"> 带小三角 <i class="layui-icon layui-icon-drop"></i> </button> <ul class="dropdown-menu-nav"> <div class="dropdown-anchor"></div><!-- 多加一个这个即可 --> <li><a>1st menu item</a></li> <li><a>2nd menu item</a></li> <li><a>3rd menu item</a></li> </ul> </div> <!-- 暗色主题 --> <div class="dropdown-menu"> <button class="layui-btn layui-btn-normal icon-btn"> 暗色主题 <i class="layui-icon layui-icon-drop"></i></button> <ul class="dropdown-menu-nav dark"><!-- 加一个dark即可 --> <div class="dropdown-anchor"></div> <li class="title">HEADER</li> <li><a><i class="layui-icon layui-icon-star-fill"></i>1st menu item</a></li> <li class="disabled"><a><i class="layui-icon layui-icon-template-1"></i>2nd menu item</a></li> <hr> <li class="title">HEADER</li> <li><a><i class="layui-icon layui-icon-set-fill"></i>3rd menu item</a></li> </ul> </div>

     

    6.1.3.对任意元素使用

    <div class="dropdown-menu dropdown-hover"> <input type="text" placeholder="一个会跳舞的输入框" class="layui-input"/> <ul class="dropdown-menu-nav"> <li class="title">是不是在找</li> <li><a>另一个会跳舞的下拉框</a></li> <li><a>一杯忧郁的可乐</a></li> </ul> </div>

     

    6.1.4.带遮罩层

    遮罩层是分离式的绑定,通过data-dropdown绑定:

    <button class="layui-btn layui-btn-normal icon-btn" data-dropdown="#dropdown1"> 带遮罩层 <i class="layui-icon layui-icon-drop"></i> </button> <!-- 下拉菜单 --> <ul class="dropdown-menu-nav dropdown-bottom-right layui-hide" id="dropdown1"> <div class="dropdown-anchor"></div> <li class="title">HEADER</li> <li><a><i class="layui-icon layui-icon-star-fill"></i>1st menu item</a></li> <li class="disabled"><a><i class="layui-icon layui-icon-template-1"></i>2nd menu item</a></li> <hr> <li class="title">HEADER</li> <li><a><i class="layui-icon layui-icon-set-fill"></i>3rd menu item</a></li> </ul>

     

    6.1.5.自定义下拉内容

    <div class="dropdown-menu"> <button class="layui-btn layui-btn-normal icon-btn"> 克隆/下载 <i class="layui-icon layui-icon-drop"></i></button> <div class="dropdown-menu-nav dropdown-bottom-right" style="width: 280px;padding: 0 10px 10px 10px;"> <div class="dropdown-anchor"></div> <!-- 下面是自定义内容 --> <div class="layui-tab layui-tab-brief"> <ul class="layui-tab-title"> <li class="layui-this">HTTPS</li> <li>SSH</li> </ul> <div class="layui-tab-content" style="padding: 10px 0 10px 0;"> <div class="layui-tab-item layui-show"> <input class="layui-input" value="https://gitee.com/whvse/easyweb-jwt.git"/> </div> <div class="layui-tab-item"> <input class="layui-input" value="git@gitee.com:whvse/easyweb-jwt.git"/> </div> </div> </div> <button class="layui-btn layui-btn-sm layui-btn-fluid" style="margin-bottom: 10px;">Download ZIP</button> <img src="http://p1.music.126.net/voV3yPduAhNATICMRJza1A==/109951164017919367.jpg" width="100%"> <!-- //end.自定义内容结束 --> </div> </div>

     

    6.1.6.控制显示方向

    在dropdown-menu-nav上加下面的class可控制位置:

    类名位置dropdown-bottom-left下左弹出dropdown-bottom-center下中弹出dropdown-bottom-right下右弹出  dropdown-top-left上左弹出dropdown-top-center上中弹出dropdown-top-right上右弹出  dropdown-left-top左上弹出dropdown-left-center左中弹出dropdown-left-bottom左下弹出  dropdown-right-top右上弹出dropdown-right-center右中弹出dropdown-right-bottom右下弹出 <!-- Bottom Center --> <div class="dropdown-menu dropdown-hover"> <button class="layui-btn layui-btn-primary icon-btn">Bottom <i class="layui-icon layui-icon-drop"></i> Center </button> <ul class="dropdown-menu-nav dropdown-bottom-center"><!-- 这里加控制方向的类 --> <div class="dropdown-anchor"></div> <li><a>1st menu item</a></li> <li><a>2nd menu item</a></li> <li><a>3rd menu item</a></li> </ul> </div> <!-- Bottom Right --> <div class="dropdown-menu dropdown-hover"> <button class="layui-btn layui-btn-primary icon-btn">Bottom Right <i class="layui-icon layui-icon-drop"></i> </button> <ul class="dropdown-menu-nav dropdown-bottom-right"><!-- 这里加控制方向的类 --> <div class="dropdown-anchor"></div> <li><a>1st menu item</a></li> <li><a>2nd menu item</a></li> <li><a>3rd menu item</a></li> </ul> </div>

     

    6.1.7.在数据表格中使用

    数据表格中使用分离式的绑定,并且加no-shade="true"去掉遮罩层:

    <!-- 表格操作列 --> <script type="text/html" id="tableBar"> <a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="edit">修改</a> <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a> <!-- 下拉菜单 --> <a class="layui-btn layui-btn-xs" data-dropdown="#dropUser{{d.LAY_INDEX}}" no-shade="true"> 更多<i class="layui-icon layui-icon-drop" style="font-size: 12px;margin-right: 0;"></i></a> <ul class="dropdown-menu-nav dropdown-bottom-right layui-hide" id="dropUser{{d.LAY_INDEX}}"> <div class="dropdown-anchor"></div> <li><a lay-event="edit2"><i class="layui-icon layui-icon-edit"></i>修改用户</a></li> <li><a lay-event="del2"><i class="layui-icon layui-icon-delete"></i>删除用户</a></li> <li><a lay-event="lock2"><i class="layui-icon layui-icon-password"></i>锁定用户</a></li> </ul> </script> <script> layui.use(['table', 'dropdown'], function () { var table = layui.table; table.render({ cols: [[ {field: 'username', title: '账号'}, {toolbar: '#tableBar', title: '操作'} ]] }); }); </script>

     

    6.1.8.气泡确认框

    <!-- 下弹出 --> <div class="dropdown-menu"> <button class="layui-btn layui-btn-primary icon-btn"> 气泡确认框 <i class="layui-icon layui-icon-drop"></i></button> <div class="dropdown-menu-nav dropdown-popconfirm"> <div class="dropdown-anchor"></div> <div class="dropdown-popconfirm-title"> <i class="layui-icon layui-icon-help"></i>这是一段内容确定删除吗? </div> <div class="dropdown-popconfirm-btn"> <button class="layui-btn" btn-cancel>取消</button> <button class="layui-btn layui-btn-normal">确定</button> </div> </div> </div> <!-- 上弹出 --> <div class="dropdown-menu"> <button class="layui-btn layui-btn-primary icon-btn"> 气泡确认框 <i class="layui-icon layui-icon-drop"></i></button> <div class="dropdown-menu-nav dropdown-popconfirm dropdown-top-right"> <div class="dropdown-anchor"></div> <div class="dropdown-popconfirm-title"> <i class="layui-icon layui-icon-about"></i>这是一段内容确定删除吗? </div> <div class="dropdown-popconfirm-btn"> <button class="layui-btn" btn-cancel>取消</button> <button class="layui-btn layui-btn-normal">确定</button> </div> </div> </div>

     

    6.2.1.快速使用

    layui.use(['notice'], function(){ var notice = layui.notice; // 消息通知 notice.success({ title: '消息通知', message: '你有新的消息,请注意查收!' }); // 提示框,1成功、2失败、3警告、4加载、5信息(蓝色图标) notice.msg('Hello', {icon: 1}); });

     

    6.2.2.全部方法

    方法参数说明success(object)见下方成功消息(绿色)warning(object)见下方警告消息(黄色)error(object)见下方错误消息(红色)info(object)见下方通知消息(蓝色)show(object)见下方自定义样式   msg(string, object)文本,其他参数提示框   destroy()无关闭全部hide(object, toast, closedBy)见下方关闭指定的通知settings(object)见下方统一设置默认值

    统一设置默认值:

    notice.settings({ timeout: 1500, transitionIn: 'flipInX', onOpened: function(){ console.log('notice opend!'); } });

    关闭指定的通知:

    notice.hide({}, document.querySelector('.toast')); 参数一   重写一些参数,比如关闭动画等参数二   根据自定义的className选择关闭的对象

     

    6.2.3.参数列表

    参数说明默认值可选值title标题无string类型message内容无string类型position显示位置topRight见下方transitionIn进入动画fadeInLeft见下方transitionOut退出动画fadeOutRight见下方timeout消失时间5000单位毫秒,false永不消失progressBar进度条truetrue显示、false不显示balloon气泡效果falsetrue开启、false关闭close关闭按钮truetrue显示,false不显示pauseOnHover鼠标滑过暂停消失时间truetrue、falseresetOnHover鼠标滑过重置消失时间falsetrue、falseanimateInside文字动画效果falsetrue开启、false关闭className自定义class无多个用空格分隔theme主题lightlight、darkaudio音效无1,2,3,4,5,6    image显示图片无图片地址imageWidth图片宽度60数字buttons显示按钮[][ [ 'btn1', function(){} ], ['btn2', function(){} ] ]overlay遮罩层falsetrue显示,false不显示drag滑动关闭truetrue开启,false关闭layout布局类型21标题和内容并排,2两排显示rtl布局方向falsefalse内容居左,true居右displayMode显示模式00无限制,1同类型存在不显示,2同类型存在先移除targetFirst插入方式自动true从上插入,false下插入onOpened打开后回调函数无functiononClosed关闭后回调函数无function    titleColor标题颜色默认颜色单位titleSize标题大小默认尺寸单位messageColor文字颜色默认颜色单位messageSize文字大小默认尺寸单位backgroundColor背景颜色默认颜色单位progressBarColor进度条颜色默认颜色单位maxWidth最大宽度空尺寸单位

    参数position显示位置可选值:

    属性说明bottomRight右下角bottomLeft左下角topRight右上角topLeft左上角topCenter顶部中间bottomCenter底部中间center正中间

    参数transitionIn进入动画可选值:

    属性说明bounceInLeft向左反弹bounceInRight向右反弹bounceInUp向上反弹bounceInDown向下反弹fadeIn淡入fadeInDown向下淡入fadeInUp向上淡入fadeInLeft向左淡入fadeInRight向右淡入flipInX翻转进入

    参数transitionOut退出动画可选值:

    属性说明fadeOut淡出fadeOutUp向上淡出fadeOutDown向下淡出fadeOutLeft向左淡出fadeOutRight向右淡出flipOutX翻转退出

     

    6.2.4.解决弹窗遮挡

    <!-- 页面加入样式 --> <style> body .iziToast-overlay { z-index: 19892001; } body .iziToast-wrapper { z-index: 19892002; } </style>

     

     

    6.3.1.快速使用

    <input id="demoCascader1" placeholder="请选择" class="layui-hide"/> <script> layui.use(['cascader'], function () { var $ = layui.jquery; var cascader = layui.cascader; cascader.render({ elem: '#demoCascader1', data: [{ value: 'beijing', label: '北京', children: [{ value: 'gugong', label: '故宫' },{ value: 'tiantan', label: '天坛' },{ value: 'wangfujing', label: '王府井' }] }] }); // 请求远程数据 cascader.render({ elem: '#demoCascader1', reqData: function (values, callback, data) { $.get('xxxx.json', function(res){ callback(res.data); // 数据请求完成通过callback回调 },'json'); } }); // 处理数据格式,如果你的数据没有value、label字段可以前端处理 cascader.render({ elem: '#demoCascader1', reqData: function (values, callback, data) { $.get('xxxx.json', function(res){ function each(data) { for (var i = 0; i < data.length; i++) { data[i].value = data[i].id; data[i].label = data[i].name; if (data[i].children) { each(data[i].children); } } } each(res.data); callback(res.data); },'json'); } }); // 如果你的数据不是children形式,可以前端转换 cascader.render({ elem: '#demoCascader1', reqData: function (values, callback, data) { $.get('xxxx.json', function(res){ callback(pidToChildren(res.data, 'id', 'pid', 0)); },'json'); } }); /* pid转children形式 */ function pidToChildren(data, idName, pidName, childName, pId) { if (!childName) childName = 'children'; var newList = []; for (var i = 0; i < data.length; i++) { if (data[i][idName] == data[i][pidName]) return; if (pId === undefined) pId = 0; if (data[i][pidName] == pId) { var children = pidToChildren(data, idName, pidName, childName, data[i][idName]); if (children.length > 0) data[i][childName] = children; newList.push(data[i]); } } return newList; } }); </script>

     

    6.3.2.异步加载

    <input id="demoCascader1" placeholder="请选择" class="layui-hide"/> <script> layui.use(['cascader'], function () { var $ = layui.jquery; var cascader = layui.cascader; cascader.render({ elem: '#demoCascader1', reqData: function (values, callback, data) { // values是当前所有选中的值,data是当前选中的对象 $.get('xxxx.json', { id: data.value }, function(res){ callback(res.data); // 数据请求完成通过callback回调 },'json'); } }); }); </script>

    异步加载的数据格式为:

    [ {value: 'beijing', label: '北京', haveChildren: true}, {value: 'jiangsu', label: '江苏', haveChildren: true} ]

    通过haveChildren字段来标识是否还有子节点,如果你的后台数据格式不是这样,可以在callback之前格式化:

    cascader.render({ elem: '#demoCascader1', reqData: function (values, callback, data) { // values是当前所有选中的值,data是当前选中的对象 $.get('xxxx.json', { id: data.value }, function(res){ var newList = []; for(var i=0;i<res.data.length;i++){ var item = res.data[i]; newList.push({ value: item.id, label: item.name, haveChildren: item.haveChildren }); } callback(newList); // 数据请求完成通过callback回调 },'json'); } });

     

    6.3.3.自定义分隔符

    <input id="demoCascader1" placeholder="请选择" class="layui-hide"/> <script> layui.use(['cascader'], function () { var $ = layui.jquery; var cascader = layui.cascader; cascader.render({ elem: '#demoCascader1', data: [], renderFormat: function (labels, values) { return labels.join(' / '); // 默认是用斜杠分割,可以自定义 } }); }); </script>

     

    <input id="demoCascader1" placeholder="请选择" class="layui-hide"/> <script> layui.use(['cascader'], function () { var $ = layui.jquery; var cascader = layui.cascader; cascader.render({ elem: '#demoCascader1', data: [], filterable: true // 这个参数是开启搜索功能 }); // 自定义搜索 cascader.render({ elem: '#demoCascader1', data: [], filterable: true, reqSearch: function (keyword, callback, dataList) { // keyword是搜索的关键字,dataList是当前的全部数据集合 $.get('xxx.json', { keyword: keyword }, function(res){ callback(res); },'json') } }); }); </script>

    搜索后端接口返回的数据格式为:

    [ {"value": "1,2", "label": "北京 / 王府井"}, {"value": "1,3", "label": "北京 / 故宫"} ]

    如果要标记关键字为红色:<span class=\"search-keyword\">北京</span> / 王府井

     

    6.3.5.省市区选择

    <input id="demoCascader1" placeholder="请选择" class="layui-hide"/> <script type="text/javascript" src="/assets/module/cascader/citys-data.js"></script> <script> layui.use(['cascader'], function () { var $ = layui.jquery; var cascader = layui.cascader; cascader.render({ elem: '#demoCascader1', data: citysData, itemHeight: '250px', filterable: true }); }); </script>

    省市区的数据已经封装好了,只需要引入数据的js即可,数据包含省市区,value是区号, 如果需要对数据进行处理,cascader封装了几种处理数据方法:

    // value也是中文而不是区号 var data = cascader.getCityData(admin.util.deepClone(citysData)); cascader.render({ elem: '#demoCascader11', data: data }); // 只显示省市,不要区域 var data = cascader.getCity(admin.util.deepClone(citysData)); // 只显示省份,不要市区 var data = cascader.getProvince(admin.util.deepClone(citysData)); // 只显示身份,并且value是中文,而不是区号 var data = cascader.getCityData(cascader.getProvince(admin.util.deepClone(citysData)));

     

    6.3.6.全部方法

    <input id="demoCascader1" placeholder="请选择" class="layui-hide"/> <script> layui.use(['cascader'], function () { var $ = layui.jquery; var cascader = layui.cascader; var ins1 = cascader.render({ elem: '#demoCascader1', data: [] }); ins1.data; // 获取当前的数据 ins1.open(); // 展开 ins1.hide(); // 关闭 ins1.removeLoading(); // 移除加载中的状态 ins1.setDisabled(true); // 禁用或取消禁用 ins1.getValue(); // 获取选中的数据值 ins1.getLabel(); // 选取选中的数据名称 ins1.setValue('1,2'); // 设置值 }); </script>

     

    6.3.7.全部参数

    参数名称介绍默认值elem需要渲染的元素 data数据 clearable是否开启清除trueclearAllActive清除时清除所有列选中falsetrigger次级菜单触发方式,可选'hover''click'disabled是否禁用falsechangeOnSelect是否点击每一项都改变值falsefilterable是否开启搜索功能falsenotFoundText搜索为空是提示文字'没有匹配数据'itemHeight下拉列表的高度'180px'reqData(values, callback, data)异步获取数据的方法 reqSearch(keyword, callback, dataList)自定义搜索的方法 renderFormat(labels, values)选择后用于展示的函数 onChange(values, data)数据选择改变的回调 onVisibleChange(isShow)展开和关闭的回调

     

     

    6.4.2.全部参数

    参数说明默认值defaultText提示文字+请输入skin样式风格 removeWithBackspace回退键可删除已添加的标签falsefocusWithClick点击已添加标签输入框获取焦点trueautocomplete_url自动提示接口url autocomplete接口配置 

    autocomplete参数:

    $('#demoTagsInput').tagsInput({ autocomplete_url: '../../json/tagsInput.json', autocomplete: { type: 'post', data: { access_token: 'xxxxx' } } });

     type是请求方式,默认是get请求,data是额外参数,请求autocomplete_url会传递name参数(输入框的值)。

    更详细的使用文档可以参考jQuery-Tags-Input。

    此插件基于 jQuery-Tags-Input 二次修改。

     

     

    6.5.1.快速使用

    <div class="split-group"> <div class="split-item" id="demoSplit1"> 面板一 </div> <div class="split-item" id="demoSplit2"> 面板二 </div> </div> <script> layui.use(['Split'], function () { var $ = layui.jquery; var Split = layui.Split; // 水平分割,需要分割的元素(id)、默认大小(百分比)、最小值(单位px) Split(['#demoSplit1', '#demoSplit2'], {sizes: [25, 75], minSize: 100}); }); </script>

     

    6.5.2.垂直分割

    <div class="split-group-vertical"> <div class="split-item" id="demoSplit3"> 面板一 </div> <div class="split-item" id="demoSplit4"> 面板二 </div> </div> <script> layui.use(['Split'], function () { var $ = layui.jquery; var Split = layui.Split; // 垂直分割 Split(['#demoSplit3', '#demoSplit4'], {direction: 'vertical'}); }); </script>

     

    6.5.3.嵌套使用

    <div class="split-group" style="height: 600px;"> <div class="split-item" id="demoSplit8"> <div class="split-group-vertical"> <div class="split-item" id="demoSplit10"> 面板一 </div> <div class="split-item" id="demoSplit11"> 面板二 </div> </div> </div> <div class="split-item" id="demoSplit9"> 面板三 </div> </div> <script> layui.use([Split'], function () { var $ = layui.jquery; var Split = layui.Split; // 垂直水平分割 Split(['#demoSplit8', '#demoSplit9'], {sizes: [25, 75], minSize: 100}); Split(['#demoSplit10', '#demoSplit11'], {direction: 'vertical'}); }); </script>

     

     

    6.6.1.快速使用

    <div id="demoProgress1"></div> <script> layui.use(['CircleProgress'], function () { var CircleProgress = layui.CircleProgress; // 快速使用 new CircleProgress('#demoProgress1', { max: 100, value: 20 }); }); </script>

    6.6.2.全部参数

    参数名称说明默认值max最大值 value当前值 clockwise是否顺时针方向truestartAngle起始角度0textFormat文字样式 

    文字样式:

    vertical   垂直percent   百分比value   只显示值valueOnCircle   值显示在进度条上none   不显示文字

    自定义文字样式:

    new CircleProgress('#demoProgress9', { max: 12, value: 9, textFormat: function (value, max) { return value + ' dots'; } });

     

    6.6.3.自定义样式

    使用css自定义样式:

    <div id="demoProgress1"></div> <script> layui.use(['CircleProgress'], function () { var CircleProgress = layui.CircleProgress; // 快速使用 new CircleProgress('#demoProgress1', { max: 100, value: 20, textFormat: 'percent' }); }); </script> <style> /* 进度条选中的样式 */ #demoProgress1 .circle-progress-value { stroke-width: 8px; /* 粗度 */ stroke: #3FDABA; /* 颜色 */ } /* 进度条未选中的样式 */ #demoProgress1 .circle-progress-circle { stroke-width: 6px; stroke: #E0FAF1; } </style>

     

     

    此插件是使用svg实现的,想要实现更丰富的样式,可先了解下svg

     

     

    6.7.1.快速使用

    默认样式:

    <div class="layui-tab layui-steps"> <ul class="layui-tab-title"> <li> <i class="layui-icon layui-icon-ok">1</i> <span class="layui-steps-title">已完成</span> <span class="layui-steps-content">这里是该步骤的描述信息</span> </li> <li class="layui-this"> <i class="layui-icon layui-icon-ok">2</i> <span class="layui-steps-title">进行中</span> <span class="layui-steps-content">这里是该步骤的描述信息</span> </li> <li> <i class="layui-icon layui-icon-ok">3</i> <span class="layui-steps-title">待进行</span> <span class="layui-steps-content">这里是该步骤的描述信息</span> </li> </ul> <div class="layui-tab-content"> <div class="layui-tab-item">内容1</div> <div class="layui-tab-item layui-show">内容2</div> <div class="layui-tab-item">内容3</div> </div> </div> <script> layui.use(['steps'], function () { var steps = layui.steps; }); </script>

    它的结构与layui的选项卡Tab一致,因为它就是在Tab的基础上增加的样式。

    6.7.2.风格选择

    迷你样式:

    <!-- 多加一个layui-steps-small即可 --> <div class="layui-tab layui-steps layui-steps-small"> <!-- 省略...... --> </div>

    自定义图标:

    <div class="layui-tab layui-steps layui-steps-small"> <ul class="layui-tab-title"> <li class="layui-this"> <!-- 这里的图标可以任意修改 --> <i class="layui-icon layui-icon-username"></i> <span class="layui-steps-title">账号注册</span> </li> <li> <i class="layui-icon layui-icon-camera"></i> <span class="layui-steps-title">上传头像</span> </li> </ul> <div class="layui-tab-content"> <div class="layui-tab-item layui-show">内容1</div> <div class="layui-tab-item">内容2</div> </div> </div>

    垂直风格:

    <!-- 多加一个layui-steps-vertical即可 --> <div class="layui-tab layui-steps layui-steps-vertical"> <!-- 省略...... --> </div>

    简洁风格:

    <!-- 多加一个layui-steps-simple --> <div class="layui-tab layui-steps layui-steps-simple"> <ul class="layui-tab-title"> <li>1.填写注册手机号</li> <li class="layui-this">2.获取短信验证码</li> <li>3.修改登录密码</li> </ul> <div class="layui-tab-content"> <div class="layui-tab-item">内容1</div> <div class="layui-tab-item layui-show">内容2</div> <div class="layui-tab-item">内容3</div> </div> </div>

    注意 简洁风格只有标题,没有图标、描述等

    6.7.3.上一步下一步

    <div class="layui-tab layui-steps" lay-filter="demoSteps"> <!-- 省略...... --> </div> <script> layui.use(['steps'], function () { var steps = layui.steps; steps.next('demoSteps'); // 下一步 steps.prev('demoSteps'); // 上一步 steps.go('demoSteps', 2); // 指定跳转,索引从0开始 }); </script>

    也可以使用属性绑定:

    <div class="layui-tab layui-steps"> <!-- 省略...... --> <a class="layui-btn" data-steps="prev">上一步</a> <a class="layui-btn" data-steps="next">下一步</a> <a class="layui-btn" data-steps="go" data-go="1">跳转第2步</a> </div>

     

    7.1.1.全部方法

    方法参数描述merges(tableId, indexs, fields)见单独说明合并单元格bindCtxMenu(tableId, items)见单独说明给表格行绑定鼠标右键exportData(object)见单独说明导出任意数据exportDataX(object)见单独说明导出任意数据(依赖社区excel模块)exportDataBack(object)见单独说明后端导出任意数据(支持post提交参数)   render(object)同layui表格渲染表格,带后端排序功能renderFront(object)同layui表格渲染表格,前端分页、排序、搜索 layui.use(['tableX'], function () { var tableX = layui.tableX; });

     

    7.1.2.合并单元格

    在table.render的done回调里面使用tableX.merges方法:

    table.render({ elem: '#xTable2', cols: [[ {type: 'numbers'}, {field: 'parentName', title: '模块名称', sort: true}, {field: 'authorityName', title: '菜单名称', sort: true} ]], done: function () { tableX.merges('xTable2', [1]); } });

    参数说明:

    tableX.merges('xTable2', [1]); // 合并第2列相同的单元格 tableX.merges('xTable2', [1], ['parentName']); // 合并第2列相同的单元格 tableX.merges('xTable2', [1, 2]); // 合并第2、3列相同的单元格 tableX.merges('xTable2', [1, 2], ['parentName', 'authorityName']); // 合并第2、3列相同的单元格 tableX.merges('xTable2', [1, 2], false); // 在后面加一个false可解决排序冲突的问题 参数一   必填    表格的lay-filter参数二   必填    要合并列的索引,数组类型参数三   非必填   根据数据字段判断是否相同,为空时根据单元格的html内容判断参数四   非必填   是否需要监听排序后重新合并,默认为true

     

    7.1.3.行绑定鼠标右键

    在table.render的done回调里面使用tableX.bindCtxMenu方法:

    table.render({ elem: '#xTable3', cols: [[ {field: 'nickName', title: '用户名'}, {field: 'sex', title: '性别'} ]], done: function () { tableX.bindCtxMenu('xTable3', [{ icon: 'layui-icon layui-icon-edit', name: '修改此用户', click: function (d, tr) { layer.msg('点击了修改,userId:' + d.userId); } }, { icon: 'layui-icon layui-icon-close text-danger', name: '<span class="text-danger">删除此用户</span>', subs: [{ icon: 'layui-icon layui-icon-camera', name: '逻辑删除', click: function (d) { layer.msg('点击了逻辑删除,userId:' + d.userId); } }, { icon: 'layui-icon layui-icon-picture-fine', name: '物理删除', click: function (d) { layer.msg('点击了物理删除,userId:' + d.userId); } }] }]); } }); 参数一   表格的id参数二   右键菜单 icon     图标name   标题click     点击事件,d是当前行的数据

    根据不同行动态显示不同菜单,只需要把参数二换成function并return菜单数组即可:

    tableX.bindCtxMenu('xTable3', function(d, tr) { if(d.userId === 1) { return [{ icon: 'layui-icon layui-icon-close text-danger', name: '<span class="text-danger">删除此用户</span>', click: function (d, tr) { layer.msg('点击了删除,userId:' + d.userId); } }]; } else { return [{ icon: 'layui-icon layui-icon-edit', name: '修改此用户', click: function (d, tr) { layer.msg('点击了修改,userId:' + d.userId); } }]; } });

     

    7.1.4.后端排序

    tableX.render({ elem: '#xTable3', url: '../../json/user.json', cols: [[ {type: 'numbers'}, {field: 'nickName', title: '用户名', sort: true}, {field: 'sex', title: '性别', sort: true} ]] });

    仅仅是把table.render换成tableX.render就会在点击排序时自动传递sort和order参数,例如:user?page=1&limit=10&sort=sex&order=asc。

    sort     排序字段,值是点击排序列的fieldorder   排序方式,升序是asc,降序是desc

    注意:如果写了sort: true开启排序,一定要写field: 'xxx'

     

    7.1.5.前端分页排序

    tableX.renderFront({ elem: '#xTable1', url: '../../json/userAll.json', page: true, cols: [[ {field: 'nickName', title: '用户名', sort: true}, {field: 'sex', title: '性别', sort: true} ]] });

    仅仅是把table.render换成tableX.renderFront就可以有前端分页和排序功能了,参数跟layui表格的参数一样,url方式你的接口可以返回全部数据,前端来分页,也支持data方式。

    前端模糊搜索:

    <input tb-search="xTable1" class="layui-input icon-search"/>

     在页面任意位置加入上面输入框,通过tb-search关联表格,就实现了对表格的模糊搜索功能。 还可以增加name属性来设置搜索时只搜索某些字段,多个字段通过逗号分隔:

    <input tb-search="xTable1" name="sex,phone" class="layui-input icon-search"/>

    刷新功能:

    <button tb-refresh="xTable1" class="layui-btn">刷新</button>

     在页面任意位置加入上面按钮,通过tb-refresh关联表格。 也可以通过js刷新:

    // url方式渲染的只能用此方法刷新 var insTb = tableX.renderFront({url: 'xxx'}); insTb.reloadUrl(); // data方式渲染的只能用此方法刷新 var insTb = tableX.renderFront({data: []}); insTb.reloadData({data: dataList, page: {curr: 1}});

    前端排序:

     前端排序如果有field字段,会根据field字段的值来排序,如果有templet会根据templet转换后的值排序, templet可能会返回表单元素,比如switch开关等,这些元素无法用来排序,可以通过export-show和export-hide来控制。

    <!-- switch开关列 --> <script type="text/html" id="tableState"> <input type="checkbox" lay-skin="switch" lay-text="正常|锁定" lay-filter="ckState" value="{{d.userId}}" {{d.state==0?'checked':''}}/> <div class="export-show">{{d.state==0?'正常':'锁定'}}</div> </script> <!-- icon图标列 --> <script type="text/html" id="tableState"> <div class="export-hide">{{d.state==0?'<i class="layui-icon layui-icon-ok"></i>':'<i class="layui-icon layui-icon-close"></i>'}}</div> <div class="export-show">{{d.state==0?'正常':'锁定'}}</div> </script> export-show   排序和导出时有效,表格展示时屏蔽export-hide   表格展示时有效,排序和导出时屏蔽

     

    7.1.6.导出数据

    tableX.exportData({ cols: insTb.config.cols, // 表头配置 data: table.cache.xTable3, // 数据,支持url方式 fileName: '用户表' // 文件名称 }); // exportDataX是新增的方法,参数与上面一摸一样 tableX.exportDataX({}); 参数必填说明默认cols是表头配置 data是导出的数据,支持数组和string的url fileName否导出的文件名称tableexpType否导出的文件类型xls(默认)、csv、xlsxoption否url方式的配置 

     如果data是string类型会把data当url请求数据,option是请求的配置,跟表格的配置一样,配置method、where、headers等, 接口返回的格式也要跟表格一样包含code、count、data等信息。

     cols的配置也跟表格一样,是一个多维数组,可以通过insTb3.config.cols来获取表格的cols,也可以重写。

     导出的数据会包含templet转换,如果templet返回的是switch开关、icon图标等,可以通过export-show和export-hide写两份, 一份用于表格的展示,一份用于表格的导出显示,具体用法参考前面前端排序章节的介绍。

    cols也可以重写:

    tableX.exportData({ cols: [[ {field: 'username', title: '账号'}, {field: 'nickName', title: '用户名'} ]], data: table.cache.xTable3, fileName: '用户表' });

    exportDataX方法使用的是社区excel模块导出的,是真正的xls格式,exportData以及layui自带的导出都是假的xls格式,如果数字前面有0会自动去掉0,exportDataX可解决此问题。

     

    7.1.7.导出全部、搜索

    后端分页时如何导出全部数据:

    tableX.exportDataX({ cols: insTb.config.cols, data: 'listAll.json', fileName: '用户表' }); // 后端再写一个查询全部的接口,data写接口地址

    导出搜索后的全部数据:

    var lastWhere; // 记录搜索的条件 // 表格搜索 form.on('submit(formSubSearchUser)', function (data) { lastWhere = data.field; insTb.reload({where: data.field}, 'data'); }); tableX.exportDataX({ cols: insTb.config.cols, data: 'listAll.json', option: { where: lastWhere }, fileName: '用户表' });

    在options里面加一个where把搜索条件传给后端。

     

    7.1.8.后端导出

    后端导出本质就是下载文件,一般用window.open(url)即可,如果要传递参数、post提交,那就麻烦了,tableX进行了完美的封装:

    tableX.exportDataBack('user/export', {sex: '男'}); tableX.exportDataBack('user/export', {sex: '男'}, 'post'); 参数一   后端的url参数二   传递的参数参数三   请求方式

    如果是get方式,会使用?和&拼接参数,如果是post方式,会创建一个隐藏的表单来提交, 如果你的参数有复杂的类型,比如json格式,建议用post的形式,此方法也可以用来做post方式下载文件的操作。

     

    7.2.1.验证规则

    规则描述提示信息phoneX手机号请输入正确的手机号emailX邮箱邮箱格式不正确urlX网址链接格式不正确numberX数字只能填写数字dateX日期日期格式不正确identityX身份证请输入正确的身份证号   psw密码密码必须5到12位,且不能出现空格equalTo重复两次输入不一致digits整数只能输入整数digitsP正整数只能输入正整数digitsN负整数只能输入负整数digitsPZ非负整数只能输入正整数和0digitsNZ非正整数只能输入负整数和0   h5兼容h5的规则 

    使用示例:

    <form class="layui-form"> <input class="layui-input" placeholder="请输入手机号" lay-verType="tips" lay-verify="phoneX"/> <input class="layui-input" placeholder="请输入手机号" lay-verType="tips" lay-verify="required|phoneX"/> <input class="layui-input" placeholder="请输入整数" lay-verType="tips" lay-verify="digits"/> <input class="layui-input" placeholder="请输入正整数" lay-verType="tips" lay-verify="digitsP"/> </form> <script> layui.use(['formX'],function(){ var formX = layui.formX; // 要引入formX模块才会生效 }); </script>

    equalTo用法,可以用来验证两次输入是否一致:

    <form class="layui-form"> <input id="demoPsw" class="layui-input" placeholder="请输入密码" lay-verType="tips" lay-verify="required|psw"/> <input class="layui-input" placeholder="请再次输入密码" lay-verType="tips" lay-verify="equalTo" lay-equalTo="#demoPsw" lay-equalToText="两次输入密码不一致"/> </form> 属性描述lay-equalTo关联输入框的dom选择器lay-equalToText自定义提示文本

    h5用法:

    属性描述minlength最少输入字符长度maxlength最多输入字符长度min最小输入数值max最大输入数值 <form class="layui-form"> <input class="layui-input" placeholder="最少输入5个字符" minlength="5" lay-verType="tips" lay-verify="required|h5"/> <input class="layui-input" placeholder="最多输入10个字符" maxlength="10" lay-verType="tips" lay-verify="h5"/> <input class="layui-input" type="number" placeholder="值只能在-9到9之间" min="-9" max="9" lay-verType="tips" lay-verify="required|numberX|h5"/> </form>

    phoneX、emailX等与layui自带phone、email等的区别是如果没有输入不会验证,输入了才验证格式。

     

    7.2.2.扩展方法

    方法描述val(filter, object)赋值表单,解决top.layui.form.val()无效bugrenderSelect(option)渲染select封装startTimer(elem, time, format)按钮验证码倒计时封装formUpdatedField(field, oldField)获取表单修改过的数据

    使用方法:

    layui.use(['formX'],function(){ var formX = layui.formX; // 赋值表单,支持top.formX.val()用法 formX.val('userForm', {name: 'user01'}); });

     

    7.2.3.渲染select封装

    <select id="sel"></select> <script> layui.use(['formX'],function(){ var formX = layui.formX; // 数据方式 formX.renderSelect({ elem: '#sel', data: [ {id: 1, name: '张三'}, {id: 2, name: '李四'} ], name: 'name', value: 'id', hint: '请选择用户', initValue: 1, done: function() {} }); // 异步方式 formX.renderSelect({ elem: '#sel', data: 'user.json', name: 'name', value: 'id', hint: '请选择用户', done: function(data) {}, method: 'get', where: {page: 20}, header: {token: 'xxx'}, async: true, error: function(xhr, res){} }); }); </script>

    基础参数:

    elem      要渲染的selectdata       数据源,可以是数组,也可以是urlname     显示的字段名称value     值的字段名称hint     未选择提示文字initValue   默认回显的数据done      渲染完成后的回调error      data为url时请求失败的回调method    data为url时请求方式where      data为url时请求参数header     data为url时请求headerasync    data为url时请求时否是异步

     后端返回数据格式为{"data": [], "code": 0},data有数据就是请求成功,没有数据就进入error,code等于多少都可以, 如果数据不是对象的形式,name和value可不填:

    formX.renderSelect({ elem: '#sel', data: ['张三','李四'] });

     

    7.2.4.验证码倒计时

    <button id="btnSend" class="layui-btn">发送验证码</button> <script> layui.use(['formX'],function(){ var formX = layui.formX; // 按钮倒计时30s formX.startTimer('#btnSend', 30); // 自定义倒计时文字,默认是30s,29s,28s... formX.startTimer('#btnSend', 30, function(time){ return time + 's 后可继续发送'; }); }); </script>

     

    7.2.5.获取修改字段

    var user = {sex: 'male', age: 18}; form.val('userForm', user); // 表单回显数据 // 获取表单修改后的字段 var field = formX.formUpdatedField(form.val('userForm'), user); console.log(field);

    利用这个方法可以做判断用户是否修改了表单:

    var user = {sex: 'male', age: 18}; form.val('userForm', user); // 表单回显数据 // 监听表单提交 form.on('submit(submit-user)', function (data) { var u = formX.formUpdatedField(data.field, user); if(!u) { alert('你没有做任何修改'); } return false; });

     

     

    printer.print(); printer.print({ hide: ['.layui-btn', '#btn01'], // 打印时隐藏的元素 horizontal: true, // 是否横向打印 blank: true, // 是否打开新页面打印 close: true, // 如果是打开新页面,打印完是否关闭 iePreview: true // 是否兼容ie打印预览 });

    参数都是可以选参数,默认值已经符合大多数需求。

     

    7.3.2.设置不打印元素

    <div class="hide-print">非打印内容</div>

    加hide-print这个class即可,可以跟hide参数叠加使用。

     

    var pWindow = printer.printHtml({ html: '<span>xxxx</span>', // 要打印的内容 horizontal: true, // 是否横向打印 blank: true, // 是否打开新页面打印 close: true, // 如果是打开新页面,打印完是否关闭 iePreview: true, // 是否兼容ie打印预览 print: true // 如果是打开新窗口是否自动打印 });

    打印表格时可以给table加print-table这个class来设置表格的边框样式:<table class="print-table">。

    如果print为false关闭自动打印,可以使用pWindow.print()触发打印。

     

    printer.printPage({ htmls: [ '<span>xxxx</span>', // 要打印的内容 '<span>xxxx</span>' ], style: '<style>span{color:red;}</style>',// 页面样式 horizontal: true, // 是否横向打印 blank: true, // 是否打开新页面打印 close: true, // 如果是打开新页面,打印完是否关闭 iePreview: true, // 是否兼容ie打印预览 print: true, // 如果是打开新窗口是否自动打印 padding: undefined, // 页面间距 debug: false, // 调试模式 height: undefined, // 页面高度 width: undefined // 页面宽度 });

    参数都是可选参数:

    htmls     数组,代表每一页;style      样式,也可以写<link rel="stylesheet">的形式;padding   页面间距,例如写'10px';debug      调试模式,每一页会加红色边框,便于调试大小;

     

    7.3.5.拼接html

    var htmlStr = printer.makeHtml({ title: '网页标题', style: '<link rel="stylesheet" href="layui.css"><script type="text/javascript" src="layui.js"><\/script>', body: $('#xxx').html() });

     

     

    7.4.1.快速使用

    layui.use(['contextMenu'], function () { var contextMenu = layui.contextMenu; // 重写整个页面右键菜单 contextMenu.bind('html', [{ icon: 'layui-icon layui-icon-snowflake', name: '菜单一', click: function (e, event) { // 通过$(event.currentTarget)可获取事件触发的元素 alert('点击了菜单一'); } }, { name: '菜单二', click: function (e) { alert('点击了菜单二'); } }]); }); 参数一   绑定元素参数二   菜单数组

    菜单数组可支持无限极:

    [{ icon: 'xxxxx', name: '菜单三', subs: [{ icon: 'xxxxx', name: '子菜单一', click: function (e, event) { alert('点击了子菜单一'); } }] }] icon     图标name   菜单名click     点击事件subs     子菜单(支持无限极)

    click事件里面的e是右键菜单的事件对象,event才是绑定的目标元素的事件对象

     

    7.4.2.自定义使用

    例如用于点击事件:

    $('#btn').click(function (e) { var x = $(this).offset().left; var y = $(this).offset().top + $(this).outerHeight() - $('html,body').scrollTop(); contextMenu.show([{ name: '按钮菜单一', click: function () { } }], x, y, e); e.preventDefault(); e.stopPropagation(); });

    你可以自己绑定事件,通过show方法显示出来,参数说明:

    参数一   菜单数组参数二   x坐标参数三   y坐标参数四   e 原始事件对象

     

    7.4.3.动态元素绑定

    对于动态生成的元素可以使用事件委托的方式来绑定:

    // 对.btn元素绑定鼠标右键 $ (document). bind('contextmenu', '.btn', function (e) { contextMenu.show([{ icon: 'layui-icon layui-icon-set', name: '删除', click: function (e, event) { layer.msg('点击了刪除'); } }],e. clientX, e. clientY, e); return false; });

     

    7.5.1.快速使用

    后台管理页面大多用数据表格展示,如果要使用网格、瀑布流、卡片列表等形式,分页、自动渲染、搜索、排序等功能都需要自己实现, 极其麻烦,dataGrid模块就是对非表格形式的列表页面实现类似数据表格的功能,也在使用方法上与数据表格大致相同。

    <div id="demoGrid"></div><!-- 容器 --> <!-- 模板 --> <script type="text/html" id="demoGridItem"> <div> <h2>{{d.title}}</h2> <p>{{d.content}}</p> <a lay-event="add">添加</a> <a lay-event="edit">修改</a> </div> </script> <script> layui.use(['dataGrid'], function () { var dataGrid = layui.dataGrid; /* 渲染 */ var ins = dataGrid.render({ elem: '#demoGrid', // 容器 templet: '#demoGridItem', // 模板 url: 'json/list.json', // 数据接口 page: {limit: 5} // 开启分页 }); /* item点击事件 */ dataGrid.on('item(demoGrid)', function (obj) { obj.data; // 当前操作的数据对象 obj.elem; // 当前操作的dom元素 obj.del(); // 删除当前item obj.update({title: 'new title'}); // 修改当前item layer.msg('点击了第' + (obj.index + 1) + '个'); }); /* item里面的lay-event的点击事件 */ dataGrid.on('tool(demoGrid)', function (obj) { var data = obj.data; if (obj.event === 'add') { layer.msg('点击了添加'); } else if (obj.event === 'edit') { layer.msg('点击了编辑'); } }); /* item双击事件 */ dataGrid.on('itemDouble(demoGrid)', function (obj) { }); /* 监听复选框选择 */ dataGrid.on('checkbox(demoGrid)', function (obj) { console.log(obj.checked); // 当前是否选中状态 console.log(obj.data); // 选中行的相关数据 console.log(obj.type); // 如果触发的是全选,则为all }); }); </script>

     

    7.5.2.全部参数

    参数类型说明示例elemString/DOM指定容器的选择器或DOM"#demo"templetStringitem模板,模板遵循 laytpl 语法 dataArray直接赋值数据,也可前端分页[{},{},{}]urlString接口地址 methodString接口http请求类型,默认:get whereObject接口的请求参数where: {id: 123}headersObject接口的请求头headers: {token: 'sasasas'}contentTypeString发送到服务端的内容编码类型contentType: 'application/json'parseDataFunction数据格式解析的回调函数 requestFunction用于对分页请求的参数重新设定名称默认是page、limituseAdminBoolean是否使用admin.ajax默认falsedoneFunction数据渲染完的回调 pageObject开启分页,配置分页参数 loadMoreObject开启加载更多,配置加载更多参数 

    parseData和request参数说明:

    var ins = dataGrid.render({ elem: '#demoGrid', templet: '#demoGridItem', url: 'json/list.json', parseData: function(res) { return { code: res.status, msg: res.message, count: res.total, data: res.list } }, request: {pageName: 'page', limitName: 'limit'} });

    渲染完成的回调done说明:

    dataGrid.render({ done: function(dataList, curr, count) { dataList; // 当前页数据 curr; // 当前第几页 count; // 总数量 } });

     

    7.5.3.分页功能

    使用page参数开启分页,page参数同layui分页组件的参数一致前往查看。

    dataGrid.render({ elem: '#demoGrid', // 容器 templet: '#demoGridItem', // 模板 url: 'json/list.json', // 数据接口 page: {limit: 5} // 开启分页 });

     

    7.5.4.加载更多功能

    dataGrid.render({ elem: '#demoGrid', // 容器 templet: '#demoGridItem', // 模板 url: 'json/list.json', // 数据接口 loadMore: {limit: 5} // 开启加载更多 });

    loadMore和page只能二选一,loadMore的可选参数:

    参数说明默认值class自定义class''limit每页多少条10text显示文字'加载更多'loadingText加载中文字'加载中...'noMoreText无数据文字'没有更多数据了~'errorText加载失败文字'加载失败,请重试'

     

    7.5.5.实例方法

    var ins = dataGrid.render({}); ins.reload(); // 重载 ins.reload({page: {curr: 2} }); // 跳到第二页 ins.update(index, fields, type); // 修改数据 // index是索引,fields是要修改的字段 // type 0整个item更新, 1只更新item子元素, 2只更新数据不更新item ins.del(index); // 删除item ins.getData(); // 获取当前数据 ins.checkStatus(); // 获取选中行数据

     

    7.5.6.自动渲染

    <div id="demoGrid" lay-data="{url: 'json/list.json', page: {limit: 5} }" data-grid> <script type="text/html" data-grid-tpl> <div> <h2>{{d.title}}</h2> <p>{{d.content}}</p> <a lay-event="edit">修改</a> </div> </script> </div>

    通过添加data-grid和data-grid-tpl属性,dataGrid组件便会自动渲染,通过lay-data属性进行参数配置。

     

    7.6.1.快速使用

    layui.use(['fileChoose'], function () { var fileChoose = layui.fileChoose; fileChoose.open({ fileUrl: '', // 文件查看的url listUrl: '../template/file/files.json', // 文件列表的url where: { access_token: 'xxxxxx' }, num: 3, // 最多选择数量 dialog: { offset: '60px' }, onChoose: function (urls) { layer.msg('你选择了:' + JSON.stringify(urls), {icon: 1}); } }); });

     

    7.6.2.全部参数

    参数描述默认值fileUrl文件查看的url listUrl文件列表的url where文件列表请求参数{}num文件选择的数量1onChoose选择后回调 upload文件上传配置(同layui配置){}dialog弹窗配置(同layui配置){}menu点击弹出的菜单数组类型menuClick菜单点击事件处理 response接口数据格式化 

    菜单配置及点击事件:

    fileChoose.open({ menu: [{ name: '预览', event: 'preview' }, { name: '复制', event: 'copy' }, { name: '<span style="color: red;">删除</span>', event: 'del' }], menuClick: function(event, item) { // event 事件名称 // item 当前数据 } });

    name菜单项名称,event点击事件名称

    接口数据格式化:

    fileChoose.open({ response: { method: 'get', // 请求方式 code: 0, // 成功码,默认200 name: 'name', // 文件名称字段名称 url: 'url', // 文件url字段名称 smUrl: 'smUrl', // 文件缩略图字段名称 isDir: 'isDir', // 是否是文件夹字段名称,boolean类型 dir: 'dir' // 当前文件夹参数名称 } });

    接口数据返回的格式需要为:

    { "code": 200, "msg": "请求成功", "data": [ { "name": "图片一", "url": "2019/07/11/001.png", "smUrl": "sm/2019/07/11/001.png", "isDir": false } ] }

    code、msg、data是必须按这个名字的,name、url、smUrl、isDir这几个字段的名称可以通过response参数配置,也可以加其他字段, 比如id、create_time等,这些字段会在菜单点击事件和选择回调事件中返回。

    如果你的接口返回的数据不是code、msg,是其他的,比如status、message,可以使用parseData参数格式化:

    fileChoose.open({ response: { parseData: function(res){ return { code: res.status, msg: res.message, data: res.list } } } });

    如果是文件夹,点击文件夹会重新请求接口,并且传递文件夹的名称,传递的字段名称可以通过response.dir修改。

    上传文件上传成功后默认会进入到当前日期生成的dir下面,你可以后端上传成功的接口返回dir指定上传成功后要进入的dir, 也可以把上传前端传递的dir原封不动的返回:

    {"code": 200,"msg": "上传成功", "dir": "/2020/0516"}

    不同文件显示不同的图标是前端根据文件url的后缀名称来判断的,在之前版本是服务器根据文件的content-type判断的。

     

     

     

    8.1.鼠标滚轮监听

    此插件来源于 jquery-mousewheel,使用方式:

    layui.use(['mousewheel'], function () { var $ = layui.jquery; // 滚动监听 $('#xxx').on('mousewheel', function (event) { console.log(event.deltaX, event.deltaY, event.deltaFactor); event.stopPropagation(); // 阻止事件冒泡 event.preventDefault(); // 阻止默认事件 }); });

    event对象中可以获取如下三个属性值:

    deltaX:值为负的(-1)表示滚轮向左滚动,值为正的(1)表示滚轮向右滚动。deltaY:值为负的(-1)表示滚轮向下滚动。值为正的(1)表示滚轮向上滚动。deltaFactor:增量因子,通过deltaFactor*deltaX或者deltaFactor*deltaY可以得到浏览器实际的滚动距离。

     

    8.2.二维码模块

    此插件来源于 qrcodejs,使用方式:

    <div id="xxx"></div> <script> layui.use(['QRCode'], function () { var $ = layui.jquery; var QRCode = layui.QRCode; // 二维码 var demoQrCode = new QRCode(document.getElementById("xxx"), { text: "Hello Word!", width: 101, // 宽度 height: 101, // 高度 colorDark: "#000000", // 颜色 colorLight: "#ffffff", // 背景颜色 correctLevel: QRCode.CorrectLevel.H }); // 更换内容 demoQrCode.makeCode("Easyweb"); }); </script>

     

    8.3.引导插件

    此插件来源于 intro.js,并对样式进行了微调,使用方式:

    <div data-step="1" data-intro="这是步骤一">步骤一</div> <div data-step="2" data-intro="这是步骤二">步骤二</div> <script> layui.use(['introJs'], function () { var introJs = layui.introJs; // 初始化 introJs().start(); }); </script>

     

    8.4.剪贴板

    此插件来源于 clipboard.js,使用方式:

    <input id="foo" value="https://github.com/zenorocha/clipboard.js.git"> <button id="btnCopy" data-clipboard-target="#foo">复制</button> <script> layui.use(['ClipboardJS'], function () { var ClipboardJS = layui.ClipboardJS; var clipboard = new ClipboardJS('#btnCopy'); clipboard.on('success', function(e) { e.clearSelection(); }); clipboard.on('error', function(e) { console.error('Action:', e.action); }); }); </script>

    按钮通过data-clipboard-target绑定的不一定是input,div也可以,也不一定用id,jquery选择器都可以。

     

    8.5.视频播放器

    视频播放器使用的是西瓜视频开源的xgplayer,使用方式:

    <div id="demoVideo"></div> <script> layui.use(['Player'], function () { var Player = layui.Player; // 视频播放器 var player = new Player({ id: "demoVideo", url: "//s1.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/xgplayer-demo.mp4", // 视频地址 poster: "https://imgcache.qq.com/open_proj/proj_qcloud_v2/gateway/solution/general-video/css/img/scene/1.png", // 封面 fluid: true, // 宽度100% playbackRate: [0.5, 1, 1.5, 2], // 开启倍速播放 pip: true, // 开启画中画 lang: 'zh-cn' }); // 开启弹幕 var dmStyle = { color: '#ffcd08', fontSize: '20px' }; var player = new Player({ id: "demoVideo2", url: "http://demo.htmleaf.com/1704/201704071459/video/2.mp4", // 视频地址 autoplay: false, fluid: true, // 宽度100% lang: 'zh-cn', danmu: { comments: [ {id: '1', start: 0, txt: '空降', color: true, style: dmStyle, duration: 15000}, {id: '2', start: 1500, txt: '前方高能', color: true, style: dmStyle, duration: 15000}, {id: '3', start: 3500, txt: '弹幕护体', color: true, style: dmStyle, duration: 15000}, ] } }); }); </script>

     

    8.6.富文本编辑器

    富文本编辑器使用的是TinyMCE,查看中文文档。

    <textarea id="demoEditor"></textarea> <script type="text/javascript" src="assets/libs/tinymce/tinymce.min.js"></script> <script> layui.use(['layer'], function () { var $ = layui.jquery; var layer = layui.layer; // 渲染富文本编辑器 tinymce.init({ selector: '#demoEditor', height: 525, branding: false, language: 'zh_CN', plugins: 'code print preview fullscreen paste searchreplace save autosave link autolink image imagetools media table codesample lists advlist hr charmap emoticons anchor directionality pagebreak quickbars nonbreaking visualblocks visualchars wordcount', toolbar: 'fullscreen preview code | undo redo | forecolor backcolor | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | outdent indent | numlist bullist | formatselect fontselect fontsizeselect | link image media emoticons charmap anchor pagebreak codesample | ltr rtl', toolbar_drawer: 'sliding', images_upload_url: '../../../json/tinymce-upload-ok.json', file_picker_types: 'media', file_picker_callback: function (callback, value, meta) { layer.msg('演示环境不允许上传', {anim: 6}); }, init_instance_callback: function (editor) { console.log(editor); // 编辑器渲染完成回调,回显值应该在这里回显 // tinymce.get('demoEditor').setContent('<span>Hello</span>'); } }); // 获取内容 var content = tinymce.get('demoEditor').getContent(); // 获取纯文本 var content = tinymce.get('demoEditor').getContent({format: 'text'}); // 设置内容 tinymce.get('demoEditor').setContent('<span>Hello</span>'); // 插入内容 tinymce.get('demoEditor').insertContent('👍赞~', {}); }); </script>

    弹窗中使用应该在弹窗关闭后销毁编辑器实例:

    admin.open({ type: 1, content: '<textarea id="demoEditor2"></textarea>', success: function () { // 渲染编辑器 tinymce.init({ selector: '#demoEditor2' }); }, end: function () { // 销毁编辑器 tinymce.get('demoEditor2').destroy(false); } });

    解决弹窗遮挡富文本组件:

    <!-- 页面加入样式 --> <style> body .tox-tinymce-aux { z-index: 19892000 !important; } </style>

    单页面中使用应该在页面卸载后销毁编辑器实例:

    // 渲染编辑器 tinymce.init({ selector: '#demoEditor' }); // 监听页面卸载并销毁编辑器 admin.on('destroy(plugin/other/editor)', function () { tinymce.get('demoEditor').destroy(false); });

    如果你多个页面都用到了TinyMCE,建议js的引用放在index.html中:

    <script type="text/javascript" src="assets/libs/tinymce/tinymce.min.js"></script>

     

     

    9.1.主题功能

    默认的样式以及内置的几套主题都在admin.css中,如果要自定义主题步骤如下:

    前往 主题生成器 在线定制主题;将生成的css放在admin.css里面,也可以像admin.css一样引入,可以直接通过<style>写在页面中,也可以建一个theme-all.css引入, 将所有生成的主题都放在这个css文件里面;打开“page/tpl/tpl-theme.html”添加生成的主题: <div class="more-theme-list"> <!-- data-theme写主题的名称 --> <div class="more-theme-item" data-theme="theme-cyan"> <img src="assets/module/img/theme-cyan.png"/> </div> </div>

    主题的预览图在主题生成器中会生成,右键可保存为图片,theme-all.css最好在admin.css之后引入。

    设置默认主题也会闪一下才会切换怎么办:

    因为主题切换是通过js切换的,js都是在css、html加在完毕之后执行的,有一点点延迟也很正常,而且换主题是换class, 大部分组件都写有transition的0.3s的css过渡效果,解决办法只能是直接在index.html的body上面加上主题对应的class:

    <body class="theme-red" data-theme="theme-red"></body>

    或者直接修改下主题的css,把前面的.theme-xxx改成body,这种方法只适合固定一套主题不需要切换的情况。

     

    9.2.自定义扩展模块

    集成社区模块:

    把下载好的模块放在/assets/module/下面,如果模块是一个js,不用做任何配置就可以使用了, 例如admin.js、index.js,如果模块是一个文件夹,还需要在main.js中配置模块的具体位置,如notice/notice。

    自定义扩展模块:

    如果需要自己写一个扩展模块,请前往阅读Layui定义模块的开发文档, 或者参考admin.js、index.js等模块。

    集成jquery插件:

    jquery作为老牌框架,有着丰富的第三方插件,把插件放入libs下,页面中先引入jquery,再引入插件,即可使用。 当然更友好的集成方式是把它改造成layui扩展模块,改造方式请参考layui 封装第三方组件。

     

    9.3.spa全部用iframe

    SPA单页面的缺点已经很明显了,就是ID不能重复(即使是多个页面),这个缺点只能通过规范ID命名来解决,或者关闭多标签模式, 或者标签全部用iframe。

    在3.1.6版本后menu.json新支持了iframe字段:

    { "name": "用户管理", "url": "#/system/user", "iframe": "http://baidu.com" }

    当浏览器访问#/system/user时,框架默认是通过ajax加载components/system/user.html的内容拼接到index.html中, 如果有iframe字段就是把<iframe src="http://baidu.com">拼接到index.html中,所以如果把菜单这样配置,就相当于iframe版的形式:

    { "name": "用户管理", "url": "#/system/user", "iframe": "components/system/user.html" }

    这样配置后user.html就不再是一个代码片段了,要完整的包含layui.css、admin.css、layui.js,而且还要参照main.js配置:

    layui.config({ base: getProjectUrl() + 'assets/module/' }).extend({ /// ......省略 }).use(['layer', 'admin'], function () { var $ = layui.jquery; var layer = layui.layer; var admin = layui.admin; });

    你可以把这段js写一个common.js作为公共引用,你可以直接让后端返回这样的menu数据格式,也可以在注册路由的时候格式化数据, index模块有介绍,getProjectUrl()这个方法可以让不同路径的子界面都可以正确配置模块位置,这个方法的实现在前面main.js章节中有介绍。

     

     

    10.弹窗专题

    Layui没有像Bootstrap那样的直接写在页面中的模态弹窗,而是通过layer模块调用js弹出,对于用习惯了bootstrap了的可能不太适应, 下面介绍几种实现表单弹窗不同方式。

    10.1.第一种 页面层弹窗

    页面层弹窗就是弹窗页面和列表页面在一个html中,弹窗类型type=1:

    <button id="btnAddUser" class="layui-btn">添加</button> <table id="tableUser" lay-filter="tableUser"></table> <!-- 表单弹窗,注意这里要用script包起来 --> <script type="text/html" id="modelUser"> <form id="modelUserForm" lay-filter="modelUserForm" class="layui-form model-form"> <input name="userId" type="hidden"/> <div class="layui-form-item"> <label class="layui-form-label">用户名</label> <div class="layui-input-block"> <input name="nickName" class="layui-input" placeholder="请输入角色名" lay-verType="tips" lay-verify="required" required/> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">性别</label> <div class="layui-input-block"> <input type="radio" name="sex" value="男" title="男" checked/> <input type="radio" name="sex" value="女" title="女"/> </div> </div> <div class="layui-form-item text-right"> <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">取消</button> <button class="layui-btn" lay-filter="modelSubmitUser" lay-submit>保存</button> </div> </form> </script> <!-- 表格操作列 --> <script type="text/html" id="tableBarUser"> <a class="layui-btn" lay-event="edit">修改</a> <a class="layui-btn" lay-event="del">删除</a> </script> <!-- js部分 --> <script> layui.use(['layer', 'form', 'table', 'admin'], function () { var $ = layui.jquery, layer = layui.layer, form = layui.form, table = layui.table, admin = layui.admin; // 渲染表格 var insTb = table.render({ elem: '#tableUser', url: '../../json/user.json', cols: [[ {field: 'nickName', title: '用户名'}, {field: 'sex', title: '性别'}, {toolbar: '#tableBarUser', title: '操作'} ]] }); // 添加 $('#btnAddUser').click(function () { showEditModel(); }); // 工具条点击事件 table.on('tool(tableUser)', function (obj) { var data = obj.data; var layEvent = obj.event; if (layEvent === 'edit') { // 修改 showEditModel(data); } else if (layEvent === 'del') { // 删除 layer.msg('点击了删除', {icon: 2}); } }); // 显示表单弹窗 function showEditModel(mUser) { admin.open({ type: 1, title: (mUser ? '修改' : '添加') + '用户', content: $('#modelUser').html(), // 注意这里有.html() success: function (layero, dIndex) { var url = mUser ? '/updateUser' : '/addUser'; form.val('modelUserForm', mUser); // 回显数据 // 表单提交事件 form.on('submit(modelSubmitUser)', function (data) { layer.load(2); $.post(url, data.field, function (res) { layer.closeAll('loading'); if (res.code == 200) { layer.close(dIndex); layer.msg(res.msg, {icon: 1}); insTb.reload(); // 保存成功刷新表格 } else { layer.msg(res.msg, {icon: 2}); } }, 'json'); return false; }); } }); } }); </script>

    通过content: $("#modelUser").html()是指定弹窗内容,表单使用<script type="text/html">而不是使用div, 这样表单就不会默认显示出来,操作表单的代码都要写在success里面,因为弹窗是把表单的html复制一份动态插入到页面上, 这种方式修改回显数据、修改完刷新表格都比较方便。

    切记: 这种写法的弹窗所有操作弹窗内元素的代码都要放在弹窗的success里面。

     

    10.2.第二种 iframe弹窗

    iframe弹窗是弹窗内容页面和表格页面是两个页面,减少每个页面的代码量,弹窗类型type=2。

    表格页面,list.html:

    <button id="btnAddUser" class="layui-btn">添加</button> <table id="tableUser" lay-filter="tableUser"></table> <!-- 表格操作列 --> <script type="text/html" id="tableBarUser"> <a class="layui-btn" lay-event="edit">修改</a> <a class="layui-btn" lay-event="del">删除</a> </script> <!-- js部分 --> <script> layui.use(['layer', 'table', 'admin'], function () { var $ = layui.jquery, layer = layui.layer, table = layui.table, admin = layui.admin; // 渲染表格 var insTb = table.render({ elem: '#tableUser', url: '../../json/user.json', cols: [[ {field: 'nickName', title: '用户名'}, {field: 'sex', title: '性别'}, {toolbar: '#tableBarUser', title: '操作'} ]] }); // 添加 $('#btnAddUser').click(function () { showEditModel(); }); // 工具条点击事件 table.on('tool(tableUser)', function (obj) { var data = obj.data; var layEvent = obj.event; if (layEvent === 'edit') { // 修改 showEditModel(data); } else if (layEvent === 'del') { // 删除 layer.msg('点击了删除', {icon: 2}); } }); // 显示表单弹窗 function showEditModel(mUser) { var layIndex = admin.open({ type: 2, title: (mUser ? '修改' : '添加') + '用户', content: 'userForm.html', data: { user: mUser }, // 使用data参数传值给弹窗页面 end: function () { // 监听弹窗关闭 if (admin.getLayerData(layIndex, 'formOk')) { // 判断表单操作成功标识 insTb.reload(); // 成功刷新表格 } } }); } }); </script>

    弹窗页面,userForm.html:

    <html> <head> <link rel="stylesheet" href="assets/libs/layui/css/layui.css"/> <link rel="stylesheet" href="assets/module/admin.css"/> </head> <body> <form id="modelUserForm" lay-filter="modelUserForm" class="layui-form model-form"> <input name="userId" type="hidden"/> <div class="layui-form-item"> <label class="layui-form-label">用户名</label> <div class="layui-input-block"> <input name="nickName" class="layui-input" placeholder="请输入角色名" lay-verType="tips" lay-verify="required" required/> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">性别</label> <div class="layui-input-block"> <input type="radio" name="sex" value="男" title="男" checked/> <input type="radio" name="sex" value="女" title="女"/> </div> </div> <div class="layui-form-item text-right"> <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">取消</button> <button class="layui-btn" lay-filter="modelSubmitUser" lay-submit>保存</button> </div> </form> <!-- js部分 --> <script type="text/javascript" src="assets/libs/layui/layui.js"></script> <script type="text/javascript" src="assets/js/common.js"></script> <script> layui.use(['layer', 'form', 'admin', 'formX'], function () { var $ = layui.jquery, layer = layui.layer, form = layui.form, admin = layui.admin, formX = layui.formX; var mUser = admin.getLayerData().user; // 获取列表页面传递的数据 // 回显数据,这里一定要用formX.val,form.val不能回显跨iframe的数据 formX.val('modelUserForm', mUser); // 表单提交事件 form.on('submit(modelSubmitUser)', function (data) { layer.load(2); var url = mUser ? '/updateUser' : '/addUser'; $.post(url, data.field, function (res) { layer.closeAll('loading'); if (res.code == 200) { layer.msg(res.msg, {icon: 1}); admin.putLayerData('formOk', true); // 设置操作成功的标识 admin.closeThisDialog(); // 关闭当前iframe弹窗 } else { layer.msg(res.msg, {icon: 2}); } }, 'json'); return false; }); }); </script> </body> </html>

    content参数写表单的页面url,在end回调里面判断操作成功的标识然后刷新表格,end是弹窗关闭的回调, 参数传递的详细介绍请看下面章节的详细介绍。

    iframe弹窗的优点是页面独立,减少代码量,降低耦合,缺点是如果页面有下拉框、日期选择等,它们的范围不能超出弹窗的范围, 会导致弹窗出现滚动条,甚至不显示出来,下面章节介绍的url方式弹窗解决了这些缺点。

     

    10.3.第三种 url方式弹窗

    url方式弹窗就是使用url参数将弹窗页面独立出来,url参数admin.open特有的。

    弹窗页面,userForm.html:

    <!-- 注意这里不需要写`<html><body>`这些东西,它是一个html片段,不是完整的html页面 --> <form id="modelUserForm" lay-filter="modelUserForm" class="layui-form model-form"> <input name="userId" type="hidden"/> <div class="layui-form-item"> <label class="layui-form-label">用户名</label> <div class="layui-input-block"> <input name="nickName" class="layui-input" placeholder="请输入用户名" lay-verType="tips" lay-verify="required" required/> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">性别</label> <div class="layui-input-block"> <input type="radio" name="sex" value="男" title="男" checked/> <input type="radio" name="sex" value="女" title="女"/> </div> </div> <div class="layui-form-item text-right"> <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">取消</button> <button class="layui-btn" lay-filter="modelSubmitUser" lay-submit>保存</button> </div> </form> <script> layui.use(['layer', 'form', 'admin'], function () { var $ = layui.jquery, layer = layui.layer, form = layui.form, admin = layui.admin; var mUser = admin.getLayerData('#modelUserForm').user; // 列表页面传递的数据,#modelUserForm这个只要写弹窗内任意一个元素的id即可 form.val('modelUserForm', mUser); // 回显数据 // 表单提交事件 form.on('submit(modelSubmitUser)', function (data) { layer.load(2); var url = mUser ? '/updateUser' : '/addUser'; $.post(url, data.field, function (res) { layer.closeAll('loading'); if (res.code == 200) { layer.msg(res.msg, {icon: 1}); admin.putLayerData('formOk', true, '#modelUserForm'); // 设置操作成功的标识,#modelUserForm这个只要写弹窗内任意一个元素的id即可 admin.closeDialog('#modelUserForm'); // 关闭页面层弹窗 } else { layer.msg(res.msg, {icon: 2}); } }, 'json'); return false; }); }); </script>

    表格页面,list.html:

    <button id="btnAddUser" class="layui-btn">添加</button> <table id="tableUser" lay-filter="tableUser"></table> <!-- 表格操作列 --> <script type="text/html" id="tableBarUser"> <a class="layui-btn" lay-event="edit">修改</a> <a class="layui-btn" lay-event="del">删除</a> </script> <!-- js部分 --> <script> layui.use(['layer', table', 'admin'], function () { var $ = layui.jquery, layer = layui.layer, table = layui.table, admin = layui.admin; // 渲染表格 var insTb = table.render({ elem: '#tableUser', url: '../../json/user.json', cols: [[ {field: 'nickName', title: '用户名'}, {field: 'sex', title: '性别'}, {toolbar: '#tableBarUser', title: '操作'} ]] }); // 添加 $('#btnAddUser').click(function () { showEditModel(); }); // 工具条点击事件 table.on('tool(tableUser)', function (obj) { var data = obj.data; var layEvent = obj.event; if (layEvent === 'edit') { // 修改 showEditModel(data); } else if (layEvent === 'del') { // 删除 layer.msg('点击了删除', {icon: 2}); } }); // 显示表单弹窗 function showEditModel(mUser) { var layIndex = admin.open({ title: (mUser ? '修改' : '添加') + '用户', url: 'userForm.html', data: { user: mUser }, // 传递数据到表单页面 end: function () { if (admin.getLayerData(layIndex, 'formOk')) { // 判断表单操作成功标识 insTb.reload(); // 成功刷新表格 } }, success: function (layero, dIndex) { // 弹窗超出范围不出现滚动条 $(layero).children('.layui-layer-content').css('overflow', 'visible'); } }); } }); </script>

    使用url参数指定弹窗的页面地址,url这个参数是admin.open新增的,这样做就会把表单页面的html使用ajax加载到弹窗中, 而不是iframe嵌入,这样表单里面的下拉框、日期等组件就可以超出弹窗的范围,不会导致弹窗出现滚动条。

    注意:表单页面是html片段,表单页面和表格页面不要出现重复的id,因为最终是在一个页面上

     

    10.7.第四种 捕获层弹窗

    第一种页面层弹窗由于所有关于弹窗内元素的操作都要写在弹窗的success里面, 部分人可能不适应这种方式,所以介绍第四种捕获层弹窗:

    <!-- 表单弹窗,加display: none默认隐藏 --> <form style="display: none;" id="modelRoleForm" lay-filter="modelRoleForm" class="layui-form model-form"> <input name="roleId" type="hidden"/> <div class="layui-form-item"> <label class="layui-form-label">角色名</label> <div class="layui-input-block"> <input name="roleName" class="layui-input" placeholder="请输入角色名" lay-verType="tips" lay-verify="required" required/> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">备注</label> <div class="layui-input-block"> <textarea name="comments" placeholder="请输入内容" class="layui-textarea"></textarea> </div> </div> <div class="layui-form-item text-right"> <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">取消</button> <button class="layui-btn" lay-filter="modelSubmitRole" lay-submit>保存</button> </div> </form> <!-- js部分 --> <script> layui.use(['layer', 'form', 'table', 'admin'], function () { var $ = layui.jquery, layer = layui.layer, form = layui.form, table = layui.table,admin = layui.admin; var formUrl; // 渲染表格 var insTb = table.render({...}); // 添加 $('#btnAddRole').click(function () { showEditModel(); }); // 表格工具条点击事件 table.on('tool(tableRole)', function (obj) { var data = obj.data; var layEvent = obj.event; if (layEvent === 'edit') { // 修改 showEditModel(data); } }); // 显示编辑弹窗 function showEditModel(mRole) { $('#modelRoleForm')[0].reset(); // 重置表单 form.val('modelRoleForm', mRole); // 回显数据 formUrl = mRole ? 'role/update' : 'role/add'; admin.open({ type: 1, fixed: true, // 加这个可解决没有居中的问题 title: (mRole ? '修改' : '添加') + '角色', content: $('#modelRoleForm') // 这里是重点,没有.html() }); } // 表单提交事件 form.on('submit(modelSubmitRole)', function (data) { layer.load(2); $.post(formUrl, data.field, function (res) { layer.closeAll('loading'); if (res.code == 200) { admin.closeDialog('#modelRoleForm'); layer.msg(res.msg, {icon: 1}); insTb.reload(); } else { layer.msg(res.msg, {icon: 2}); } }, 'json'); return false; }); }); </script>

    与第一种的区别是form不用<script>包裹,加style="display:none"隐藏, admin.open的content是$('#roleForm')而不是$('#roleForm').html(), 表单的提交事件可以直接写在外面,而不用写在弹窗的success里面。

    捕获层的弊端就是弹窗的页面代码最好是写在body下面,不然样式会被其他样式影响。

     

    10.4.四种方式选择指南

    方式推荐理由第一、四种建议初学者使用这种不涉及两个页面传值问题第二种iframe推荐表单跟表格无交互使用,比如详情下拉框、日期不能超出弹窗第三种url表单弹窗、页面有交互建议使用页面传值方便,不存在问题

    如果四种弹窗方式的用法都掌握了更好,这四种足以灵活应对各种业务场景了。

     

    10.5.admin.modelForm方法

    此方法是把layer弹窗自带的确定按钮绑定成表单的提交按钮:

    <!-- 表单弹窗 --> <script type="text/html" id="modelUser"> <div class="layui-form-item"> <label class="layui-form-label">用户名</label> <div class="layui-input-block"> <input name="nickName" class="layui-input" lay-verType="tips" lay-verify="required" required/> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">备注</label> <div class="layui-input-block"> <textarea name="comments" class="layui-textarea"></textarea> </div> </div> </script> <!-- js部分 --> <script> layui.use(['layer', 'form', 'admin'], function () { var $ = layui.jquery, layer = layui.layer, form = layui.form, admin = layui.admin; admin.open({ type: 1, title: '添加用户', btn: ['确定', '取消'], content: $('#modelUser').html(), success: function (layero, dIndex) { // 把确定按钮绑定表单提交,参数二是给按钮起一个lay-filter,参数三是给表单起一个lay-filter admin.modelForm(layero, 'demoFormSubmit', 'demoForm'); // 给表单赋值 form.val('demoForm', {nickName: '张三', sex: '男'}); // 监听表单提交 form.on('submit(demoFormSubmit)', function (data) { layer.msg(JSON.stringify(data.field)); return false; }); }, yes: function () { // 确定按钮方法什么都不要操作 } }); }); </script>

    admin.modelForm()这个方法会把弹窗外面包一个form,然后把确定按钮加lay-submit,所以你的表单页面不需要写form和确定按钮,只需要写表单项。

    这个方法的使用场景为你想要表单的按钮固定,只滚动表单内容部分,可以用这个操作, 当然前面介绍的4中方式也是支持固定按钮的,请到css组件样式中查看详细介绍。

     

    10.6.参数传递方法详解

    参数传递:

    admin.open({ type: 2, content: 'userForm.html', data: { name: '李白', sex: '男' } });

    通过data属性进行参数传递,data同样是admin.open新增的参数。

    获取参数:

    方法说明参数admin.getLayerData(index)获取某弹窗的全部参数layer的indexadmin.getLayerData(index, key)参数某弹窗参数的某个字段index,字段admin.getLayerData()iframe弹窗子页面获取参数无任何参数admin.getLayerData('#xxForm')url方式弹窗子页面获取参数弹窗内任意元素id

    如果是在iframe弹窗的子页面中可以使用admin.getLayerData()直接获取父页面传递的全部参数, 如果是在url方式打开的弹窗中可以使用admin.getLayerData('#xx')直接获取父页面的全部参数,'#xx'是弹窗内任意元素的id。

    增加参数:

    方法说明参数admin.putLayerData(key, value, index)增加参数字段名,值,indexadmin.putLayerData(key, value)iframe弹窗子页面增加参数字段名,值admin.putLayerData(key, value, '#xx')url方式弹窗子页面增加参数弹窗内任意元素id

    关于子页面向父页面传递参数,子页面put新参数,父页面根据弹窗的index取参数就可以了,上面四种方式弹窗中就有示例, 子页面修改成功了put了一个formOk的标识,父页面通过这个标识判断是否要刷新表格。

    注意: data参数必须是对象的形式,data: 1、data: 'aa'这种写法会导致无法put新参数。

     

    10.7.刷新url方式弹窗

    admin.reloadLayer(index, url, success); index     弹窗的index,可以用admin.getLayerIndex('#elem')获取页面层indexurl       用新的url刷新(可不填)success   刷新完成的回调,function类型(可不填)

    iframe弹窗可以用location.reload()或者iframe.contentWindow.location.reload()来刷新弹窗页面。

     

    10.8.弹窗使用模板引擎

    admin.open({ url: 'dialog-url.html', data: { name: '妲己', sex: '女' }, tpl: true // 增加tpl:true开启模板引擎 });

    dialog-url.html代码:

    <div>NAME: {{d.name}}</div> <div>SEX: {{d.sex}}</div> <a class="layui-btn" ew-event="closeDialog">关闭我</a> <script> layui.use(['layer'], function () { var $ = layui.jquery; }); </script>

    模板引擎语法同laytpl,d表示弹窗传递的数据,页面层也支持tpl: true,捕获层和iframe层不支持, 可以使用动态模板功能。

     

    11.1.跨页面操作

    单页面是可以直接跨页面操作的:

    table.reload('userTab', {}); // 刷新其他页面表格

    layui.use里面定义的变量想在其他页面访问:

    layui.use(['layer'], function() { window.xxx = 'xxxx'; // 变量给其他页面访问 // 方法给其他页面访问 window.xxx = function(){ alert('aa'); }; });

     

    11.2.nginx部署解决跨域

    部署只需要把前端所有代码放在nginx的html中,修改setter.js的baseServer为接口地址即可, 如果接口没有做跨域支持,可使用nginx反向代理来解决跨域问题:

    打开“nginx/conf/nginx.conf”配置文件设置反向代理: http { server { # 加入以下配置,之前的配置全部不要动,这个location是新加入的 location /api/ { proxy_pass http://11.11.111.111:8088/; # 这个是后台接口所在的地址 } } } 修改setter.js里面的baseServer为/api/。

    这样配置接口就会访问localhost:80/api/,然后nginx再反向代理到实际接口。

     

    11.3.多系统模式

    在header中有几个选项:“xx系统”、“xx系统”,点击不同的系统切换不同的侧边菜单,查看演示。

    侧边栏代码,使用nav-id标识不同的菜单:

    <div class="layui-side"> <div class="layui-side-scroll"> <!-- 系统一的菜单,每个ul都加nav-id --> <ul nav-id="xt1" class="layui-nav layui-nav-tree" lay-filter="admin-side-nav"> <!-- ...省略代码... --> </ul> <!-- 系统二的菜单,加layui-hide隐藏 --> <ul nav-id="xt2" class="layui-nav layui-nav-tree layui-hide" lay-filter="admin-side-nav"> <!-- ...省略代码... --> </ul> </div> </div>

    header.html代码,使用nav-bind绑定侧边栏菜单:

    <div class="layui-header"> <ul class="layui-nav layui-layout-left"> <li class="layui-nav-item"><a nav-bind="xt1">系统一</a></li> <li class="layui-nav-item"<a nav-bind="xt2">系统二</a></li> </ul> </div>

     

    11.4.logo文字换行显示

    <div class="layui-logo"> <img src="assets/images/logo.png"/> <cite style="display: inline-block;line-height: inherit;margin-top: -4px;"> EasyWeb<br/>iframe </cite> </div>

     

    11.5.侧边栏全部展开

    首先要去掉lay-shrink="_all"这个属性关闭手风琴,然后加layui-nav-itemed默认展开:

    <ul class="layui-nav layui-nav-tree" lay-filter="admin-side-nav" lay-shrink="false"> <li class="layui-nav-item layui-nav-itemed"> ......省略 </li> <li class="layui-nav-item layui-nav-itemed"> ......省略 </li> </ul>

    3.1.8之前的版本由于修改了layui还需要在layui-nav-child上加style:

    <ul class="layui-nav layui-nav-tree" lay-filter="admin-side-nav" lay-shrink="false"> <li class="layui-nav-item layui-nav-itemed"> <a>Dashboard</a> <dl class="layui-nav-child" style="display: block;"> <dd><a>工作台</a></dd> </dl> </li> </ul>

     

    11.6.侧边栏折叠图标放大

    侧边栏折叠后图标会进行放大,如果要修改大小添加css修改font-size,如果不想放大改成14px:

    @media screen and (min-width: 750px) { .layui-layout-admin.admin-nav-mini .layui-side .layui-nav .layui-nav-item > a > .layui-icon { font-size: 18px; } }

     

    11.7.弹窗下拉框出现滚动条

    非iframe类型的弹窗才能解决(页面层、捕获层、url方式等):

    admin.open({ type: 1, title: '添加用户', content: $('#model').html(), success: function (layero, index) { // 禁止出现滚动条,关键代码就是这句 $(layero).children('.layui-layer-content').css('overflow', 'visible'); } });

     

    11.8.弹窗宽度不能超出屏幕

    这个是针对手机屏幕下做了让弹窗宽度自适应,如果需要让弹窗宽度超出屏幕:

    admin.open({ title: '添加用户', content: $('#model').html(), success: function (layero, index) { $(layero).css('max-width', 'unset'); // 去掉max-width属性,unset在ie无效可以用auto } });

     

    11.9.表单文字出现换行

    layui的表单左边标题最多显示5个字,超出会换行,添加css修改宽度:

    #userForm .layui-form-label { width: 100px; /* 这里修改标题宽度 */ } #userForm .layui-input-block { margin-left: 130px; /* 这里要比上面始终大30px */ }

    #userForm是表单的id,加id避免影响其他表单样式:

    <form id="userForm" class="layui-form"> <div class="layui-form-item"> <label class="layui-form-label">活动起止时间</label> <div class="layui-input-block"> <input type="text" class="layui-input"/> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">活动详细介绍</label> <div class="layui-input-block"> <textarea class="layui-textarea" maxlength="200"></textarea> </div> </div> </form>

     

    11.10.select、radio不显示

    select(下拉框)、radio(单选框)等表单元素在layui中会被美化,对于动态生成的元素需要重新渲染才能美化:

    $('div').appen('<select><option value="1">xxxx</option></select>'); form.render('select'); // 重新渲染select form.render('radio'); // 重新渲染radio form.render('checkbox'); // 重新渲染checkbox // 对于弹窗内select不显示 admin.open({ type: 1, content: '<select><option value="1">xxxx</option></select>', success: function(){ form.render('select'); // 弹窗要在success里重新渲染 } });

    另外需要注意父元素有layui-form这个class才会被layui识别并美化。

     

    11.11.日期laydate不能显示

    如果是因为窗口太小不能显示,可以加个trigger: 'click'解决:

    laydate.render({ elem: '#xxx', type: 'date', trigger: 'click' });

    如果是弹窗中的laydate不显示,检查是否是在弹窗的success里面渲染的:

    admin.open({ type: 1, content: $('#modelUser').html(), success: function (layero, dIndex) { laydate.render({ elem: '#xxx', type: 'date', }); } });

     

    11.12.弹窗打开后按enter无限打开

    弹窗打开后焦点还位于点击打开的按钮上,就会导致按enter键无限打开,解决办法就是让焦点移到其他元素上, 下面是将焦点移到弹窗内表单提交按钮上:

    admin.open({ type: 1, title: '添加用户', content: $('#userEditDialog').html(), success: function (layero, dIndex) { $(layero).find('[lay-submit]').focus(); } });

     

    11.13.表单提交post变成了get

    首先检查监听表单提交事件里面有没有写return false,表单里面如果有其他按钮要加type="button",如果还会导致点击按钮刷新页面, 一般是你的代码有报错的地方,建议将<form class="layui-form"></form>改成<div class="layui-form"></div>,form改成div对表单提交不会有任何影响, 只是不能按回车键提交表单,不能重置表单了,改成div后报错就不会导致刷新页面了,你可以看控制台里面的错误信息。

    <form class="layui-form"> <div class="layui-form-item"> <div class="layui-inline"> <label class="layui-form-label">账号:</label> <div class="layui-input-inline"> <input name="username" class="layui-input" placeholder="输入账号"/> </div> </div> <div class="layui-inline"> <label class="layui-form-label">用户名:</label> <div class="layui-input-inline"> <input name="nickName" class="layui-input" placeholder="输入用户名"/> </div> </div> <div class="layui-inline"> <button class="layui-btn" lay-filter="userTbSearch" lay-submit>搜索</button> <button type="reset" class="layui-btn">重置</button> </div> </div> </form> <script> /* 监听表单提交 */ form.on('submit(userTbSearch)', function (data) { return false; }); </script>

     

    11.14.修改表格背景和边框颜色

    /* 表格背景颜色 */ .layui-table tbody tr:hover, .layui-table thead tr, .layui-table-click, .layui-table-header, .layui-table-hover, .layui-table-mend, .layui-table-patch, .layui-table-tool, .layui-table-total, .layui-table-total tr, .layui-table[lay-even] tr:nth-child(even) { background-color: #f5f7fa; } /* 表格边框颜色 */ .layui-table td, .layui-table th, .layui-table-col-set, .layui-table-fixed-r, .layui-table-grid-down, .layui-table-header, .layui-table-page, .layui-table-tips-main, .layui-table-tool, .layui-table-total, .layui-table-view, .layui-table[lay-skin=line], .layui-table[lay-skin=row] { border-color: #ebeef5; }

     

    11.15.修改placeholder颜色

    .layui-input::-webkit-input-placeholder, .layui-textarea::-webkit-input-placeholder { color: #ccc; } .layui-input::-moz-placeholder, .layui-textarea::-webkit-input-placeholder { color: #ccc; } .layui-input::-ms-input-placeholder, .layui-textarea::-webkit-input-placeholder { color: #ccc; } body xm-select > .xm-tips { color: #ccc; }

     

    11.16.IE数据表格缓存严重

    在渲染和重载表格的时候加一个随机参数:

    /* 渲染表格 */ var insTb = table.render({ elem: '#userTable', url: '../../json/user.json', where: {v: new Date().getTime()}, cols: [[ {type: 'checkbox'}, {type: 'numbers'}, {field: 'username', title: '账号', sort: true}, {field: 'nickName', title: '用户名', sort: true} ]] }); /* 重载表格 */ form.on('submit(userTbSearch)', function (data) { data.field.v = new Date().getTime(); insTb.reload({where: data.field, page: {curr: 1}}); return false; }); insTb.reload({where: {v: new Date().getTime()}, page: {curr: 1}});

     

    11.17.使用parent.layer问题

    如果用的是parent.layui.admin.open打开的弹窗,弹窗success里面的一些操作也应该相应的加parent:

    function showEditModel(mData) { parent.layui.admin.open({ type: 1, title: (mData ? '修改' : '添加') + '用户', content: $('#userEditDialog').html(), success: function (layero, dIndex) { // 回显表单数据 parent.layui.formX.val('userEditForm', mData); // 表单提交事件 parent.layui.form.on('submit(userEditSubmit)', function (data) { return false; }); // 禁止弹窗出现滚动条 parent.layui.jquery(layero).children('.layui-layer-content').css('overflow', 'visible'); } }); }

    需要注意的是parent.layui.form.val不支持跨iframe的数据,可以使用formX模块,$应该用parent.layui.jquery。

    如果你喜欢跨iframe操作,你需要了解window、parent、top:

    <iframe id="child" src="child.html"></iframe> <script> layui.use(['jquery'], function() { var $ = layui.jquery; window.aaa = 'aaa'; // 定义变量到window下 // 定义方法到window下 window.bbb = function(str) { alert(str); }; // 访问iframe的变量 var childWin = $('#child')[0].contentWindow; console.log(childWin.ccc); childWin.location.reload(); // 刷新iframe页面 }); </script>

    child.html:

    <script> layui.use(['jquery'], function() { window.ccc = 'ccc'; // 定义变量到window下 parent.aaa = '__a'; // 修改parent的变量 parent.bbb('bbb'); // 调用parent的方法 }); </script>

     

    11.18.表格打印太长列未换行

    // 如果phone这一列全是字母和数字并且很长打印的时候不会自动换行 {field: 'phone', title: '手机号'} // 改成这样就会自动换行了 { field: 'phone', title: '手机号', templet: '<div><div style="word-break: break-all;">{{d.phone}}</div></div>' }

    注意要两个div,样式加在里面的div上面。

     

    11.19.弹窗layer.js报错404

    这个问题一般是由于弹窗是url方式的弹窗,弹窗页面内又引入js、css导致的:

    admin.open({ url: 'password.html' });

    url方式的弹窗页面是片段,不是完整的html,请不要包含<html>、<head>、<body>这些,不要重复引用layui.js:

    <form class="layui-form model-form"> </form> <script> layui.use(['layer', 'form'], function () { }); </script>

    如果是主题、修改密码、便签、消息等弹窗出现的,是老版本使用的iframe弹窗方式,新版本默认改成url方式导致的,可升级对应的弹窗页面解决, 也可以配置成iframe弹窗:

    <a ew-event="theme" data-type="2" data-content="page/tpl/tpl-theme.html">主题</a>

     

    11.20.表格请求去掉page和limit

    数据表格即使设置了page: false发送的请求还是会有page、limit这两个参数,page参数是无法去掉的,只能去掉limit参数:

    table.render({ elem: '#userTable', url: '../../json/user.json', page: false, limit: null });

    后端可以判断如果limit参数为null就不分页查询全部,你也可以规定limit为0或者-1就查询全部。

     

     

    12.1.表格内switch获取行数据

    用户管理演示了表格内开关switch的使用,这里只用到了数据的id修改状态, 如果要获取所在行的更多数据,可以通过加data-属性:

    <script type="text/html" id="userTbState"> <input type="checkbox" lay-filter="userTbStateCk" value="{{d.userId}}" lay-skin="switch" data-name="{{d.username}}" data-sex="{{d.sex}}" lay-text="正常|锁定" {{d.state==0?'checked':''}}/> </script> <script> form.on('switch(userTbStateCk)', function (obj) { var id = obj.elem.value; var data = $(obj.elem).data(); console.log(id + data.name + data.sex); }); </script>

    也可以利用LAY_TABLE_INDEX获取:

    <script type="text/html" id="userTbState"> <input type="checkbox" lay-filter="userTbStateCk" value="{{d.LAY_TABLE_INDEX}}" lay-skin="switch" lay-text="正常|锁定" {{d.state==0?'checked':''}}/> </script> <script> form.on('switch(userTbStateCk)', function (obj) { var index = obj.elem.value; var data = table.cache['userTable'][index]; console.log(data.userId + data.username); }); </script>

    表格中的下拉框select的用法与表格中的开关switch是一样的,可以参考使用:

    <!-- 表格性别选择列 --> <script type="text/html" id="tbBasicTbSex"> <div class="ew-select-fixed"> <select lay-filter="tbBasicTbSexSel" data-index="{{d.LAY_INDEX}}"> <option value="">请选择</option> <option value="男" {{d.sex=='男'?'selected':''}}>男</option> <option value="女" {{d.sex=='女'?'selected':''}}>女</option> </select> </div> </script> <script> form.on('select(tbBasicTbSexSel)', function(obj){ var index = $(obj.elem).data('index'); var data = table.cache['userTable'][index]; console.log(data); // 得到当前行数据 console.log(obj.value); // 得到被选中的值 }); </script>

     

    12.2.表格回显复选框

    var insTb = table.render({ elem: '#userTable', url: '../../json/user.json', cols: [[ {type: 'checkbox'}, {type: 'numbers'}, {field: 'username', title: '账号', sort: true}, {field: 'nickName', title: '用户名', sort: true} ]], parseData: function(res) { res.data[3].LAY_CHECKED = true; // 让第4条数据选中 return res; } });

     

    12.3.表格工具列动态显示

    工具列中可以使用模板引擎语法:

    <script type="text/html" id="userTbBar"> <a class="layui-btn" lay-event="view">查看</a> {{# if(d.state==0){ }} <a class="layui-btn" lay-event="send">发送</a> {{# }else if(d.state==1){ }} <a class="layui-btn" lay-event="back">撤回</a> {{# } }} <a class="layui-btn" lay-event="del">删除</a> </script>

     

    12.4.表单提交数组

    layui的表单提交、赋值等不支持数组及嵌套的格式,可以通过简单的格式处理数据为自己想要的格式:

    <form class="layui-form" lay-filter="demoForm"> <input name="name" class="layui-input"/> <input name="role__0" class="layui-input"/> <input name="role__1" class="layui-input"/> <input name="role__2" class="layui-input"/> <input name="sex__0" class="layui-input"/> <input name="sex__1" class="layui-input"/> <button class="layui-btn" lay-filter="demoSubmit" lay-submit>提交</button> </form> <script> /* 监听表单提交 */ form.on('submit(demoSubmit)', function (data) { var roleList = [], sexList = []; for(var f in data.field) { if(f.indexOf('role__') === 0) { roleList.push(data.field[f]); delete data.field[f]; } if(f.indexOf('sex__') === 0) { sexList.push(data.field[f]); delete data.field[f]; } } data.field.roleList = roleList; data.field.sexList = sexList; console.log(data.field); return false; }); /* 赋值 */ var res = {roleList:[], sexList: []}; for(var i=0;i<res.roleList.length;i++) { res['role__'+i] = res.roleList[i]; } form.val('demoForm', res); </script>

     

    12.5.重载表格重置排序

    insTb.reload({ where: {}, page: {curr: 1}, initSort: {field: 'createTime', type: null} });

    field写任意一个字段名称即可。

     

    12.6.laydte动态控制日期限制

    以最小日期限制举例:

    /* 渲染日期 */ var insDate = laydate.render({ elem: '#test1', min: 7 }); var minConfig = insDate.config.min; // 获取配置的最小日期限制 /* 取消最小日期限制 */ insDate.config.min = {}; /* 恢复最小日期限制 */ insDate.config.min = minConfig;

     

    12.7.下拉树一些数据不可选

    以演示页面的权限管理为例,让类型为按钮不可选:

    // 这个是treeTable提供的遍历数据的方法 insTb.eachData(function(i,item){ if (!item.isMenu) item.disabled = true; // 如果是按钮设置不可选 }); // 渲染下拉树 var insXmSel = xmSelect.render({ el: '#authoritiesEditParentSel', data: insTb.options.data, // 用treeTabled的数据 model: {label: {type: 'text'}}, prop: { name: 'authorityName', value: 'authorityId' }, radio: true, clickClose: true, tree: { show: true, indent: 15, strict: false, expandedKeys: true } });

     

    12.8.修改弹窗禁用输入框

    /* 显示表单弹窗 */ function showEditModel(mData) { admin.open({ type: 1, title: (mData ? '修改' : '添加') + '用户', content: $('#userEditDialog').html(), success: function (layero, dIndex) { if(mData) { // 表示是修改 // 把账号输入框变为只读 $(layero).find('[name="username"]').attr('readonly', 'readonly'); // 把密码输入框移除 $(layero).find('[name="password"]').parent().parent().remove(); } } }); }

     

    12.9.表格中下拉框数据动态

    模板页面/列表页/数据表格 中展示了表格中下拉框的使用,如何将下拉框的数据变为动态的(来源后端的):

    var sexList = [{name: '男', value:0}, {name:'女', value: 1}]; var sexHtml = '<div><div class="ew-select-fixed"><select lay-filter="tbBasicTbSexSel">'; layui.each(sexList, function(i,item){ sexHtml += ('<option value="' + item.value + '">' + item.name + '</option>'); }); sexHtml += '</select></div></div>'; /* 渲染表格 */ var insTb = table.render({ elem: '#tbBasicTable', url: '../../../json/user.json', cols: [[ {type: 'checkbox'}, {type: 'numbers'}, {field: 'username', title: '账号', align: 'center', sort: true}, {field: 'sex', title: '性别', templet: sexHtml, sort: true} ]] });

    如果数据是ajax请求的,应该用同步的请求,或者在请求结束后再渲染表格:

    var insTb, sexList = []; $.get('sex.json', function(res) { sexList = res.data; var sexHtml = '......省略'; /* 渲染表格,......省略具体代码 */ insTb = table.render({}); });

     

    12.10.实现点击后转一圈

    有一个刷新按钮,用的layui的刷新图标,点击后实现图标转圈,刷新完后停止转圈:

    <i id="btnRefresh" class="layui-icon layui-icon-refresh"></i> <script> $('#btnRefresh').click(function() { $('#btnRefresh').removeClass('layui-anim layui-anim-rotate'); setTimeout(function() { $('#btnRefresh').addClass('layui-anim layui-anim-rotate'); // $('#btnRefresh').addClass('layui-anim layui-anim-rotate layui-anim-loop'); }); }); </script>

    多加一个classlayui-anim-loop是实现一直转圈,没有这个只会转一圈。

     

    12.11.页面下拉框数据动态

    演示页面里面的下拉框之所以都是直接写的静态的,是因为实际项目中也可能后端渲染,也可能ajax渲染, 如果是前后端不分离项目建议直接用后端模板引擎渲染,如果是前后端分离方式需要用ajax渲染。

    可以页面一进入就先获取下拉框的数据:

    <form class="layui-form" lay-filter="userTbSearchForm"> 性别: <select name="sex"></select> </form> <!-- 表单弹窗 --> <script type="text/html" id="userEditDialog"> <form id="userEditForm" lay-filter="userEditForm" class="layui-form model-form"> 性别: <select name="sex" lay-verType="tips" lay-verify="required" required></select> </form> </script> <!-- js部分 --> <script> layui.use(['layer', 'form', 'table', 'formX'], function () { var $ = layui.jquery; var layer = layui.layer; var form = layui.form; var admin = layui.admin; var formX = layui.formX; var mSexList = []; // 所有性别 /* 获取性别数据字典 */ var loadIndex = layer.load(2); admin.req('sys/dictdata', {dictCode: 'sex'}, function (res) { layer.close(loadIndex); if (0 === res.code) { mSexList = res.data; // 渲染搜索栏中的性别select formX.renderSelect({ elem: '[lay-filter="userTbSearchForm"] select[name="sex"]', data: mSexList, name: 'dictDataName', value: 'dictDataId', hint: '请选择性别' }); } else { layer.msg(res.msg, {icon: 2}); } }); /* 显示表单弹窗 */ function showEditModel(mData) { admin.open({ type: 1, title: (mData ? '修改' : '添加') + '用户', content: $('#userEditDialog').html(), success: function (layero, dIndex) { form.val('userEditForm', mData); // 回显表单数据 // 渲染性别下拉 formX.renderSelect({ elem: '[lay-filter="userEditForm"] select[name="sex"]', data: mSexList, name: 'dictDataName', value: 'dictDataId', hint: '请选择性别', initValue: mData ? mData.sex : undefined }); } }); } }); </script>

     

    12.12.表格动态tool事件处理

    <!-- 表格操作列 --> <script type="text/html" id="userTbBar"> {{# layui.each(d.roles, function(i, item) { }} <a class="layui-btn" lay-event="role" data-index="{{i}}">{{item.roleName}}</a> {{# }); }} </script> <script> table.render({ elem: '#userTable', cols: [[ {field: 'username', title: '账号'}, {field: 'sex', title: '性别'}, {title: '角色', toolbar: '#userTbBar'} ]] }); /* 表格工具条点击事件 */ table.on('tool(userTable)', function (obj) { var d = obj.data; if (obj.event === 'role') { var i = $(this).data('index'); console.log(d.roles[i]); } }); </script>

    像上面这样角色是动态循环出来的,想监听点击每一行的每个角色的事件,并且获取到点击的行的数据和点击的角色的数据, 获取行的数据table模块直接提供,如果要获取点击的角色对应的数据,就可以参考上面用data-index来实现。

     

    12.13.表格复选框和序号列合并

    table.render({ elem: '#userTable', cols: [[ { title:'<input type="checkbox" name="layTableCheckbox" lay-skin="primary" lay-filter="layTableAllChoose">', templet: '<div><input type="checkbox" name="layTableCheckbox" lay-skin="primary"> {{d.LAY_INDEX}}</div>' }, {field: 'username', title: '账号'}, {field: 'sex', title: '性别'} ]] });

    用title加全选框,用templet加复选框,用d.LAY_INDEX获取序号。

     

    12.14.表单提交带文件上传

    <form class="layui-form" id="demoForm"> <input type="file" name="file" class="layui-input"/> <input type="text" name="title" class="layui-input"/> <button class="layui-btn" lay-filter="demoSubmit" lay-sunmit>提交</button> </form> <script> form.on('submit(demoSubmit)', function (data) { var formData = new FormData(); for(var f in data.field) { if(!data.field.hasOwnProperty(f)) continue; formData.append(f, data.field[f]); } $('#demoForm [type="file"]').each(function() { formData.append($(this).attr('name'), $(this)[0].files[0]); }); $.ajax({ url:'/url', type:'post', processData:false, contentType:false, data:formData, success:function (res) { console.log(res); } }); return false; }); </script>

     

    12.15.单标签模式加居中文字

    在index.loadHome方法之后加js插入内容:

    index.loadHome('......省略'); // 插入居中文字 $('.layui-body-header').addClass('text-center'); $('.layui-body-header-title').addClass('pull-left').css({'line-height': 'initial', 'margin-top': '10px'}) .after('<span>天气预报</span>');

    最后实现的效果:

    增加循环滚动的效果,类似滚动公告,加一个marquee就实现了:

    <span style="display: inline-block;height: 40px;"><marquee>天气预报</marquee></span>

     

     

    13.1.基础用法

    layRouter是封装的一个简单的路由模块,给index模块作为支撑的,一般不需你要去直接用它, layRouter模块相对独立,你也可以拿出来用在自己的网站中,使用示例:

    <a href="#/user">go user</a> <a href="#/home">go home</a> <div id="m"></div> <script> layui.use(['layRouter'], function() { var layRouter = layui.layRouter; layRouter.reg('#/home', function(routerInfo) { document.getElementById('m').innerHTML = 'Hello World'; }).reg('#/user', function(routerInfo) { document.getElementById('m').innerHTML = 'This is user page'; }); layRouter.init({ index: '/home' /* 首页地址 */ }); }); </script>

    打开例子后,会默认在id为m的div中显示 Hello World。 然后点击go user的链接,会跳转到 http://xx.com/#/user ,并且在id为m的div中显示 his is user page。

     

    13.2.注册路由

    调用reg方法,参数一是路由关键字,参数二是路由触发的回调方法:

    layRouter.reg('#/home', function(routerInfo) { console.log(routerInfo); }); // 参数一支持数组写法,并且#号是可以有可无的 layRouter.reg(['#/home', '/user', 'order'], function(routerInfo) { console.log(routerInfo); }); // 在easyweb框架中要使用这种,具体说明请前往index模块查看 index.regRouter([{ name: '用户管理', url: '#/system/user' }]);

    layRouter.reg是基础的写法,下面是index模块封装的写法,使用index.regRouter注册后访问#/system/user,就会打开一个“用户管理”的标签页,使用上面的写法不会。

    在路由触发的回调里面routerInfo包含什么:

    例如你访问 `#/system/user/id=1/sex=男` 它解析的信息为 { path: ["system", "user"], search: {id: 1, sex: "男"}, href: "/system/user/id=1/sex=男", refresh: false } path     路径数组search   参数列表refresh   如果是刷新触发的值为true

     

    13.3.路由参数传递

    参数传递的规则:

    #/system/user // 无参数 #/system/user/id=1 // 参数id=1 #/system/user/id=1/name=aaa // 参数id=1,name=aaa

    这三种类型的url注册路由的时候只会注册#/system/user这个url,后面两个都是加了参数,而且后面的参数可以无限加。

    获取路由的参数:

    var search = layui.router().search; var search = layui.router('#/system/user/id=1/name=aa').search; console.log(search);

    上面是layui提供的方法,建议使用layRouter模块封装的方法:

    var search = layRouter.routerInfo().search; var search = layRouter.routerInfo('#/system/user/id=1/name=aa').search;

    layRouter封装的方法具有容错性,不管有没有#号都可以正确解析。

    关于后端不能识别这种参数的解答:

    有人建议参数用正常的?id=1&name=aa的方式,认为上面这种后端识别不了。首先spa版本一般都是前后端分离的, http://localhost/#/user/id=1这个url不会进入后端,路由地址也并不代表页面的地址, 访问#/user实际请求的页面是components/user.html,而且是ajax请求的。其次这种解析规则是layui自带的方法解析的。 最后为了满足前后端不分离的情况,3.1.6版本开始已经做了适配,当你访问#/user/id=1/name=aa时, ajax请求html页面会发送components/user.html?id=1&name=aa的请求,会把路由的参数带上,便于后端接收。

     

    13.4.跳转页面

    跳转页面(#号可写可不写):

    layRouter.go('#/user'); layRouter.go('/user'); layRouter.go('user');

    刷新页面:

    layRouter.refresh('#/user'); // #号也是可写可不写

    刷新页面与跳转页面的区别:

    layRouter.reg('#/home', function(routerInfo) { console.log(routerInfo); });

    如果当前hash地址已经是#/home了,再go到home,回调是不会触发的,refresh会触发, 并且如果是刷新触发的,回调里面的routerInfo会多一个refresh字段值为true

     

    13.5.路由不存在处理

    layRouter.init({ index: '/home', notFound: function(routerInfo) { } });

    在easyweb中处理路由不存在是setter.js中的routerNotFound方法。

     

    13.6.路由切换监听

    重写pop方法即可监听路由的切换:

    layRouter.pop = function(routerInfo) { console.log(routerInfo); };

     

    13.7.做一个单页网站

    下面演示如何从零实现一个单页面网站,项目结构:

    |- layui |- page | |- home.html | |- order | |- product.html | |- introduction.html |- expand | |- layRouter.js |- index.html

    index.html:

    <html> <body> <a href="#/home">首页</a> <a href="#/order/product">产品</a> <a href="#/order/introduction">订单</a> <div id="LAY_MAIN"></div> <script type="text/javascript" src="layui/layui.js"></script> <script> layui.config({ base: 'expand' }).use(['jquery', 'layRouter'], function() { var $ = layui.jquery; var layRouter = layui.layRouter; layRouter.reg(['#/home', '#/order/product', '#/order/introduction'], function(routerInfo) { var path = routerInfo.path.join('/'); $('#LAY_MAIN').load('page/' + path + '.html'); }); layRouter.init({ index: '/home' }); }); </script> </body> </html>

    home.html:

    <style> #LAY_HOME h2 { color: red; } </style> <div id="LAY_HOME"> <h2>This is Home page.</h2> </div> <script> layui.use(['layer'],function() { var layer = layui.layer; layer.msg('Hello'); }); </script>

    product.html、order.html可自行发挥,然后运行index.html就可以实现一个简单的单页面应用了。

     

     

     

     

     

     

     

     

     

     

     

     

    Processed: 0.015, SQL: 9