開發管理後臺是每個開發人員都要熟悉的一個環節,做爲後端程序員,公司的全部機密數據都掌握在咱們手上,因此這個時候,若是不是公司的核心成員,是不能接觸到某些數據的,這個時候全部的工做都落到了咱們的手上,從PS到Linux都須要咱們親歷親爲,還好發現了layui這個前端框架,很大程度上減輕了咱們的壓力.
今天咱們先來學習一下layui
實現動態數據表,靜態數據表,以及表格的分頁,其中還涉及到動態刷新數據表,數據表工具欄使用,表單提交等功能,這個靜態分頁一樣適用在信息類網站,個人工做開發環境是debian
桌面版,因此全部的實驗也是在debian
基礎上測試javascript
業務邏輯我都寫到註釋裏面了,這樣你們也友好一些,避免一會看代碼,一會看說明容易分神php
前端代碼:css
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <title><?php echo $curTitle;?></title> <meta name="renderer" content="webkit"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="format-detection" content="telephone=no"> <link rel="stylesheet" href="static/css/layui.css" media="all"> <link rel="stylesheet" href="static/css/globals.css" media="all"> <script src="static/layui.js" charset="utf-8"></script> <!--引入自定義模塊全局配置文件--> <script src="static/global.js" charset="utf-8"></script> </head> <body class="layui-layout-body">
<?php $this->import("head"); ?> <div class="layui-fluid"> <blockquote class="layui-elem-quote">注意:爲保障訪問速度,查詢同時請配合時間範圍,默認顯示一天之內的記錄</blockquote> <br/> <div class="layui-form-item layui-form-pane"> <div class="layui-inline"> <label class="layui-form-label" style="width: 85px;">商戶號</label> <div class="layui-input-inline" style="width: 165px;"> <input type="text" name="merchant_no" autocomplete="off" class="layui-input"> </div> </div> <div class="layui-inline"> <label class="layui-form-label" style="width: 85px;">訂單號:</label> <div class="layui-input-inline" style="width: 165px;"> <input type="text" name="order_no" autocomplete="off" class="layui-input"> </div> </div> <div class="layui-inline"> <label class="layui-form-label" style="width: 95px;">發起時間</label> <div class="layui-input-inline" style="width: 165px;"> <input type="text" class="layui-input" name="start_time" id="test5" placeholder="yyyy-MM-dd HH:mm:ss"> </div> <div class="layui-form-mid">-</div> <div class="layui-input-inline" style="width: 165px;"> <input type="text" class="layui-input" name="end_time" id="test6" placeholder="yyyy-MM-dd HH:mm:ss"> </div> </div> <div class="layui-inline"> <button id="fuck-btn" class="layui-btn layui-btn-normal" data-type="reload"><i class="layui-icon"></i>查詢</button> <button id="reloadtable" class="layui-btn layui-btn-normal"><i class="layui-icon">ဂ</i>刷新數據</button> <button id="reloadpage" class="layui-btn layui-btn-normal"><i class="layui-icon">ဂ</i>刷新頁面</button> </div> </div> <table class="layui-hide" id="test"></table> </div> <script> // 加載須要用到的模塊,若是有使用到自定義模塊也在此加載 layui.use(['laydate','form','table'], function(){ // 初始化元素,若是有大量的元素操做能夠也引入和初始化element模塊 var table = layui.table; var form = layui.form; var laydate = layui.laydate; var $ = layui.$; // 定義時間選擇器 laydate.render({ elem:'#test5', type:'datetime' }); laydate.render({ elem:'#test6', type:'datetime' }); // 動態數據表渲染 table.render({ elem: '#test' /* 綁定表格容器id */ ,url:'index.php?c=orders&a=orderList' /* 獲取數據的後端API URL */ ,where:{getlist:'orderlist'} /* 這裏還能夠額外的傳參到後端 */ ,method: 'post' /* 使用什麼協議,默認的是GET */ ,cellMinWidth: 60 /* 最小單元格寬度 */ ,cols: [[ {field:'orderno', title: '訂單號',align: 'center',sort:true} ,{field:'username', title: '商戶號',align: 'center'} ,{field:'user_orderno', title: '商戶訂單號',align: 'center'} ,{field:'trace_time', title: '建立時間',align: 'center',sort:true,width:200} ,{field:'price', title: '交易金額',align: 'center',sort:true} ,{field:'fee', title: '手續費',align: 'center',sort:true,width:80} ,{field:'real_price', title: '結算金額',align: 'center',sort:true} ,{field:'pay_type', title: '支付類型', align: 'center'} ,{field:'pay_status', title: '訂單狀態',align: 'center',width:90} ,{field:'pay_time', title: '支付時間',align: 'center',sort:true,width:200} ,{field:'push_nums', title: '通知次數',align: 'center',width:90} ,{field:'notice_result', title: '通知支付結果',align: 'center'} ]] // 使用sort將自動爲咱們添加排序事件,徹底不用人工干預 ,page: true ,limit:10 ,id:'testReload' // 這裏就是重載的id }); // 數據表重載,這個是配合上面的表格一塊兒使用的 var active = { reload:function(){ table.reload('testReload',{ // 點擊查詢和刷新數據表會把如下參數傳到後端進行查找和分頁顯示 where:{ merchant_no:$("input[name='merchant_no']").val(), order_no: $("input[name='order_no']").val(), start_time:$("input[name='start_time']").val(), end_time:$("input[name='end_time']").val() } }); } }; form.render(); // 渲染表單 // 查找點擊時間,這裏的事件綁定建議使用on來綁定,由於元素都是後期渲染過的 $("#fuck-btn").click(function(){ var type = $(this).data('type'); active[type] ? active[type].call(this) : ''; }); $("#reloadtable").click(function(){ active.reload(); }); $("#reloadpage").click(function(){ location.reload(); }); }); </script> </body> </html>
後端php代碼html
// 訂單列表 public function orderList() { // 動態渲染前臺表格 $operating = $this->request->getPost('getlist', 'trim'); // 首次這裏不會執行,數據表開始渲染的時候纔會請求如下部分 if ('orderlist' === $operating) { // 進行分頁查詢 $page = $this->request->getPost('page', 'intval', 1); $limit = $this->request->getPost('limit', 'intval', 10); $start = ($page - 1) * $limit; // 若是有其餘條件查詢在這裏能夠帶上 $merchant_no = $this->request->getPost('merchant_no', 'trim', ''); $order_no = $this->request->getPost('order_no', 'trim', ''); $start_time = $this->request->getPost('start_time', 'trim', date("Y-m-d H:i:s", strtotime("-1 day"))); $end_time = $this->request->getPost('end_time', 'trim', date("Y-m-d H:i:s"), time()); // 獲取符合條件的記錄數量 if($GLOBALS['SESSION']['admin_group_id'] >1){ $merchant_no = $GLOBALS['SESSION']['admin_username']; } $order_nums = orders::getItemNums($merchant_no, $order_no, $start_time, $end_time); // 分頁進行查詢條件記錄 $order_list = orders::getItem($merchant_no, $order_no, $start_time, $end_time, $start, $limit); $datas = ['code' => 0, 'msg' => '']; // 將總的記錄條數傳給前臺進行渲染分頁 $datas['count'] = $order_nums; // 從新過濾一遍數據,不少沒有用到的不能所有發給試圖,尤爲是動態渲染的,很容易暴露,建議加工一下再傳 foreach ($order_list as $k => $v) { $order_list[$k]['orderno'] = $v['order_id']; $order_list[$k]['user_orderno'] = $v['order_no']; $order_list[$k]['username'] = $v['merchant_no']; $order_list[$k]['pay_type'] = ($v['pay_type'] == 1) ? "支付寶掃碼" : "微信掃碼"; $order_list[$k]['pay_status'] = ($v['callback_status'] > 0) ? "已支付" : "未支付"; $order_list[$k]['pay_time'] = $v['callback_time']; $order_list[$k]['notice_result'] = ($v['push_status'] > 0) ? "<span class=\"layui-badge layui-bg-blue\">已推送</span>" : "<span class=\"layui-badge layui-bg-gray\">未推送</span>"; } // 將數據經過json格式響應給前臺渲染 $datas['data'] = $order_list; echo json_encode($datas); safe_exit(); } // 首次先現實模板頁 self::$view->render('orders_orderlist'); }
數據格式請參照官方指導:數據接口格式,表格模塊
調試的時候能夠打開chrome
,firefox
的 console
和 network
進行查看,仔細研究分析前端
工具欄是指在行單元格內能夠操做對應的行,由於使用layui
的元素監聽,很容易就獲取到相應對應整行的數據.
好比獲取表單的數據,只須要監聽表單提交事件,直接就能夠一次獲取到全部的參數和值:java
<script> layui.use(['form','jquery'],function(){ let form = layui.form, $ = layui.$; form.on('submit(fuck-submit)', function(data){ if(data.field.password && data.field.password.length < 5){ layer.msg('密碼不能小於5位'); return false; } $.post('index.php?&a=adminEdit&op=update&uid='+data.field.uid,{ username:data.field.username, password:data.field.password, level:data.field.level, is_enabled:data.field.is_enabled }, function(responseText){ //console.log(responseText); if(responseText.errno === 8){ layer.msg(responseText.errstr,{icon:6}); return false; } else { layer.msg(responseText.errstr,{icon:5}); location.reload(); } },'json' ); return false; }); }); </script>
這裏是官方文檔的:jquery
form.on('submit(*)', function(data){ console.log(data.elem) //被執行事件的元素DOM對象,通常爲button對象 console.log(data.form) //被執行提交的form對象,通常在存在form標籤時纔會返回 console.log(data.field) //當前容器的所有表單字段,名值對形式:{name: value} return false; //阻止表單跳轉。若是須要表單跳轉,去掉這段便可。 });
咱們今天要操做的數據表也是要採用這種方式,首先咱們看看看怎樣生成和渲染出工具條:程序員
只須要在body部分插入一個容器,注意這裏的javascript
的type
是text/html
,這個是供layui
解析用的,在這裏的d也就是咱們在渲染表格的時候的數據,全部的字段的值均可以在這個d
裏面獲取到web
<table class="layui-hide" lay-filter="fucktest" id="test"></table> <script type="text/html" id="barDemo"> <a class="layui-btn layui-btn-xs" user_id="{{d.admin_id}}" lay-event="edit">編輯</a> </script>
// 這裏就是咱們渲染表格字段的地方,和上面的容器進行綁定,容器裏面能夠經過d.fixed來獲取到 {fixed: 'right', width:158,title:'操做', align:'center', toolbar: '#barDemo'}
而後咱們就能夠對工具條綁定事件了,這裏我只使用了編輯事件chrome
table.on('tool(fucktest)', function(obj){ //注:tool是工具條事件名,test是table原始容器的屬性 lay-filter="對應的值" var data = obj.data; //得到當前行數據 var layEvent = obj.event; //得到 lay-event 對應的值(也能夠是表頭的 event 參數對應的值) var tr = obj.tr; //得到當前行 tr 的DOM對象 if(layEvent === 'detail'){ //查看 //do somehing } else if(layEvent === 'del'){ //刪除 layer.confirm('真的刪除行麼', function(index){ obj.del(); //刪除對應行(tr)的DOM結構,並更新緩存 layer.close(index); //向服務端發送刪除指令 }); } else if(layEvent === 'edit'){ //編輯 // 開始根據用戶id來進行獲取用戶進入新窗口 var index = layer.open({ type: 2, title:'編輯管理員', area: ['700px', '560px'], maxmin: true, content: 'index.php?c=adminUser&a=editUser&uid='+data.admin_id }); layer.full(index); } })
這樣在點擊編輯以後就能激活對應的事件了,咱們這裏是打開新的一個全屏彈窗來修改管理員資料
在修改完成後,若是隻是單純的重載數據表可使用咱們前面使用的方式,若是是刷新頁面直接使用location.reload()
// 重載數據表 var active = { reload:function(){ var demoReload = $("#demoReload"); var dateReload = $("#dateReload"); table.reload('testReload',{ where:{ username:demoReload.val(), dates:dateReload.val() } }); } }; $("#fresh-btn").click(function(){active.reload();}); $("#fresh-page-btn").click(function(){location.reload();});
這裏是官方的例子 toolbar-綁定列工具條
toolbar 對應的模板,它能夠存放在頁面的任意位置:
<script type="text/html" id="barDemo"> <a class="layui-btn layui-btn-xs" lay-event="detail">查看</a> <a class="layui-btn layui-btn-xs" lay-event="edit">編輯</a> <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">刪除</a> <!-- 這裏一樣支持 laytpl 語法,如: --> {{# if(d.auth > 2){ }} <a class="layui-btn layui-btn-xs" lay-event="check">審覈</a> {{# } }} </script> 注意:屬性 lay-event="" 是模板的關鍵所在,值可隨意定義。
渲染工具條:
table.render({ cols: [[ {field:'id', title:'ID', width:100} ,{fixed: 'right', width:150, align:'center', toolbar: '#barDemo'} //這裏的toolbar值是模板元素的選擇器 ]] }); 等價於: <th lay-data="{field:'id', width:100}">ID</th> <th lay-data="{fixed: 'right', width:150, align:'center', toolbar: '#barDemo'}"></th>
工具條綁定事件:
//監聽工具條 table.on('tool(test)', function(obj){ //注:tool是工具條事件名,test是table原始容器的屬性 lay-filter="對應的值" var data = obj.data; //得到當前行數據 var layEvent = obj.event; //得到 lay-event 對應的值(也能夠是表頭的 event 參數對應的值) var tr = obj.tr; //得到當前行 tr 的DOM對象 if(layEvent === 'detail'){ //查看 //do somehing } else if(layEvent === 'del'){ //刪除 layer.confirm('真的刪除行麼', function(index){ obj.del(); //刪除對應行(tr)的DOM結構,並更新緩存 layer.close(index); //向服務端發送刪除指令 }); } else if(layEvent === 'edit'){ //編輯 //do something //同步更新緩存對應的值 obj.update({ username: '123' ,title: 'xxx' }); } });
更加詳細的介紹請仔細研讀官方文檔 layui table模塊
在不少時候在pc
端過多的使用動態渲染不是一個明智的選擇,好比稍微懂行的人都能看到你的API
和須要的param
,因此咱們仍是建議對安全要求比較高的程序上仍是使用靜態表格,經過模板引擎也好,仍是直接使用使用後端動態語言混合,用戶最終只能看到解析好的頁面,對程序保護也是頗有必要的,個人一個hacker
朋友在進行滲透的時候都是這樣進行鑽空子的
靜態表格我這裏直接是使用php
混合解析進行展現:
前端模板:
<?php $this->import('head');?> <body> <blockquote class="layui-elem-quote">注意:此處僅顯示部分日誌</blockquote> <table class="layui-table" lay-size="sm"> <colgroup> </colgroup> <thead> <tr> <th>日誌ID</th> <th>操做用戶</th> <th>操做</th> <th>控制器</th> <th>方法</th> <th>是否成功</th> <th>操做IP</th> <th>備註信息</th> <th>日期</th> </tr> </thead> <tbody> <?php foreach($log_list as $kk => $vv):?> <tr> <td><?php echo $vv['log_id'];?></td> <td><?php echo $vv['username'];?></td> <td><?php echo $vv['title'];?></td> <td><?php echo $vv['control'];?></td> <td><?php echo $vv['action'];?></td> <td><?php echo $vv['is_success'];?></td> <td><?php echo $vv['client_ip'];?></td> <td><?php echo $vv['remark'];?></td> <td><?php echo $vv['date'];?></td> </tr> <?php endforeach;?> </tbody> </table> <div id="test1"></div> <script src="js/layui/layui.js"></script> <script> layui.use('laypage', function(){ var laypage = layui.laypage; laypage.render({ elem: 'test1' //注意,這裏的 test1 是 ID,不用加 # 號 ,count: <?php echo $log_num;?> // 數據總數,從服務端獲得 ,curr: <?php echo $currpage;?> // 服務器端回傳當前頁 ,jump: function(obj, first){ //obj包含了當前分頁的全部參數,好比: console.log(obj.curr); //獲得當前頁,以便向服務端請求對應頁的數據。 console.log(obj.limit); //獲得每頁顯示的條數 //首次不執行,使用原始的curr,後面須要本身經過回傳來更新 var curr = obj.curr; if(!first){ location.href='index.php?&a=adminLogList&page='+obj.curr; } } }); }); </script> </body> <?php $this->import('foot');?>
這裏的原理很是簡單,主要利用的是layui
下的laypage
模塊,使用jump
來觸發事件
public function adminLogList() { // 接收當前頁,若是沒有收到默認是第一頁 $page = $this->request->getGet('page','intval',1); // 設置limit查找起始,DEFAULT_PER_PAGE爲全局變量,設置的是每頁顯示10條 $start = ($page-1)*DEFAULT_PER_PAGE; // 獲取總日誌數量 $adminlog_num = adminLogs::getItemsNumber(); // 分頁查找,其餘查詢條件暫時不傳 $admin_log_list = adminLogs::getItems('','','','','',$start); $log_list = array(); foreach($admin_log_list as $kk => $vv){ if($vv['admin_id'] > 0){ try{ $admins = admins::getItemById($vv['admin_id']); $log_list[$kk]['username'] = $admins['username']; } catch (exception2 $e){ logexception($e->format_stack_trace()); } } else { $log_list[$kk]['username'] = 'Tourists'; } $log_list[$kk]['log_id'] = $vv['log_id']; $log_list[$kk]['control'] = $vv['control']; $log_list[$kk]['action'] = $vv['action']; $log_list[$kk]['is_success'] = $vv['is_success']; $log_list[$kk]['client_ip'] = ip2location($vv['client_ip']); $log_list[$kk]['remark'] = $vv['remark']; $log_list[$kk]['date'] = $vv['date']; $log_list[$kk]['title'] = $vv['title']; unset($admin_log_list[$kk]); } self::$view->setVar('currpage',$page); self::$view->setVar('log_num',$adminlog_num); self::$view->setVar('log_list',$log_list); self::$view->render('default_addloglist'); }
最終效果,已經完成靜態分頁,此部分功能也適用於信息類網站: