多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
## [1.开始使用](https://www.easyweb.vip/doc/#/?id=_1%e5%bc%80%e5%a7%8b%e4%bd%bf%e7%94%a8)  当前版本:`iframe v3.1.3`, 更新于2019/07/12,[【更新日志】](https://easyweb.vip/doc/log/)。 ### [1.1.项目结构](https://www.easyweb.vip/doc/#/?id=_11%e9%a1%b9%e7%9b%ae%e7%bb%93%e6%9e%84) ~~~ |-assets | |-css // 样式 | |-images // 图片 | |-js // javascript | |-common.js // 公共js,主要配置layui扩展模块位置 | |-libs // 第三方库,echarts(图表)、layui(ui框架) | |-module // layui扩展模块,版本更新只用替换此目录 | |-theme // 主题资源 | |-admin.css // admin样式 | |-admin.js // admin模块 | |-index.js // index模块 | |-contextMenu.js // 鼠标右键模块 | |-printer.js // 打印模块 | |-******** // 其他模块,不一一列举 |-page // html页面 |-json // 模拟数据 |-index.html // 主页面 ~~~ > 与后端整合从index.html页面入手,page、json可以删除,assets整个目录都是静态资源。 ### [1.2.导入项目](https://www.easyweb.vip/doc/#/?id=_12%e5%af%bc%e5%85%a5%e9%a1%b9%e7%9b%ae) 1. 在`我的订单`中下载项目源码; 2. 使用IDEA、WebStorm、HBuilder等工具打开; 3. 运行index.html启动: ![运行教程](https://s2.ax1x.com/2019/07/06/ZwThon.jpg) > 注意:使用`http://`的形式访问,而不是使用`file://`的形式访问。 ### [1.3.index.html结构说明](https://www.easyweb.vip/doc/#/?id=_13indexhtml%e7%bb%93%e6%9e%84%e8%af%b4%e6%98%8e) ~~~ <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/common.js"></script> <script> layui.use(['index'], function () { var index = layui.index; // 加载主页 index.loadHome({ menuPath: 'page/console/console.html', menuName: '<i class="layui-icon layui-icon-home"></i>' }); }); </script> </body> </html> ~~~ > index.html就是这样固定的结构,在整合到后台时,你可以把头部、侧边栏抽离出来,再include进去。 ### [1.4.添加一个菜单](https://www.easyweb.vip/doc/#/?id=_14%e6%b7%bb%e5%8a%a0%e4%b8%80%e4%b8%aa%e8%8f%9c%e5%8d%95) 1. 打开`index.html`,找到侧导航栏,添加一个菜单: ~~~ <dd><a lay-href="xxx.html">XX管理</a></dd> <!-- 还可以增加ew-title属性自定义打开的Tab标题 <a lay-href="xxx.html" ew-title="XXXXX">XX管理</a> --> ~~~ 2. 新建一个`xxx.html`页面; 3. 运行项目,查看效果。 > 注意:a标签里面是`lay-href`而不是`href`,lay-href点击会打开一个Tab标签页。 ### [1.5.common.js说明](https://www.easyweb.vip/doc/#/?id=_15commonjs%e8%af%b4%e6%98%8e) ~~~ layui.config({ base: getProjectUrl() + 'assets/module/' // 配置layui扩展模块目录 }).extend({ // 配置每个模块分别所在的目录 notice: 'notice/notice', step: 'step-lay/step' }).use(['admin'], function () { var admin = layui.admin; // 移除loading动画 setTimeout(function () { admin.removeLoading(); }, window == top ? 600 : 100); }); // 获取项目根路径 function getProjectUrl() { return '...省略'; } ~~~ * layui.config是告诉layui扩展模块所在目录; * layui.extend是配置每个模块具体js位置; * admin.removeLoading()是移除页面加载动画;  像`admin.js`、`index.js`这些没有用子目录存放的模块不需要配置layui.extend,延时移除加载动画是给切换主题预留时间。 > 每个页面都需要引入common.js * * * ## [2.index模块](https://www.easyweb.vip/doc/#/?id=_2index%e6%a8%a1%e5%9d%97) 使用方法: ~~~ layui.use(['index'], function () { var index = layui.index; }); ~~~ ### [2.1.选项卡配置](https://www.easyweb.vip/doc/#/?id=_21%e9%80%89%e9%a1%b9%e5%8d%a1%e9%85%8d%e7%bd%ae) | 配置名 | 默认 | 说明 | | :-- | :-- | :-- | | pageTabs | true | 是否开启多标签 | | cacheTab | true | 是否记忆打开的选项卡 | | openTabCtxMenu | true | 是否开启Tab右键菜单 | | maxTabNum | 20 | 最多打开多少个tab | 修改默认配置直接打开index.js修改这几个参数即可: ~~~ var index = { pageTabs: true, // 是否开启多标签 cacheTab: true, // 是否记忆打开的选项卡 openTabCtxMenu: true, // 是否开启Tab右键菜单 maxTabNum: 20 // 最多打开多少个tab // ... 省略 } ~~~ > 在设置界面修改的配置会高于index中的默认配置,设置界面的配置信息是放在缓存中,清除缓存就会以index中配置为主。 ### [2.2.loadHome加载主页](https://www.easyweb.vip/doc/#/?id=_22loadhome%e5%8a%a0%e8%bd%bd%e4%b8%bb%e9%a1%b5) ~~~ layui.use(['index'], function () { var index = layui.index; index.loadHome({ menuPath: 'page/console/console.html', menuName: '<i class="layui-icon layui-icon-home"></i>' }); }); ~~~ * menuPath: 必填 主页路径 * menuName: 必填 Tab标题 > index.loadHome()方法在index.html中调用即可。 ### [2.3.openTab打开选项卡](https://www.easyweb.vip/doc/#/?id=_23opentab%e6%89%93%e5%bc%80%e9%80%89%e9%a1%b9%e5%8d%a1) ~~~ index.openTab({ title: '百度', url: 'https://www.baidu.com', end: function() { // table.reload('userTable'); } }); ~~~ * title: 选项卡的标题 * url: 打开的页面地址 * end: Tab关闭的回调事件  也可以直接使用`<a ew-href="xxx.html">XXX</a>`,注意是`ew-href`,还可以增加`ew-title`属性设置Tab标题:`<a ew-href="xxx.html" ew-title="XXX管理">XXX</a>`。 > 注意:单标签模式下end回调无效。 ### [2.4.closeTab关闭选项卡](https://www.easyweb.vip/doc/#/?id=_24closetab%e5%85%b3%e9%97%ad%e9%80%89%e9%a1%b9%e5%8d%a1) ~~~ index.closeTab('https://www.baidu.com'); ~~~ 关闭已经打开的Tab选项卡,参数是Tab的url,单标签模式下此方法无效。 ### [2.5.clearTabCache清除Tab记忆](https://www.easyweb.vip/doc/#/?id=_25cleartabcache%e6%b8%85%e9%99%a4tab%e8%ae%b0%e5%bf%86) ~~~ index.clearTabCache(); ~~~  Tab记忆功能是刷新页面的时候可以恢复上次打开的所有Tab,此方法用于清除已经缓存的Tab。 > 注意:在实际项目中,登录成功后应该调用此方法清除Tab记忆。 ### [2.6.setTabTitle修改Tab标题](https://www.easyweb.vip/doc/#/?id=_26settabtitle%e4%bf%ae%e6%94%b9tab%e6%a0%87%e9%a2%98) ~~~ index.setTabTitle('Hello'); // 修改当前Tab标题文字,也支持单标签模式 index.setTabTitle(title, tabId); // 修改指定Tab标题文字 index.setTabTitleHtml('<span>Hello</span>'); // 修改整个标题栏的html,此方法只在单标签模式有效 ~~~  关闭多标签时框架会自动生成一个标题栏,可使用此方法修改标题栏内容,参数为undefined时为隐藏标题栏。 ### [2.7.切换Tab自动刷新](https://www.easyweb.vip/doc/#/?id=_27%e5%88%87%e6%8d%a2tab%e8%87%aa%e5%8a%a8%e5%88%b7%e6%96%b0) 默认是关闭的,在设置界面可开启,如果要直接开启在index.html中添加如下代码: ~~~ $('.layui-body>.layui-tab[lay-filter="admin-pagetabs"]').attr('lay-autoRefresh', 'true'); ~~~ 给layui-tab增加`lay-autoRefresh`属性为true即可。 ### [2.8.侧边栏手风琴折叠](https://www.easyweb.vip/doc/#/?id=_28%e4%be%a7%e8%be%b9%e6%a0%8f%e6%89%8b%e9%a3%8e%e7%90%b4%e6%8a%98%e5%8f%a0) 默认是开启的,如要关闭配置如下: ~~~ <!-- 侧边栏 --> <div class="layui-side"> <div class="layui-side-scroll"> <ul class="layui-nav layui-nav-tree" lay-accordion="false"> ......省略其他部分 </ul> </div> </div> ~~~ 修改`lay-accordion`属性为false或者直接去掉即可。 * * * ## [3.admin模块](https://www.easyweb.vip/doc/#/?id=_3admin%e6%a8%a1%e5%9d%97) ### [3.1.默认主题、存储表名](https://www.easyweb.vip/doc/#/?id=_31%e9%bb%98%e8%ae%a4%e4%b8%bb%e9%a2%98%e3%80%81%e5%ad%98%e5%82%a8%e8%a1%a8%e5%90%8d) 修改这两个默认的配置打开admin.js修改如下参数即可: ~~~ var admin = { defaultTheme: 'theme-admin', // 默认主题 tableName: 'easyweb' // 存储表名 // ...省略 } ~~~ * `defaultTheme`是默认的主题,可修改成`theme-red`等你配置的主题。 * `tableName`是本地缓存的表名,如果一个域名下有多个项目,建议修改成不同的名字。 ### [3.2.全部方法](https://www.easyweb.vip/doc/#/?id=_32%e5%85%a8%e9%83%a8%e6%96%b9%e6%b3%95) | 方法 | 参数 | 描述 | | :-- | :-- | :-- | | flexible(expand) | true和false | 折叠/展开侧导航 | | activeNav(url) | a标签里面的lay-href值 | 设置侧导航栏选中 | | refresh(url) | url,可为空 | 刷新指定Tab或当前Tab | | closeAllTabs() | 无 | 关闭所有选项卡 | | closeOtherTabs(url) | url | 关闭除url外所有选项卡 | | closeThisTabs(url) | url,可为空 | 关闭url或当前选项卡 | | rollPage(d) | 方向(left、right、auto) | 滚动选项卡tab | | iframeAuto() | 无 | 让当前的ifram弹层自适应高度 | | closeThisDialog() | 无 | 关闭当前iframe弹窗 | | closeDialog(elem) | dom选择器 | 关闭elem元素所在的弹窗(页面层弹窗) | | putTempData(key, value) | key,value | 缓存临时数据 | | getTempData(key,) | key | 获取缓存的临时数据 | | parseJSON(string) | 字符串 | 解析json,解析失败返回undefined | | getPageHeight() | 无 | 获取浏览器高度 | | getPageWidth() | 无 | 获取浏览器宽度 | | btnLoading(elem) | dom选择器 | 设置按钮为加载状态 | | openSideAutoExpand() | 无 | 开启鼠标移入侧边栏自动展开 | | openCellAutoExpand() | 无 | 开启鼠标移入表格单元格超出内容自动展开 | | modelForm(layero, btnFilter, formFilter) | | 把弹窗自带的按钮跟弹窗内的表单绑定一起 | 使用示例: ~~~ layui.use(['admin'], function () { var admin = layui.admin; var pageHeight = admin.getPageHeight(); // 获取浏览器高度 }); ~~~ **按钮loading:** ~~~ admin.btnLoading('#btn1'); // 设置按钮为loading状态 admin.btnLoading('#btnLoading', false); // 移除按钮的loading状态 admin.btnLoading('#btn1', '加载中'); // 设置按钮为loading状态,同时修改按钮文字 admin.btnLoading('#btnLoading', '保存', false); // 移除按钮的loading状态,同时修改按钮文字 ~~~ **admin.iframeAuto()方法:** 针对type:2的弹窗自适应弹窗高度,写在你的弹窗的子页面中,此方法是调用一次做一次高度自适应,如果你用js动态修改了弹窗子页面的高度,需要再调用一次。 ~~~ layui.use(['admin'], function(){ var admin = layui.admin; admin.iframeAuto(); }); ~~~ **admin.closeThisDialog()关闭当前iframe类型弹窗:** 针对type:2的弹窗,在弹窗的子页面调用即可关闭当前的iframe弹窗。 **admin.closeDialog(elem)关闭非iframe类型的弹窗:** 调用传递任意一个弹窗页面里面的元素即可,比如弹窗里面有一个`<button id="xxx">`: ~~~ admin.closeDialog('#xxx'); // 即可关闭xxx元素所在的页面层的弹窗 ~~~ 关闭弹窗还可以使用ew-event操作: ~~~ <!-- 关闭iframe类型的弹窗 --> <button ew-event="closeDialog"></button> <!-- 关闭页面层的弹窗 --> <button ew-event="closePageDialog"></button> ~~~ > admin.openSideAutoExpand()方法在index.html中调用,admin.openCellAutoExpand()可在任何页面调用 ### [3.3.弹窗popupRight和open](https://www.easyweb.vip/doc/#/?id=_33%e5%bc%b9%e7%aa%97popupright%e5%92%8copen) ~~~ // 打开弹窗 admin.open({ type: 2, content: 'tpl-theme.html' }); // 右侧打开面板 admin.popupRight({ type: 2, content: 'tpl-theme.html' }); ~~~  这两个方法只是对layer.open进行了一层封装,使得弹窗可以有更好的样式,可以跟随主题改变颜色。 > open和popupRight参数和layer用法一样,查看[layer文档](https://www.layui.com/doc/modules/layer.html)。 popupRight右侧面板示例: ![右侧弹出示例](https://s2.ax1x.com/2019/07/06/Zwov28.jpg)  `type:2, content:xxx`这种是iframe类型的弹窗,也可以使用`url`,这个参数是额外增加的,使用`url`会通过ajax方式加载页面到弹窗中,而不是iframe,看到很多人喜欢把弹窗页面独立,然而父子页面传值又比较麻烦,所以增加了url方式。 ~~~ admin.open({ title: 'Hello', url: 'tpl-theme.html' }); admin.popupRight({ url: 'tpl-theme.html' }); ~~~  当你使用url方式加载的时候,你的弹窗页面应该时代码片段,而不是完整的html,如下所示: ~~~ <form 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" placeholder="请输入角色名" type="text" class="layui-input" maxlength="20" lay-verType="tips" lay-verify="required" required/> </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="modelSubmitRole" lay-submit>保存</button> </div> </form> <script> layui.use(['layer', 'form'], function () { var $ = layui.jquery; var layer = layui.layer; var form = layui.form; // 表单提交事件 form.on('submit(modelSubmitRole)', function (data) { console.log(data.field); return false; }); }); </script> ~~~  页面不需要html、body这些东西,并且可以直接用`<script>`标签来写事件,至于参数传递,请查看下面的弹窗专题。 ### [3.4.显示加载动画](https://www.easyweb.vip/doc/#/?id=_34%e6%98%be%e7%a4%ba%e5%8a%a0%e8%bd%bd%e5%8a%a8%e7%94%bb) **`showLoading`显示加载动画:** ~~~ admin.showLoading('#xxx'); // 在id为xxx的元素中显示加载层 admin.showLoading('#xxx', 1, '.8'); // 显示type为1透明度为0.8的遮罩层 ~~~ * 参数一`elem` 非必填 元素选择器,不填为body; * 参数二`type` 非必填 动画类型(1 小球,2 魔方,3信号),默认是1; * 参数三`opacity` 非必填 透明度(0 - 1),默认不透明;  目前增加了尺寸的控制,提供有两种尺寸,用法: ~~~ admin.showLoading({ elem: '#xxx', type: 1, size: 'sm' }); ~~~  默认是sm小型尺寸,还可以选md大型尺寸 **removeLoading`移除加载动画:** ~~~ admin.removeLoading('#xxx'); admin.removeLoading('#xxx', true, true); ~~~ * 参数一 非必填 元素选择器,不填为body; * 参数二 非必填 true是淡出效果,false直接隐藏,默认是true; * 参数三 非必填 true是删除,false是隐藏不删除,默认是false; **也可以写在body中作为页面载入的加载动画:** ~~~ <body> <!-- 小球样式 --> <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> <!-- 加sm是小型尺寸 --> <div class="page-loading"> <div class="signal-loader sm"> <span></span><span></span><span></span><span></span> </div> </div> </body> ~~~  写在页面中需要在js中调用`admin.removeLoading()`移除加载动画,不过common.js中已经写了。 ### [3.5.ajax封装](https://www.easyweb.vip/doc/#/?id=_35ajax%e5%b0%81%e8%a3%85) **`admin.req`是固定的写法,用法如下:** ~~~ admin.req('url',{ 参数一: 'xxx', 参数二: 'xxx' }, function(res){ alert(res.code + '-' + res.msg); }, 'get'); ~~~ * 参数一 请求的url * 参数二 请求参数 * 参数三 请求回调(失败也进此回调,404、403等) * 参数四 请求方式,get、post、put、delete等 **`admin.ajax`参数跟$.ajax参数一致,用法如下:** ~~~ admin.ajax({ url: 'url', data: {}, type: 'post', dataType: 'json', success: function(res){ alert(res.code + '-' + res.msg); } }); ~~~  admin.req和admin.ajax都实现了自动传递header、预处理、系统错误依然回调到success等功能。 **自动传递header:**  重写admin的`getAjaxHeaders`方法: ~~~ admin.getAjaxHeaders = function (requestUrl) { var headers = new Array(); headers.push({name: 'token', value: 'xxxxx'}); return headers; } ~~~ **请求回调预处理:**  重写admin的`ajaxSuccessBefore`方法: ~~~ admin.ajaxSuccessBefore = function (res, requestUrl) { if(res.code==401){ alert('登录超时,请重新登录'); return false; // 返回false阻止代码执行 } return true; } ~~~ > 重写的操作建议放在common.js里面,这样就不用每个页面都去重写了,只要保证重写是在调用req、ajax之前即可。 ### [3.6.ew-event事件绑定](https://www.easyweb.vip/doc/#/?id=_36ew-event%e4%ba%8b%e4%bb%b6%e7%bb%91%e5%ae%9a) 使用示例: ~~~ <a ew-event="fullScreen">全屏</a> <a ew-event="flexible">折叠导航</a> ~~~ | 事件 | 描述 | | :-- | :-- | | flexible | 折叠侧导航 | | refresh | 刷新主体部分 | | closeThisTabs | 关闭当前选项卡 | | closeOtherTabs | 关闭其他选项卡 | | closeAllTabs | 关闭全部选项卡 | | leftPage | 左滚动选项卡 | | rightPage | 右滚动选项卡 | | closeDialog | 关闭当前iframe弹窗 | | closePageDialog | 关闭当前页面层弹窗 | | theme | 打开主题设置弹窗 | | note | 打开便签弹窗 | | message | 打开消息弹窗 | | psw | 打开修改密码弹窗 | | logout | 退出登录 | | fullScreen | 全屏切换 | | back | 浏览器后退 | | open | 打开弹窗 | | popupRight | 打开右侧弹窗 | `theme`、`note`等可以通过`data-url`属性配置对应的url,还可以通过`data-window="top"`属性在父页面处理事件。 ~~~ <a ew-event="theme" data-url="xxx.html">主题</a> ~~~ `ew-event`属性可用于任何元素,不仅仅是a标签。 #### [3.6.1.open事件和popupRight](https://www.easyweb.vip/doc/#/?id=_361open%e4%ba%8b%e4%bb%b6%e5%92%8cpopupright)  这两个事件是用来支持非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> ~~~  layer支持的参数大部分都可以通过data属性来设置,数组类型用逗号分隔,function类型不支持。 ### [3.7.提示框](https://www.easyweb.vip/doc/#/?id=_37%e6%8f%90%e7%a4%ba%e6%a1%86) 鼠标滑过弹出tips,使用示例: ~~~ <button lay-tips="大家好!">按钮</button> <button lay-tips="大家好!" lay-direction="2" lay-bg="#009788">按钮</button> <button lay-tips="大家好!" lay-offset="10px">按钮</button> <button lay-tips="大家好!" lay-offset="10px,10px">按钮</button> ~~~ * `lay-direction`: 设置位置,1上面(默认);2右边;3下面;4 左边; * `lay-bg`: 设置背景颜色; * `lay-offset`: 设置偏移距离,(上下,左右) ![](https://s2.ax1x.com/2019/07/11/Z2BGmd.png) ### [3.8.chooseLocation地图选择位置](https://www.easyweb.vip/doc/#/?id=_38chooselocation%e5%9c%b0%e5%9b%be%e9%80%89%e6%8b%a9%e4%bd%8d%e7%bd%ae) ~~~ admin.chooseLocation({ needCity: true, onSelect: function (res) { layer.msg(JSON.stringify(res), {icon: 1}); } }); ~~~ | 参数 | 默认 | 描述 | | :-- | :-- | :-- | | title | "选择位置" | 弹窗标题 | | needCity | false | 是否返回行政区,省市区默认不返回 | | center | 定位当前城市 | 地图默认的中心点 | | defaultZoom | 11 | 地图默认缩放级别 | | pointZoom | 17 | 选中时地图的缩放级别 | | keywords | 无 | poi检索关键字,例如:建筑、写字楼 | | pageSize | 30 | poi检索最大数量 | | 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; // 城市代码 ![](https://s2.ax1x.com/2019/06/05/VUqpZD.png) ### [3.9.cropImg裁剪图片](https://www.easyweb.vip/doc/#/?id=_39cropimg%e8%a3%81%e5%89%aa%e5%9b%be%e7%89%87) ~~~ 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 | "裁剪图片" | 弹窗标题 | | aspectRatio | 1/1 | 裁剪比例,例如:16/9 | | imgSrc | 无 | 要裁剪的图片,无则先弹出选择图片 | | imgType | 'image/jpeg' | 裁剪的图片类型,非必填 | | onCrop | 无 | 裁剪完成回调 | | limitSize | 不限制 | 限制选择的图片大小 | | acceptMime | 'image/\*' | 限制选择的图片类型 | | exts | 不限制 | 限制选择的图片后缀 | * acceptMime参考值:'image/jpg, image/png'(只显示 jpg 和 png 文件) * exts参考值:jpg|png|gif|bmp|jpeg ![](https://s2.ax1x.com/2019/06/06/VUq2wD.png) * * * ## [4.admin.css介绍](https://www.easyweb.vip/doc/#/?id=_4admincss%e4%bb%8b%e7%bb%8d) ### [4.1.公共类](https://www.easyweb.vip/doc/#/?id=_41%e5%85%ac%e5%85%b1%e7%b1%bb) | 类名(class) | 说明 | | :-- | :-- | | pull-left | 左浮动 | | pull-right | 右浮动 | | text-left | 内容居左 | | text-center | 内容居中 | | text-right | 内容居右 | | inline-block | 设置display为inline-block | | bg-white | 设置背景为白色 | | layui-link | 设置a标签颜色为主题色 | | text-muted | 文字颜色为灰色 | | text-success | 文字颜色为绿色,成功色 | | text-warning | 文字颜色为黄色警告色 | | text-danger | 文字颜色为红色危险色 | | text-info | 文字颜色为蓝色信息色 | | text-primary | 文字颜色为主题色 | | layui-text | .layui-text下面的a标签为蓝色 | ~~~ <a href="xxx" class="layui-link">帐号注册</a> ~~~ ![](https://s2.ax1x.com/2019/07/06/ZwTuqJ.jpg) ~~~ <div class="layui-text"> <a href="xxx">xxx</a> <a href="xxx">xxx</a> </div> ~~~ ![](https://s2.ax1x.com/2019/06/05/VUIQit.png) ### [4.2.组件样式](https://www.easyweb.vip/doc/#/?id=_42%e7%bb%84%e4%bb%b6%e6%a0%b7%e5%bc%8f) | 类名(class) | 说明 | | :-- | :-- | | icon-btn | 带图标的按钮,会缩小边距 | | date-icon | 在元素的右边加入日期的图标 | | search-icon | 在元素的右边加入搜索的图标 | | btn-circle | 圆形按钮,参见便签界面 | | layui-form-select-top | 控制下拉框上弹出,加载select父元素上 | | xm-select-nri | 多选下拉框去掉最后那个没用的图标,加在父元素上 | | mini-bar | 如果有滚动条,使用细的风格 | | arrow2 | 设置侧边栏小三角为箭头图标,加在layui-nav上 | | arrow3 | 设置侧边栏小三角为加减号图标,加在layui-nav上 | | close-footer | 关闭页脚,加`<body class="layui-layout-body close-footer">`上 | | table-tool-mini | 数据表格工具栏mini样式,加在table父元素上 | | hide-body-title | 全局隐藏单标签模式标题栏,加在body上 | ~~~ <!-- 图标按钮 --> <button class="layui-btn icon-btn"><i class="layui-icon">&#xe615;</i>搜索</button> <!-- 日期图标 --> <input class="layui-input date-icon" 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> <!-- 多选下拉框去掉最后那个没用的图标 --> <div class="xm-select-nri"> <select xm-select="xx">....</select> </div> ~~~ ![](https://s2.ax1x.com/2019/07/06/ZwHpAs.jpg)![](https://s2.ax1x.com/2019/07/06/ZwTtMD.jpg)![](https://s2.ax1x.com/2019/06/05/VUTm4I.png)![](https://s2.ax1x.com/2019/07/11/Z2UdEV.png) ### [4.3.表单弹窗](https://www.easyweb.vip/doc/#/?id=_43%e8%a1%a8%e5%8d%95%e5%bc%b9%e7%aa%97) | 类名(class) | 说明 | | :-- | :-- | | model-form | 调整弹窗内的表单的间距使之更好看 | | model-form-body | 表单内容部分,高度自适应,超过屏幕高度显示滚动条 | | model-form-footer | 表单底部按钮部分,用于固定底部按钮 | 表单弹窗示例,添加用户: ~~~ <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="username" placeholder="请输入账号" type="text" class="layui-input" maxlength="20" 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 name="nickName" placeholder="请输入用户名" type="text" class="layui-input" maxlength="20" 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"> <label class="layui-form-label">角色</label> <div class="layui-input-block"> <select name="roleId" lay-verType="tips" lay-verify="required"> <option value="">请选择角色</option> <option value="1">管理员</option> <option value="2">普通用户</option> <option value="3">游客</option> </select> </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> admin.open({ type: 1, title: '添加用户', content: $('#modelUser').html(), success: function (layero, dIndex) { } }); </script> ~~~ ![](https://s2.ax1x.com/2019/06/05/VU7UdH.png) 固定底部操作按钮: ~~~ <script type="text/html" id="modelPtInfo"> <form id="modelFormPtInfo" lay-filter="modelFormPtInfo" class="layui-form model-form no-padding"> <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" placeholder="请输入实习公司" type="text" class="layui-input" lay-verType="tips" lay-verify="required" required/> </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="modelSubmitPtInfo" lay-submit>保存</button> </div> </form> </script> ~~~ ![](https://s2.ax1x.com/2019/06/05/VU7olV.png) ### [4.4.表格工具栏](https://www.easyweb.vip/doc/#/?id=_44%e8%a1%a8%e6%a0%bc%e5%b7%a5%e5%85%b7%e6%a0%8f) | 类名(class) | 说明 | | :-- | :-- | | toolbar | 调整表格上面的表单间距使之更好看 | | w-auto | 设置width:auto,用于重置一些有固定宽度表单元素 | | mr0 | 设置margin-right:0,用于重置一些表单元素的样式 | ~~~ <div class="layui-form toolbar"> <div class="layui-form-item"> <div class="layui-inline"> <label class="layui-form-label w-auto">账&emsp;号:</label> <div class="layui-input-inline mr0"> <input name="username" class="layui-input" type="text" placeholder="输入账号"/> </div> </div> <div class="layui-inline"> <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">&#xe615;</i>搜索 </button> <button id="btnAddUser" class="layui-btn icon-btn"><i class="layui-icon">&#xe654;</i>添加</button> </div> </div> </div> <table class="layui-table" id="tableUser" lay-filter="tableUser"></table> ~~~ ![](https://s2.ax1x.com/2019/06/05/VU7qw4.png) 移动端下自动适配样式: ![](https://s2.ax1x.com/2019/06/05/VUHAkd.png) * * * ## [5.主题功能](https://www.easyweb.vip/doc/#/?id=_5%e4%b8%bb%e9%a2%98%e5%8a%9f%e8%83%bd) 1. 使用[主题生成器](https://demo.easyweb.vip/theme/)生成个性化主题; 2. 将生成的css放在`assets/moudel/theme`目录下; 3. 打开`page/tpl/tpl-theme.html`添加生成的主题: ~~~ var themes = [ {title: '黑白主题', theme: 'admin'}, {title: '黑色主题', theme: 'black'}, {title: '你的主题', theme: 'xxx'} ]; ~~~ > 主题css以`theme-xxx.css`的形式命名,主题预览图跟主题css名字保持一致,预览图可在主题生成器中获取。 * * * ## [6.扩展插件](https://www.easyweb.vip/doc/#/?id=_6%e6%89%a9%e5%b1%95%e6%8f%92%e4%bb%b6) ### [6.1.鼠标右键](https://www.easyweb.vip/doc/#/?id=_61%e9%bc%a0%e6%a0%87%e5%8f%b3%e9%94%ae) 快速使用: ~~~ layui.use(['contextMenu'], function () { var contextMenu = layui.contextMenu; // 重写整个页面右键菜单 contextMenu.bind('html', [{ icon: 'layui-icon layui-icon-snowflake', name: '菜单一', click: function () { alert('点击了菜单一'); } }, { name: '菜单二', click: function () { alert('点击了菜单二'); } }]); }); ~~~ * 参数一: 绑定元素; * 参数二:菜单数组; **菜单数组结构:** ~~~ [{ icon: 'xxxxx', name: '菜单三', subs: [{ icon: 'xxxxx', name: '子菜单一', click: function () { alert('点击了子菜单一'); } }] }] ~~~ > `icon`:图标,`name`:菜单名,`click`:点击事件,`subs`:子菜单(支持无限极)。 **用于点击事件:**(使用`show`方法) ~~~ $('#btn').click(function (e) { var x = $(this).offset().left; var y = $(this).offset().top + $(this).outerHeight(); contextMenu.show([{ name: '按钮菜单一', click: function () { } }, { name: '按钮菜单二', click: function () { } }], x, y); e.preventDefault(); e.stopPropagation(); }); ~~~ * 参数一: 菜单数组; * 参数二三:xy坐标; ### [6.2.打印插件](https://www.easyweb.vip/doc/#/?id=_62%e6%89%93%e5%8d%b0%e6%8f%92%e4%bb%b6) **打印当前页面:** ~~~ printer.print(); printer.print({ hide: ['.layui-btn', '#btn01'], // 打印时隐藏的元素 horizontal: true, // 是否横向打印 blank: true, // 是否打开新页面打印 close: true, // 如果是打开新页面,打印完是否关闭 iePreview: true // 是否兼容ie打印预览 }); ~~~ > 参数都是可以选参数,默认值已经符合大多数需求。 **设置不打印的元素:** ~~~ <div class="hide-print">非打印内容</div> ~~~ > 加`hide-print`这个class即可,可以跟`hide`参数叠加使用。 **打印自定义内容:** ~~~ printer.printHtml({ html: '<span>xxxx</span>', // 要打印的内容 horizontal: true, // 是否横向打印 blank: true, // 是否打开新页面打印 close: true, // 如果是打开新页面,打印完是否关闭 iePreview: true, // 是否兼容ie打印预览 print: true // 如果是打开新窗口是否自动打印 }); ~~~  打印表格时可以给table加`print-table`这个class来设置表格的边框样式: 。 **分页打印:** ~~~ printer.printPage({ htmls: [ '<span>xxxx</span>', // 要打印的内容 '<span>xxxx</span>' ], style: '<style> span { color: red; } </style>', // 页面样式 horizontal: true, // 是否横向打印 padding: undefined, // 页面间距,例如写'10px' debug: false, // 调试模式 blank: true, // 是否打开新页面打印 close: true, // 如果是打开新页面,打印完是否关闭 iePreview: true, // 是否兼容ie打印预览 print: true // 如果是打开新窗口是否自动打印 }); ~~~ 参数都是可选参数: * htmls 数组,代表每一页; * style 样式,也可以写`<link rel="stylesheet">`的形式; * padding 间距,undefined表示使用打印机默认间距,如果自定义间距,打印机间距要选择无; * debug 调试模式,每一页会加红色边框,便于调试大小; > `padding`为undefined表示使用打印机默认间距,插件内部会根据不同浏览器做兼容处理,因为不同浏览器的默认间距不同, 目前对谷歌、IE、Edge、火狐做了兼容处理,safari、欧朋后续会考虑。 **makeHtml()拼接html:** ~~~ var htmlStr = printer.makeHtml({ title: '网页标题', style: '<link rel="stylesheet" href="layui.css"><script type="text/javascript" src="layui.js"><\/script>', body: $('#xxx').html() }); ~~~ **其他方法:** ~~~ printer.isIE(); printer.isEdge(); printer.isFirefox(); ~~~ **打印任意url:** 目前没有提供直接的方法,可以使用ajax请求到url的html内容,在使用printHtml方法打印: ~~~ $.ajax({ url: 'xxx.html', type: 'get', dataType: 'html', success: function (res) { printer.printHtml({ html: res, // 要打印的内容 horizontal: true // 是否横向打印 }); } }); ~~~ > 另外js直接控制横向打印只支持谷歌内核的浏览器,火狐不支持js调用打印预览, 火狐打印预览可以通过设置`blank:true,print:false`然后手动选择打印预览。 ### [6.3.tableX表格扩展](https://www.easyweb.vip/doc/#/?id=_63tablex%e8%a1%a8%e6%a0%bc%e6%89%a9%e5%b1%95) | 方法 | 参数 | 描述 | | :-- | :-- | :-- | | merges(tableId, indexs, fields) | 见单独说明 | 合并单元格 | | bindCtxMenu(tableId, items) | 见单独说明 | 给表格行绑定鼠标右键 | | render(object) | 同layui表格 | 渲染表格,带后端排序功能 | | renderFront(object) | 同layui表格 | 渲染表格,带前端分页、排序、模糊搜索、刷新功能 | | exportData(object) | 见单独说明 | 导出任意数据为excel | | loadUrl(object, callback) | 见单独说明 | 请求表格数据 | | parseTbData(cols, dataList, overwrite) | 见单独说明 | 获取解析templet后数据 | | filterData(dataList, searchName, searchValue) | 见单独说明 | 前端搜索数据 | | deepClone(object) | 任意对象 | 深度克隆对象 | #### [6.3.1.merges合并单元格](https://www.easyweb.vip/doc/#/?id=_631merges%e5%90%88%e5%b9%b6%e5%8d%95%e5%85%83%e6%a0%bc) ~~~ layui.use(['tableX'], function () { var tableX = layui.tableX; table.render({ elem: '#xTable2', url: '../../json/tablex1.json', cols: [[ {type: 'numbers'}, {field: 'parentName', title: '模块名称', sort: true}, {field: 'authorityName', title: '菜单名称', sort: true} ]], done: function () { tableX.merges('xTable2', [1]); // 在done回调里面调用 } }); }); ~~~ 使用方法: ~~~ 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内容判断 #### [6.3.2.bindCtxMenu行绑定鼠标右键](https://www.easyweb.vip/doc/#/?id=_632bindctxmenu%e8%a1%8c%e7%bb%91%e5%ae%9a%e9%bc%a0%e6%a0%87%e5%8f%b3%e9%94%ae) ~~~ table.render({ elem: '#xTable3', url: '../../json/user.json', cols: [[ {field: 'nickName', title: '用户名', sort: true}, {field: 'sex', title: '性别', sort: true} ]], done: function () { // 在done回调里面绑定 tableX.bindCtxMenu('xTable3', [{ icon: 'layui-icon layui-icon-edit', name: '修改此用户', click: function (d) { layer.msg('点击了修改,userId:' + d.userId); } }, { icon: 'layui-icon layui-icon-close text-danger', name: '<span class="text-danger">删除此用户</span>', click: function (d) { layer.msg('点击了删除,userId:' + d.userId); } }]); } }); ~~~ * 参数一   表格的lay-filter * 参数二   右键菜单 * icon     图标 * name   标题 * click     点击事件,d是当前行的数据 #### [6.3.3.render后端排序](https://www.easyweb.vip/doc/#/?id=_633render%e5%90%8e%e7%ab%af%e6%8e%92%e5%ba%8f) ~~~ 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     排序字段,值是点击排序列的field * order   排序方式,升序是asc,降序是desc > 注意:如果写了sort: true开启排序,一定要写field: 'xxx'。 #### [6.3.4.renderFront前端分页排序](https://www.easyweb.vip/doc/#/?id=_634renderfront%e5%89%8d%e7%ab%af%e5%88%86%e9%a1%b5%e6%8e%92%e5%ba%8f) ~~~ tableX.renderFront({ elem: '#xTable1', url: '../../json/userAll.json', page: { groups: 6 }, cols: [[ {type: 'checkbox'}, {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" type="text"/> ~~~  页面中加入上面的输入框,通过`tb-search`关联表格,就实现了对表格的模糊搜索功能,你可以对该input加任意样式,放在任意位置。  还可以增加name属性来设置搜索时只搜索某些字段,多个字段通过逗号分隔: ~~~ <input tb-search="xTable1" name="sex,phone" class="layui-input icon-search" type="text"/> ~~~ **刷新功能:** ~~~ <!-- 通过tb-refresh绑定刷新按钮 --> <button tb-refresh="xTable1" class="layui-btn">刷新</button> ~~~  也可以通过js刷新: ~~~ var insTb = tableX.renderFront('.....省略'); insTb.reloadUrl(); // url方式刷新 insTb.reloadData({data: dataList, page: {curr: 1}}); // data方式的刷新 ~~~ > 注意:url方式的前端分页使用reloadUrl()方法,reloadUrl()方法暂时不支持加参数,reloadData方法跟table.reload()方法参数一致。 **前端排序:**  前端排序如果有field字段,会根据field字段的值来排序,如果没有field有templet会根据templet转换后的值排序, templet可能会返回表单元素,比如switch开关等,这些元素根本无法用来排序,那么可以通过`export-show`和`export-hide`这两个东西来控制。 ~~~ <!-- 开关,state=0开关打开,state=1开关关闭 --> <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> <!-- 图标,state=0显示ok的图标,state=1显示叉叉的图标 --> <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-hide`用于表格展示,但是对排序和导出时屏蔽 * `export-show`用于排序和导出功能获取单元格数据,但是对表格展示时屏蔽 > 排序建议最好是通过field来根据数据的字段排序,field不支持d.xxx.xxx这种嵌套的对象,就需要用上面的方法 #### [6.3.5.exportData导出任意数据](https://www.easyweb.vip/doc/#/?id=_635exportdata%e5%af%bc%e5%87%ba%e4%bb%bb%e6%84%8f%e6%95%b0%e6%8d%ae) ~~~ tableX.exportData({ cols: insTb.config.cols, // 表头配置 data: table.cache.xTable3, // 数据,支持url方式 fileName: '用户表' // 文件名称 }); ~~~ | 参数 | 必填 | 说明 | 默认 | | :-- | :-- | :-- | :-- | | cols | 是 | 表头配置 | | | data | 是 | 导出的数据,支持数组和string的url | | | fileName | 否 | 导出的文件名称 | table | | expType | 否 | 导出的文件类型 | xls | | option | 否 | url方式的配置 | |  如果data是string类型会把data当url请求数据,option是请求的配置,跟表格的配置一样,配置method、where、headers等,接口返回的格式也要跟表格一样包含code、count、data等信息。  cols的配置也跟表格一样,是一个多维数组,可以通过`insTb3.config.cols`来获取表格的cols,也可以重写。 **导出的数据会包含templet转换:** ~~~ tableX.renderFront({ elem: '#xTable1', url: '../../json/userAll.json', page: { groups: 6 }, cols: [[ {type: 'checkbox'}, {field: 'nickName', title: '用户名', sort: true}, {field: 'sex', title: '性别', sort: true}, { title: '状态', templet: function (d) { var stateStr = ['正常', '冻结', '欠费']; return stateStr[d.state]; } } ]] }); ~~~  像上面这种state数据存的是0和1,但是显示是文字,导出数据会自动转成文字(layui2.5后自带的带出也包含此功能)。  如果列是表单元素,比如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> <script> layui.use(['tableX'], function () { var tableX = layui.tableX; tableX.render({ elem: '#xTable3', url: '../../json/user.json', cols: [[ {field: 'nickName', title: '用户名', sort: true}, {field: 'phone', title: '手机号', sort: true}, {field: 'state', templet: '#tableState', title: '状态', sort: true} ]] }); }); </script> ~~~  通过加一个`export-show`类可以保证里面的内容只作为导出的时候用,不作为表格展示,还可以加`export-hide`来设置导出的时候屏蔽的内容。 ~~~ <!-- 图标,state=0显示ok的图标,state=1显示叉叉的图标 --> <script type="text/html" id="tableState"> <div class="export-hide">{{d.state==0?'<i class="layui-icon">&#xe605;</i>':'<i class="layui-icon">&#x1006;</i>'}}</div> <div class="export-show">{{d.state==0?'正常':'锁定'}}</div> </script> <!-- 不可能把图标的unicode字符导出吧,那就写两份,一份用于表格展示,一份用于排序和导出功能 --> ~~~ * `export-hide`用于表格展示,但是对排序和导出时屏蔽 * `export-show`用于排序和导出功能获取单元格数据,但是对表格展示时屏蔽 ### [6.4.formX表单扩展](https://www.easyweb.vip/doc/#/?id=_64formx%e8%a1%a8%e5%8d%95%e6%89%a9%e5%b1%95) 后续推出... ### [6.5.树形表格](https://www.easyweb.vip/doc/#/?id=_65%e6%a0%91%e5%bd%a2%e8%a1%a8%e6%a0%bc) [前往码云查看](https://gitee.com/whvse/treetable-lay) ### [6.6.下拉菜单](https://www.easyweb.vip/doc/#/?id=_66%e4%b8%8b%e6%8b%89%e8%8f%9c%e5%8d%95) 快速使用: ~~~ <!-- click模式触发 --> <div class="dropdown-menu"> <button class="layui-btn icon-btn"> &nbsp;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"> &nbsp;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> ~~~ ![](https://s2.ax1x.com/2019/06/06/VUL0HS.png) 更多样式: ~~~ <!-- 标题及禁用样式 --> <div class="dropdown-menu dropdown-hover"> <button class="layui-btn icon-btn"> &nbsp;更多样式 <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"> &nbsp;带小三角 <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"> &nbsp;暗色主题 <i class="layui-icon layui-icon-drop"></i></button> <ul class="dropdown-menu-nav 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> ~~~ ![](https://s2.ax1x.com/2019/06/06/VULshj.png)![](https://s2.ax1x.com/2019/06/06/VUL69s.png)![](https://s2.ax1x.com/2019/06/06/VULc3n.png) 对任意元素都可以绑定,不一定是按钮: ~~~ <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> ~~~ ![](https://s2.ax1x.com/2019/06/06/VULWuV.png) 带遮罩层,遮罩层是分离式的绑定,通过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> ~~~ ![](https://s2.ax1x.com/2019/06/06/VULfBT.png) 自定义下拉里面的内容: ~~~ <div class="dropdown-menu"> <button class="layui-btn layui-btn-normal icon-btn"> &nbsp;克隆/下载 <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> ~~~ ![](https://s2.ax1x.com/2019/06/06/VUL5EF.png) 控制显示方向,在dropdown-menu-nav上加dropdown-bottom-center等位置: | 类名 | 位置 | | :-- | :-- | | 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> ~~~ ![](https://s2.ax1x.com/2019/06/06/VULo4J.png) ### [6.7.消息通知](https://www.easyweb.vip/doc/#/?id=_67%e6%b6%88%e6%81%af%e9%80%9a%e7%9f%a5) ~~~ layui.use(['notice'], function(){ var notice = layui.notice; // 通知样式 notice.success({ title: '消息通知', message: '你有新的消息,请注意查收!' }); // 提示框样式,1成功、2失败、3警告、4加载、5信息(蓝色图标) notice.msg('Hello', {icon: 1}); }); ~~~ **方法:** | 方法 | 参数 | 说明 | | :-- | :-- | :-- | | success(object) | 见下方 | 成功消息(绿色) | | warning(object) | 见下方 | 警告消息(黄色) | | error(object) | 见下方 | 错误消息(红色) | | info(object) | 见下方 | 通知消息(蓝色) | | show(object) | 见下方 | 自定义样式 | | msg(string, object) | 内容,其他配置 | 提示框 | | destroy() | 无 | 关闭全部 | | hide(object, toast, closedBy) | 见下方 | 关闭指定的通知 | | settings(object) | 见下方 | 统一设置默认值 | **参数:** | 参数 | 说明 | 默认值 | 可选值 | | :-- | :-- | :-- | :-- | | title | 标题 | 无 | string类型 | | message | 内容 | 无 | string类型 | | position | 显示位置 | topRight | 见下方 | | transitionIn | 进入动画 | fadeInLeft | 见下方 | | transitionOut | 退出动画 | fadeOutRight | 见下方 | | timeout | 消失时间 | 5000 | 单位毫秒,false永不消失 | | progressBar | 进度条 | true | true显示、false不显示 | | balloon | 气泡效果 | false | true开启、false关闭 | | close | 关闭按钮 | true | true显示,false不显示 | | pauseOnHover | 鼠标滑过暂停消失时间 | true | true、false | | resetOnHover | 鼠标滑过重置消失时间 | false | true、false | | animateInside | 文字动画效果 | false | true开启、false关闭 | | className | 自定义class | 无 | 多个用空格分隔 | | theme | 主题 | light | light、dark | | audio | 音效 | 无 | 1,2,3,4,5,6 | | image | 显示图片 | 无 | 图片地址 | | imageWidth | 图片宽度 | 60 | 数字 | | buttons | 显示按钮 | \[\] | \[ \[ 'btn1', function(){} \], \['btn2', function(){} \] \] | | overlay | 遮罩层 | false | true显示,false不显示 | | drag | 滑动关闭 | true | true开启,false关闭 | | layout | 布局类型 | 2 | 1标题和内容并排,2两排显示 | | rtl | 布局方向 | false | false内容居左,true居右 | | displayMode | 显示模式 | 0 | 0无限制,1同类型存在不显示,2同类型存在先移除 | | targetFirst | 插入方式 | 自动 | true从上插入,false下插入,null自动 | | onOpened | 打开后回调函数 | 无 | function | | onClosed | 关闭后回调函数 | 无 | function | | titleColor | 标题颜色 | 默认 | 颜色单位 | | titleSize | 标题大小 | 默认 | 尺寸单位 | | messageColor | 文字颜色 | 默认 | 颜色单位 | | messageSize | 文字大小 | 默认 | 尺寸单位 | | backgroundColor | 背景颜色 | 默认 | 颜色单位 | | progressBarColor | 进度条颜色 | 默认 | 颜色单位 | | maxWidth | 最大宽度 | null | 尺寸单位 | **显示位置可选属性:** `bottomRight`、`bottomLeft`、`topRight`、`topLeft`、`topCenter`、`bottomCenter`、`center`。 **进入动画可选属性:** `bounceInLeft`,`bounceInRight`,`bounceInUp`,`bounceInDown`,`fadeIn`,`fadeInDown`,`fadeInUp`,`fadeInLeft`,`fadeInRight`,`flipInX`。 **退出动画可选属性:** `fadeOut`,`fadeOutUp`,`fadeOutDown`,`fadeOutLeft`,`fadeOutRight`,`flipOutX`。 **统一设置默认值:** ~~~ notice.settings({ timeout: 10000, transitionIn: 'flipInX', onOpen: function(){ console.log('callback abriu!'); } }); ~~~ **关闭指定的通知** ~~~ notice.hide({}, document.querySelector('.toast')); ~~~ * 参数一   重写一些参数,比如关闭动画等 * 参数二   根据自定义的className选择关闭的对象 ### [6.8.文件选择弹窗](https://www.easyweb.vip/doc/#/?id=_68%e6%96%87%e4%bb%b6%e9%80%89%e6%8b%a9%e5%bc%b9%e7%aa%97) 快速使用: ~~~ 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}); } }); }); ~~~ 参数: | 参数 | 描述 | 默认值 | | --- | --- | --- | | fileUrl | 文件查看的url | | | listUrl | 文件列表的url | | | where | 文件列表请求参数 | {} | | num | 文件选择的数量 | 1 | | onChoose | 选择后回调 | | | 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修改。  不同文件显示不同的图标是前端根据文件url的后缀名称来判断的,在之前版本是服务器根据文件的content-type判断的。 ![](https://s2.ax1x.com/2019/07/11/Z2dfpD.png) ### [6.9.标签输入框](https://www.easyweb.vip/doc/#/?id=_69%e6%a0%87%e7%ad%be%e8%be%93%e5%85%a5%e6%a1%86) 模块名:tagsInput,使用方法: ~~~ <input id="demoTagsInput" value="辣妹子,大长腿" class="layui-hide"/> <script> layui.use(['jquery', 'tagsInput'], function () { var $ = layui.jquery; // 输入框样式 $('#demoTagsInput').tagsInput(); // 无边框样式 $('#demoTagsInput').tagsInput({skin: 'tagsinput-default'}); // BackSpace键可删除标签 $('#demoTagsInput').tagsInput({removeWithBackspace: true}); // 输入列表提示 $('#demoTagsInput').tagsInput({ skin: 'tagsinput-default', autocomplete_url: '../../json/tagsInput.json' }); }); </script> ~~~  只需要写一个input框,调用tagsInput方法渲染即可,回显数据写在value中用逗号分隔。 参数说明: | 参数 | 说明 | 默认值 | | --- | --- | --- | | defaultText | 提示文字 | +请输入 | | skin | 样式风格 | | | removeWithBackspace | 回退键可删除已添加的标签 | false | | focusWithClick | 点击已添加标签输入框获取焦点 | true | | autocomplete\_url | 自动提示接口url | | | autocomplete | 接口配置 | | autocomplete参数: ~~~ $('#demoTagsInput').tagsInput({ autocomplete_url: '../../json/tagsInput.json', autocomplete: { type: 'post', data: { access_token: 'xxxxx' } } }); ~~~  type是请求方式,默认是get请求,data是额外参数,请求autocomplete\_url会传递`name`参数(输入框的值)。 ![](https://s2.ax1x.com/2019/07/11/Z26OyT.png) > 此插件基于[jQuery-Tags-Input](https://github.com/xoxco/jQuery-Tags-Input)二次修改。 ### [6.10.鼠标滚轮监听](https://www.easyweb.vip/doc/#/?id=_610%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9b%91%e5%90%ac) 模块名: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 可以得到浏览器实际的滚动距离。 > 此插件来源于[jquery-mousewheel](https://github.com/jquery/jquery-mousewheel)。 ### [6.11.二维码模块](https://www.easyweb.vip/doc/#/?id=_611%e4%ba%8c%e7%bb%b4%e7%a0%81%e6%a8%a1%e5%9d%97) 模块名:QRCode,使用方式: ~~~ <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> ~~~ > 此插件来源于[qrcodejs](https://github.com/davidshimjs/qrcodejs)。 ### [6.12.引导插件](https://www.easyweb.vip/doc/#/?id=_612%e5%bc%95%e5%af%bc%e6%8f%92%e4%bb%b6) 模块名:introJs,使用方式: ~~~ <p data-step="1" data-intro="这是步骤一">步骤一</p> <p data-step="2" data-intro="这是步骤二">步骤二</p> <script> layui.use(['introJs'], function () { var introJs = layui.introJs; // 初始化 introJs().start(); }); </script> ~~~ > 此插件基于[intro.js](https://github.com/usablica/intro.js)二次修改。 ### [6.13.剪贴板](https://www.easyweb.vip/doc/#/?id=_613%e5%89%aa%e8%b4%b4%e6%9d%bf) 模块名:ClipboardJS,使用方式: ~~~ <input id="foo" value="https://github.com/zenorocha/clipboard.js.git"> <button class="btn" data-clipboard-target="#foo">复制</button> <script> layui.use(['ClipboardJS'], function () { var ClipboardJS = layui.ClipboardJS; var clipboard = new ClipboardJS('.btn'); clipboard.on('success', function(e) { e.clearSelection(); }); clipboard.on('error', function(e) { console.error('Action:', e.action); }); }); </script> ~~~ > 此插件来源于[clipboard.js](https://zenorocha.github.io/clipboard.js)。 * * * ## [7.常见问题](https://www.easyweb.vip/doc/#/?id=_7%e5%b8%b8%e8%a7%81%e9%97%ae%e9%a2%98) ### [7.1 后台生成侧边栏](https://www.easyweb.vip/doc/#/?id=_71-%e5%90%8e%e5%8f%b0%e7%94%9f%e6%88%90%e4%be%a7%e8%be%b9%e6%a0%8f) 这里用java的一个模板引擎beetl的语法示例: ~~~ <ul class="layui-nav layui-nav-tree" lay-filter="admin-side-nav"> <% for(menu in menus) { %> <li class="layui-nav-item"> <a lay-href="${menu.menuUrl}"><i class="${menu.menuIcon}"></i>&emsp;<cite>${menu.menuName}</cite></a> <% if(menu.subMenus.~size>0) { %> <dl class="layui-nav-child"> <% for(subMenu in menu.subMenus) { %> <dd> <a lay-href="${subMenu.menuUrl}">${subMenu.menuName}</a> <% if(subMenu.subMenus.~size>0) { %> <dl class="layui-nav-child"> <% for(temp in subMenu.subMenus) { %> <dd><a lay-href="${temp.menuUrl}">${temp.menuName}</a></dd> <% } %> </dl> <% } %> </dd> <% } %> </dl> <% } %> </li> <% } %> </ul> ~~~ ### [7.2 ajax加载侧边栏](https://www.easyweb.vip/doc/#/?id=_72-ajax%e5%8a%a0%e8%bd%bd%e4%be%a7%e8%be%b9%e6%a0%8f) 演示地址:[side-ajax.html](https://demo.easyweb.vip/iframe/page/template/side-ajax.html) ~~~ <div class="layui-side"> <div class="layui-side-scroll"> <ul class="layui-nav layui-nav-tree" lay-filter="admin-side-nav"></ul> </div> </div> <script id="sideNav" type="text/html"> {{# layui.each(d, function(index, item){ }} <li class="layui-nav-item"> <a lay-href="{{item.url}}"><i class="{{item.icon}}"></i>&emsp;<cite>{{item.name }}</cite></a> {{# if(item.subMenus&&item.subMenus.length>0){ }} <dl class="layui-nav-child"> {{# layui.each(item.subMenus, function(index, subItem){ }} <dd> <a lay-href="{{ subItem.url }}">{{ subItem.name }}</a> {{# if(subItem.subMenus&&subItem.subMenus.length>0){ }} <dl class="layui-nav-child"> {{# layui.each(subItem.subMenus, function(index, thrItem){ }} <dd><a lay-href="{{ thrItem.url }}">{{ thrItem.name }}</a></dd> {{# }); }} </dl> {{# } }} </dd> {{# }); }} </dl> {{# } }} </li> {{# }); }} </script> <script> layui.use([ 'element', 'admin','laytpl'], function () { var $ = layui.jquery; var admin = layui.admin; var laytpl = layui.laytpl; var element = layui.element; $.get('json/side.json', function (res) { laytpl(sideNav.innerHTML).render(res.data, function (html) { $('*[lay-filter=admin-side-nav]').html(html); element.render('nav'); // 这里非常重要 }); }, 'json'); }); </script> ~~~ json数据格式: ~~~ { "code": 200, "msg": "", "data": [{ "name": "系统管理", "icon": "layui-icon layui-icon-set", "url": "javascript:;", "subMenus": [ { "name": "用户管理", "url": "system/user.html" } ] } ] } ~~~ ### [7.3 多系统模式](https://www.easyweb.vip/doc/#/?id=_73-%e5%a4%9a%e7%b3%bb%e7%bb%9f%e6%a8%a1%e5%bc%8f)   在header中有几个选项:“xx系统”、“xx系统”,点击不同的系统切换不同的侧边菜单,在线演示:[side-more.html](https://demo.easyweb.vip/iframe/page/template/side-more.html) 侧边栏代码,使用`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> ~~~ ### [7.4 弹窗下拉框出现滚动条](https://www.easyweb.vip/doc/#/?id=_74-%e5%bc%b9%e7%aa%97%e4%b8%8b%e6%8b%89%e6%a1%86%e5%87%ba%e7%8e%b0%e6%bb%9a%e5%8a%a8%e6%9d%a1) 非iframe类型的弹窗才能解决,解决办法如下: ~~~ admin.open({ title: '添加用户', content: $('#model').html(), success: function (layero, index) { // 禁止出现滚动条 $(layero).children('.layui-layer-content').css('overflow', 'visible'); } }); ~~~ > 关键代码就是在success回调中写上面那句话 ### [7.5 弹窗宽度不能超出屏幕](https://www.easyweb.vip/doc/#/?id=_75-%e5%bc%b9%e7%aa%97%e5%ae%bd%e5%ba%a6%e4%b8%8d%e8%83%bd%e8%b6%85%e5%87%ba%e5%b1%8f%e5%b9%95)  这个是针对手机屏幕下做了让弹窗宽度自适应,如果你需要让弹窗宽度超出屏幕如下代码即可: ~~~ admin.open({ title: '添加用户', content: $('#model').html(), success: function (layero, index) { $(layero).css('max-width', 'unset'); // 去掉max-width属性 } }); ~~~ > success回调中去掉max-width属性 ### [7.6 表单文字出现换行](https://www.easyweb.vip/doc/#/?id=_76-%e8%a1%a8%e5%8d%95%e6%96%87%e5%ad%97%e5%87%ba%e7%8e%b0%e6%8d%a2%e8%a1%8c)  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> ~~~ ### [7.7 侧边栏折叠图标放大](https://www.easyweb.vip/doc/#/?id=_77-%e4%be%a7%e8%be%b9%e6%a0%8f%e6%8a%98%e5%8f%a0%e5%9b%be%e6%a0%87%e6%94%be%e5%a4%a7)  侧边栏折叠后图标会进行放大,如果要修改大小,添加如下css: ~~~ @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; } } ~~~  修改font-size即可,如果不想放大,改成14px即可。 ## [8.表单弹窗专题](https://www.easyweb.vip/doc/#/?id=_8%e8%a1%a8%e5%8d%95%e5%bc%b9%e7%aa%97%e4%b8%93%e9%a2%98)   layui没有像bootstrap那样的直接写在页面中的模态弹窗,layui的弹窗是通过layer模块用js去弹出窗口, 这就意味着layui的弹窗功能更丰富、操作更灵活,当然灵活也就意味着对于新手来说使用更为复杂, easyweb为了方便大家使用弹窗,也下了大量的功夫来封装layer,下面来介绍在easyweb中使用弹窗的几种方式。 ### [8.1.第一种 页面层弹窗](https://www.easyweb.vip/doc/#/?id=_81%e7%ac%ac%e4%b8%80%e7%a7%8d-%e9%a1%b5%e9%9d%a2%e5%b1%82%e5%bc%b9%e7%aa%97)  页面层弹窗就是弹窗页面和列表页面写在一起,弹窗类型type=1: ~~~ <button id="btnAddUser" class="layui-btn">添加</button> <table id="tableUser" lay-filter="tableUser"></table> <!-- 表单弹窗 --> <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" placeholder="请输入用户名" type="text" class="layui-input" maxlength="20" 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="closePageDialog">取消</button> <button class="layui-btn" lay-filter="modelSubmitUser" lay-submit>保存</button> </div> </form> </script> <!-- 表格操作列 --> <script type="text/html" id="tableBarUser"> <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> </script> <!-- js部分 --> <script> layui.use(['layer', 'form', 'table', 'admin'], function () { var $ = layui.jquery; var layer = layui.layer; var form = layui.form; var table = layui.table; var admin = layui.admin; // 渲染表格 var insTb = table.render({ elem: '#tableUser', url: '../../json/user.json', cols: [[ {type: 'numbers', title: '#'}, {field: 'nickName', sort: true, title: '用户名'}, {field: 'sex', sort: true, title: '性别'}, {align: 'center', toolbar: '#tableBarUser', title: '操作', minWidth: 200} ]] }); // 添加 $('#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(), 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> ~~~  弹窗的参数`type: 1`表示弹窗类型是页面层类型而不是iframe层类型,`content: $("#modelUser").html()`是指定弹窗的内容, 表单使用`<script type="text/html">`而不是使用div,这样表单页面不会直接显示在列表下面,需要注意的是,操作表单的代码, 包括表单的事件监听都要写在弹窗的`success`回调里面,因为layer弹窗是把表单的html**复制一份**动态插入到页面上,而不是把那一段代码变成模态窗, 所以事件绑定必须写在success里面。 > 这种方式表单和表格在一个页面上面,数据传递、页面相互操作比较方便,不涉及到iframe父子传值的问题,推荐新手使用这种方式 ### [8.2.第二种 iframe层弹窗](https://www.easyweb.vip/doc/#/?id=_82%e7%ac%ac%e4%ba%8c%e7%a7%8d-iframe%e5%b1%82%e5%bc%b9%e7%aa%97)  使用iframe类型的弹窗可以让表单页面和表格页面分开,逻辑更清晰。 弹窗页面,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" placeholder="请输入用户名" type="text" class="layui-input" maxlength="20" 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="closePageDialog">取消</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'], function () { var $ = layui.jquery; var layer = layui.layer; var form = layui.form; var admin = layui.admin; var mUser = parent.mSelUser; // 获取列表页面传递的数据,也可以使用top.xxx // 回显数据 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}); parent.userFormIsOk = true; // 设置操作成功的标识,也可以使用top.xxx admin.closeThisDialog(); // 关闭当前iframe弹窗 } else { layer.msg(res.msg, {icon: 2}); } }, 'json'); return false; }); }); </script> </body> </html> ~~~ 表格页面,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 layui-btn-primary layui-btn-xs" lay-event="edit">修改</a> <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a> </script> <!-- js部分 --> <script> layui.use(['layer', 'table', 'admin'], function () { var $ = layui.jquery; var layer = layui.layer; var table = layui.table; var admin = layui.admin; // 渲染表格 var insTb = table.render({ elem: '#tableUser', url: '../../json/user.json', cols: [[ {type: 'numbers', title: '#'}, {field: 'nickName', sort: true, title: '用户名'}, {field: 'sex', sort: true, title: '性别'}, {align: 'center', toolbar: '#tableBarUser', title: '操作', minWidth: 200} ]] }); // 添加 $('#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) { window.mSelUser = mUser; // 传递数据到表单页面,也可以使用top.xxx window.userFormIsOk = false; // 重置表单操作成功标识,也可以使用top.xxx admin.open({ type: 2, title: (mUser ? '修改' : '添加') + '用户', content: 'userForm.html', end: function () { if (window.userFormIsOk) { // 判断表单操作成功标识,也可以使用top.xxx insTb.reload(); // 成功刷新表格 } } }); } }); </script> ~~~  弹窗参数`type: 2`就表示是一个iframe类型的弹窗,content参数写表单的页面url, 然后在end回调里面判断操作成功的标识然后刷新表格,注意是end而不是success,这样做的好处就是, 弹窗页面跟表格独立开了,大大减少了每个页面的代码量,将业务逻辑分开,坏处就是需要借助window和parent来做父子页面的参数传递, 还有一个坏处就是,如果页面有下拉框、日期选择控件等元素,它们的范围不能超出弹窗的范围,会导致弹窗出现滚动条,甚至不显示出来。  那么有没有办法既能让表单页面独立,又能让表单里面的下拉框、日期等组件能够超出弹窗的范围呢,请看第三种方式。  这里演示的是使用window和parent来传递参数,也可以使用admin.putTempData(key, value) 和admin.getTempData(key)来操作sessionStorage实现参数传递,如果你被window、parent、top这三个绕晕了,那就使用这个方法。 > 注意:如果你用top.layui.admin.open打开弹窗,那就不要用window和parent传递参数,全部使用top ### [8.3.第三种 url方式弹窗](https://www.easyweb.vip/doc/#/?id=_83%e7%ac%ac%e4%b8%89%e7%a7%8d-url%e6%96%b9%e5%bc%8f%e5%bc%b9%e7%aa%97)  url方式弹窗就是使用url参数将弹窗页面独立出来: 弹窗页面,userForm.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" placeholder="请输入用户名" type="text" class="layui-input" maxlength="20" 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="closePageDialog">取消</button> <button class="layui-btn" lay-filter="modelSubmitUser" lay-submit>保存</button> </div> </form> <script> layui.use(['layer', 'form', admin'], function () { var $ = layui.jquery; var layer = layui.layer; var form = layui.form; var admin = layui.admin; var mUser = window.mSelUser; // 列表页面传递的数据,也可以使用top.xxx // 回显数据 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}); window.userFormIsOk = true; // 设置操作成功的标识,也可以使用top.xxx admin.closeDialog('#modelUserForm'); // 关闭页面层弹窗 } else { layer.msg(res.msg, {icon: 2}); } }, 'json'); return false; }); }); </script> ~~~  注意这里,页面不需要写`<html><body>`这些东西,它是一个html片段,不是完整的html页面。 表格页面,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 layui-btn-primary layui-btn-xs" lay-event="edit">修改</a> <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a> </script> <!-- js部分 --> <script> layui.use(['layer', table', 'admin'], function () { var $ = layui.jquery; var layer = layui.layer; var table = layui.table; var admin = layui.admin; // 渲染表格 var insTb = table.render({ elem: '#tableUser', url: '../../json/user.json', cols: [[ {type: 'numbers', title: '#'}, {field: 'nickName', sort: true, title: '用户名'}, {field: 'sex', sort: true, title: '性别'}, {align: 'center', toolbar: '#tableBarUser', title: '操作', minWidth: 200} ]] }); // 添加 $('#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) { window.mSelUser = mUser; // 传递数据到表单页面,也可以使用top.xxx window.userFormIsOk = false; // 重置表单操作成功标识,也可以使用top.xxx admin.open({ title: (mUser ? '修改' : '添加') + '用户', url: 'userForm.html', end: function () { if (window.userFormIsOk) { // 判断表单操作成功标识,也可以使用top.xxx insTb.reload(); } }, success: function (layero, dIndex) { // 弹窗超出范围不出现滚动条 $(layero).children('.layui-layer-content').css('overflow', 'visible'); } }); } }); </script> ~~~  这里与iframe弹窗的区别是,使用`url`参数指定表单的页面链接,而不是使用content,url这个参数是admin.open扩展的,layer不具备, 这样做会把表单页面的html内容使用ajax加载到弹窗中,而不是iframe嵌入,这样表单里面的下拉框、日期等组件就可以超出弹窗的范围,不会导致弹窗出现滚动条。  需要注意的是,参数传递不是widnow和parent,而是全部是window,因为表单页面和列表页面虽然是两个页面,但是是通过ajax加载在一个页面上的 ,如果使用top.layui.admin.open打开弹窗那就全部使用top。 > 注意:表单页面是html片段,不是完整的html,这点不要忘记了,另外表单页面和表格页面不要出现重复的id,因为最终是在一个页面上 ### [8.4.三种方式选择指南](https://www.easyweb.vip/doc/#/?id=_84%e4%b8%89%e7%a7%8d%e6%96%b9%e5%bc%8f%e9%80%89%e6%8b%a9%e6%8c%87%e5%8d%97) | 方式 | 推荐 | 理由 | | :-- | :-- | :-- | | 第一种 | 建议新手使用这种 | 不涉及两个页面传值问题 | | 第二种 | 推荐表单跟表格无交互使用,比如详情 | iframe弹窗不建议做表单 | | 第三种 | 表单弹窗、页面有交互建议使用 | 页面传值方便,不存在问题 |  父子页面参数传递除了使用window、parent、top之外,还可以使用admin.putTempData(key, value) 和admin.getTempData(key)来操作sessionStorage实现参数传递,如果你被window、parent、top这三个绕晕了, 那就使用这个方法,这个方法是操作本地存储sessionStorage,从效率上来讲没有window和parent高效。 ### [8.5.admin.modelForm方法](https://www.easyweb.vip/doc/#/?id=_85adminmodelform%e6%96%b9%e6%b3%95)  此方法是把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" placeholder="请输入用户名" type="text" class="layui-input" maxlength="20" 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> </script> <!-- js部分 --> <script> layui.use(['layer', 'form', admin'], function () { var $ = layui.jquery; var layer = layui.layer; var form = layui.form; var 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和确定、关闭按钮,只需要写表单项。  这个方法的使用场景为你想要表单的按钮固定,只滚动表单内容部分,可以用这个操作, 当然以前那种表单弹窗的写法(就是自己写确定和取消按钮那种写法)也是支持固定按钮的, 前面css组件样式中有介绍。