FastAdmin 基本知识流程一栏
安装:出现登陆页无法显示:可能是php的gd2扩展未开启
FastAdmin 在 Nginx 中的配置
用的是AdminLTE后台模板require.js、less、Bower
调试错误:看runtime/log
FastAdmin 的上传代码在哪里?
一张图解析FastAdmin中的表格列表的功能
fastadmin的页面是如何生成的?
FastAdmin 如何隐藏操作栏中的“删除”按钮“?
笔记:FastAdmin 上传设置
如何修改 FastAdmin 弹窗大小?
FastAdmin 的 CRUD 不支持层级模型
fastadmin笔记,应该能解决大部分问题
一键生成数据表的crud 的记录会保存到fa_command表中
当在线命令行管理成功生成crud时生成的文件如下:如fa_tom
application/admin/contorller/Tom.php application/admin/model/Tom.php application/admin/validate/Tom.php application/admin/view/tom/index.html、edit.html、add.html application/admin/lang/zh-cn/tom.php /public/assets/js/backend/tom.js
如果是fa_demo_tom则会生成(_分隔成目录)
application/admin/contorller/demo/Tom.php application/admin/model/demo/Tom.php application/admin/validate/demo/Tom.php application/admin/view/demo/tom/index.html、edit.html、add.html application/admin/lang/zh-cn/demo/tom.php /public/assets/js/backend/demo/tom.js
生成菜单的记录会更新fa_auth_rule的数据 name不带方法的就是菜单显示的pidwei0是选项卡
一键生成的是层级目录的菜单,在后台展示时父级菜单会以目录名称显示,
如上面的contorller/demo/Tom.php 父菜单显示demo子菜单显示Tom ,我们必须在application/admin/lang/zh-cn.php中添加
'Demo'=>'案例','Tom'=>'案例1' 配置后菜单显示如上:
一键压缩打包(略)
在FastAdmin中如果修改了核心的JS或CSS文件,是需要重新压缩打包后在生产环境下才会生效。FastAdmin采用的是基于RequireJS
的r.js
进行JS和CSS文件的压缩打包,application/config.php
中app_debug
的值,当为true的时候是采用的无压缩的JS和CSS,当为false时采用的是压缩版的JS和CSS
多语言:
return[
'Home'=>'前台'
];
{:__('Home')}
的方式调用,而在PHP和JS中均可以使用__('Home')
的方式发起调用
如果我们需要跨模块引入其它模块的语言包,则可以在 控制器中使用loadlang方法来引入,如
$this->loadlang('模块名');
如果需要在JS中跨模块引入语言包,则需要修改Ajax.php
中的lang
这个方法
控制器
我们的控制器都必须继承自application/common/controller/Backend.php的\app\common\controller\Backend
这个基类
这个基类application/admin/library/traits/Backend.php里引入的 use \app\admin\library\traits\Backend;它有八个公共方法
index/add/edit/del/multi/recyclebin/destroy/restore/ import
查看、添加、编辑、删除、批量更新、回收站、真实删除、还原 导入
common/controller/Backend里还有好多属性:
/** * 无需登录的方法,同时也就不需要鉴权了 * @var array */ protected $noNeedLogin = []; /** * 无需鉴权的方法,但需要登录 * @var array */ protected $noNeedRight = []; /** * 布局模板 * @var string */ protected $layout = 'default'; /** * 权限控制类 * @var Auth */ protected $auth = null; /** * 快速搜索时执行查找的字段 */ protected $searchFields = 'id'; /** * 是否是关联查询 */ protected $relationSearch = false; /** * 是否开启数据限制 * 支持auth/personal * 表示按权限判断/仅限个人 * 默认为禁用,若启用请务必保证表中存在admin_id字段 */ protected $dataLimit = false; /** * 数据限制字段 */ protected $dataLimitField = 'admin_id'; /** * 是否开启Validate验证 */ protected $modelValidate = false; /** * 是否开启模型场景验证 */ protected $modelSceneValidate = false; /** * Multi方法可批量修改的字段 */ protected $multiFields = 'status'; 方法 /** * 加载语言文件 * @param string $name */ protected function loadlang($name) { } /** * 渲染配置信息 * @param mixed $name 键名或数组 * @param mixed $value 值 */ protected function assignconfig($name, $value = '') { } /** * 生成查询所需要的条件,排序方式 * @param mixed $searchfields 快速查询的字段 * @param boolean $relationSearch 是否关联查询 * @return array */ protected function buildparams($searchfields = null, $relationSearch = null) { } /** * 获取数据限制的管理员ID * 禁用数据限制时返回的是null * @return mixed */ protected function getDataLimitAdminIds() { } /** * Selectpage的实现方法 * * 当前方法只是一个比较通用的搜索匹配,请按需重载此方法来编写自己的搜索逻辑,$where按自己的需求写即可 * 这里示例了所有的参数,所以比较复杂,实现上自己实现只需简单的几行即可 * */ protected function selectpage() { }
当两张相似的表意见curd时一个没有关联模型查询一个有时的区别:
class Demo extends Backend { /** * Demo模型对象 * @var \app\admin\model\Demo */ protected $model = null; public function _initialize() { parent::_initialize(); $this->model = new \app\admin\model\Demo; } /** * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法 * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑 * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改 */ }
traits 的原idnex方法
trait Backend { /** * 查看 */ public function index() { //设置过滤方法 $this->request->filter(['strip_tags']); if ($this->request->isAjax()) { //如果发送的来源是Selectpage,则转发到Selectpage if ($this->request->request('keyField')) { return $this->selectpage(); } list($where, $sort, $order, $offset, $limit) = $this->buildparams(); $total = $this->model ->where($where) ->order($sort, $order) ->count(); $list = $this->model ->where($where) ->order($sort, $order) ->limit($offset, $limit) ->select(); $list = collection($list)->toArray(); $result = array("total" => $total, "rows" => $list); return json($result); } return $this->view->fetch(); } //...... }
有关联时的控制器:
class Dash extends Backend { /** * Dash模型对象 * @var \app\admin\model\Dash */ protected $model = null; public function _initialize() { parent::_initialize(); $this->model = new \app\admin\model\Dash; } /** * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法 * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑 * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改 */ /** * 查看 */ public function index() { //当前是否为关联查询 $this->relationSearch = true; //设置过滤方法 $this->request->filter(['strip_tags']); if ($this->request->isAjax()) { //如果发送的来源是Selectpage,则转发到Selectpage if ($this->request->request('keyField')) { return $this->selectpage(); } list($where, $sort, $order, $offset, $limit) = $this->buildparams(); $total = $this->model ->with(['category']) ->where($where) ->order($sort, $order) ->fetchSql(false) ->count(); $list = $this->model ->with(['category']) ->where($where) ->order($sort, $order) ->limit($offset, $limit) ->fetchSql(false) ->select(); //file_put_contents(__DIR__.'/../../../runtime/log/sql_'.time().'_log.txt', $total); //file_put_contents(__DIR__.'/../../../runtime/log/sql_'.time().'_log1.txt', $list); foreach ($list as $row) { } $list = collection($list)->toArray(); $result = array("total" => $total, "rows" => $list); return json($result); } return $this->view->fetch(); } }
无关联时的model
class Demo extends Model { // 表名 protected $name = 'demo'; // 自动写入时间戳字段 protected $autoWriteTimestamp = false; // 定义时间戳字段名 protected $createTime = false; protected $updateTime = false; // 追加属性 protected $append = [ ]; }
有关联时的model(多出了一个方法)
class Dash extends Model { // 表名 protected $name = 'dash'; // 自动写入时间戳字段 protected $autoWriteTimestamp = false; // 定义时间戳字段名 protected $createTime = false; protected $updateTime = false; // 追加属性 protected $append = [ ]; public function category() { return $this->belongsTo('Category', 'category_id', 'id', [], 'LEFT')->setEagerlyType(0); } }
js
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) { var Controller = { index: function () { // 初始化表格参数配置 Table.api.init({ extend: { index_url: 'demo/index', add_url: 'demo/add', edit_url: 'demo/edit', del_url: 'demo/del', multi_url: 'demo/multi', table: 'demo', } }); var table = $("#table"); // 初始化表格 table.bootstrapTable({ url: $.fn.bootstrapTable.defaults.extend.index_url, pk: 'id', sortName: 'id', columns: [ [ {checkbox: true}, {field: 'id', title: __('Id')}, {field: 'name', title: __('Name')}, {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} ] ] }); // 为表格绑定事件 Table.api.bindevent(table); }, add: function () { Controller.api.bindevent(); }, edit: function () { Controller.api.bindevent(); }, api: { bindevent: function () { Form.api.bindevent($("form[role=form]")); } } }; return Controller; });
关联后的js
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) { var Controller = { index: function () { // 初始化表格参数配置 Table.api.init({ extend: { index_url: 'dash/index', add_url: 'dash/add', edit_url: 'dash/edit', del_url: 'dash/del', multi_url: 'dash/multi', table: 'dash', } }); var table = $("#table"); // 初始化表格 table.bootstrapTable({ url: $.fn.bootstrapTable.defaults.extend.index_url, pk: 'id', sortName: 'id', columns: [ [ {checkbox: true}, {field: 'id', title: __('Id')}, {field: 'name', title: __('Name')}, {field: 'category_id', title: __('Category_id')}, {field: 'category.id', title: __('Category.id')}, {field: 'category.pid', title: __('Category.pid')}, {field: 'category.type', title: __('Category.type')}, {field: 'category.name', title: __('Category.name')}, {field: 'category.nickname', title: __('Category.nickname')}, {field: 'category.flag', title: __('Category.flag'), operate:'FIND_IN_SET', formatter: Table.api.formatter.label}, {field: 'category.image', title: __('Category.image'), formatter: Table.api.formatter.image}, {field: 'category.keywords', title: __('Category.keywords')}, {field: 'category.description', title: __('Category.description')}, {field: 'category.diyname', title: __('Category.diyname')}, {field: 'category.createtime', title: __('Category.createtime'), operate:'RANGE', addclass:'datetimerange', formatter: Table.api.formatter.datetime}, {field: 'category.updatetime', title: __('Category.updatetime'), operate:'RANGE', addclass:'datetimerange', formatter: Table.api.formatter.datetime}, {field: 'category.weigh', title: __('Category.weigh')}, {field: 'category.status', title: __('Category.status'), formatter: Table.api.formatter.status}, {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} ] ] }); // 为表格绑定事件 Table.api.bindevent(table); }, add: function () { Controller.api.bindevent(); }, edit: function () { Controller.api.bindevent(); }, api: { bindevent: function () { Form.api.bindevent($("form[role=form]")); } } }; return Controller; });
bootstraptable详细的参数
var table = $("#table"); // 初始化表格 table.bootstrapTable({ url: '/Home/GetDepartment', //请求后台的URL(*)用于从远程站点请求数据的URL method: 'get', //请求方式(*) toolbar: '#toolbar', //工具栏按钮用哪个容器 一个jQuery 选择器,指明自定义的 buttons toolbar。例如:#buttons-toolbar, .buttons-toolbar 或 DOM 节点 toolbarAlign:'left' //指示如何对齐自定义工具栏。可以使用'left','right' buttonsToolbar:'', //一个jQuery选择器,指示按钮工具栏,例如:#buttons-toolbar,.buttons-toolbar或DOM节点 buttonsAlign:'right', //指示如何对齐工具栏按钮。可以使用'left','right'。 buttonsClass:'secondary', //定义表按钮的Bootstrap类(在'btn-'之后添加) striped: true, //是否显示行间隔色 cache: false, //是否使用缓存,默认为true,所以一般情况下需要设置一下这个属性(*) pagination: true, //是否显示分页(*) 设置为true以在表格底部显示分页工具栏默认false sortable: true, //是否启用排序 列中也有此变量 sortName:'', //定义要排序的列 没定义默认都不排列,同sortOrder结合使用,sortOrder没写的话列默认递增(asc) sortOrder: "asc", //定义列排序顺序,只能是'asc'或'desc'。 sortStable: false, //如果你把此属性设为了true)我们将为此行添加'_position'属性 (别看错了,是sortStable,sortable在下面)设为true,则和sort部分一样,区别是:在排序过程中,如果存在相等的元素,则原来的顺序不会改变 queryParams: oTableInit.queryParams,//传递参数(*) sidePagination: "server", //分页方式:client客户端分页(默认),server服务端分页(*) silentSort:true,//设置为false以便对加载的消息数据进行排序。当sidePagination选项设置为“server”时,此选项有效。 pageNumber:1, //初始化加载第一页,默认第一页 pageSize: 10, //每页的记录行数(*) pageList: [10, 25, 50, 100], //可供选择的每页的行数(*) search: true, //是否显示表格搜索input,此搜索是客户端搜索,不会进服务端,所以,个人感觉意义不大 strictSearch: true, //启用严格搜索 showColumns: false, //是否显示所有的列 设置为true以显示列下拉列表(一个可以设置显示想要的列的下拉f按钮) showRefresh: true, //是否显示刷新按钮 默认false minimumCountColumns: 1, //最少允许的列数 要从列下拉列表中隐藏的最小列数 clickToSelect: true, //是否启用点击选中行 height: 500, //行高,如果没有设置height属性,表格自动根据记录条数觉得表格高度 idField:'', //表明哪个是字段是标识字段 uniqueId: "ID", //表明每一行的唯一标识字段,一般为主键列 showToggle:true, //是否显示详细视图和列表视图的切换按钮 cardView: false, //是否显示详细视图 设置为true以显示卡片视图表,例如mobile视图(卡片视图) detailView: false, //设置为true以显示detail 视图表(细节视图) locale:'zh-CN', height:800, //固定表格的高度 classes:'table table-bordered table-hover',//表的类名。可以使用'table','table-bordered','table-hover','table-striped','table-dark','table-sm'和'table-borderless'。默认情况下,表格是有界的。 theadClasses:'',// 表thead的类名 如使用.thead-light或.thead-dark使theads显示为浅灰色或深灰色。 rowStyle:function(row,index){},// 行样式格式化程序函数支持类或css rowAttributes:function(row,index){},// row属性formatter函数,支持所有自定义属性 undefinedText:'-',// 定义默认的未定义文本 sortClass:'',//已排序的td元素的类名 rememberOrder:false,//设置为true以记住每列的顺序 data:[],// 要加载的数据 [] or {} contentType:'application/json',//请求远程数据的contentType,例如:application/x-www-form-urlencoded。 dataType:'json',//您希望服务器返回的数据类型 totalField:'total',//Key in incoming json containing 'total' data. dataField:'rows',//名称写自己定义的每列的字段名,也就是key,通过key才能给某行的某列赋value原文:获取每行数据json内的key onlyInfoPagination:false,//设置为true以仅显示表中显示的数据量。它需要将分页表选项即pagination设置为true paginationLoop:true,//设置为true以启用分页连续循环模式 paginationHAlign:'right',//分页条水平方向的位置,默认right(最右),可选left totalRows:0,//该属性主要由分页服务器传递,易于使用 paginationDetailHAlign:'left',//如果解译的话太长,举个例子,paginationDetail就是“显示第 1 到第 8 条记录,总共 15 条记录 每页显示 8 条记录”,默认left(最左),可选right paginationVAlign:'bottom',//分页条垂直方向的位置,默认bottom(底部),可选top、both(顶部和底部均有分页条) paginationPreText:'<',//上一页的按钮符号 paginationNextText:'>',//下一页的按钮符号 paginationSuccessivelySize:5,//分页时会有<12345...80>这种格式而5则表示显示...左边的的页数 paginationPagesBySide:1,//...右边的最大连续页数如改为2则 <1 2 3 4....79 80> paginationUseIntermediate:false,//计算并显示中间页面以便快速访问 true 会将...替换为计算的中间页数42 searchOnEnterKey:false,// true时搜索方法将一直执行,直到按下Enter键(即按下回车键才进行搜索) trimOnSearch:true,//默认true,自动忽略空格 searchAlign:'right',//指定搜索输入框的方向。可以使用'left','right'。 searchTimeOut:500,//设置搜索触发超时 searchText:'',//设置搜索文本框的默认搜索值 showHeader:true,//设置为false以隐藏表头 showFooter:false,//设置为true以显示摘要页脚行(固定也交 比如显示总数什么的最合适) showPaginationSwitch:false,//设置为true以显示分页组件的切换按钮 showFullscreen:false,// 设置为true以显示全屏按钮 smartDisplay:true,//设置为true以巧妙地显示分页或卡片视图 escape:false,// 转义字符串以插入HTML,替换 &, <, >, “, `, 和 ‘字符 跳过插入HTML中的字符串,替换掉特殊字符 selectItemName:'btSelectItem',// 设置radio 或者 checkbox的字段名称 clickToSelect:false,//设置为true时 在点击列时可以选择checkbox或radio singleSelect:false,// 默认false,设为true则允许复选框仅选择一行(不能多选了?) checkboxHeader:true,//设置为false以隐藏标题行中的check-all复选框 即隐藏全选框 maintainSelected:false,// true时点击分页按钮或搜索按钮时,记住checkbox的选择项 设为true则保持被选的那一行的状态 icons:{//定义工具栏,分页和详细信息视图中使用的图标 paginationSwitchDown: 'fa-caret-square-down', paginationSwitchUp: 'fa-caret-square-up', refresh: 'fa-sync', toggleOff: 'fa-toggle-off', toggleOn: 'fa-toggle-on', columns: 'fa-th-list', detailOpen: 'fa-plus', detailClose: 'fa-minus', fullscreen: 'fa-arrows-alt' }, iconSize:'undefined',// 定义icon图表的尺寸大小html对应为data-icon-undefined (默认btn)、data-icon-lg 大按钮的尺寸(btn-lg)...; 这里的值依次为undefined => btnxs => btn-xssm => btn-smlg => btn-lg iconsPrefix:'fa',//定义图标集名称(FontAwesome的'glyphicon'或'fa')。默认情况下,'fa'用于Bootstrap v4 queryParamsType:'limit',//设置'limit'以使用RESTFul类型发送查询参数。 ajaxOptions:{},//提交ajax请求的其他选项。值列表:jQuery.ajax。 customSort:function(sortName,sortOrder,data){},//自定义排序功能(用来代替自带的排序功能),需要两个参数(可以参考前面): ajax:function(){},// 一种替换ajax调用的方法。应该实现与jQuery ajax方法相同的API queryParams: function(params) { // 请求远程数据时,您可以通过修改queryParams来发送其他参数 return params }, responseHandler:function(res) { //在加载远程数据之前,处理响应数据格式,参数对象包含 return res }, customSearch:function(data,text){// 执行自定义搜索功能替换内置搜索功能,需要两个参数 return data.filter(function (row) {return row.field.indexOf(text) > -1}) }, footerStyle:function(column){// 页脚样式格式化程序函数,只需一个参数 m默认{} return { css: { 'font-weight': 'normal' }, classes: 'my-class' } }, detailFormatter:function(index,row,element){//前提:detailView设为true,启用了显示detail view。- 用于格式化细节视图- 返回一个字符串,通过第三个参数element直接添加到细节视图的cell(某一格)中,其中,element为目标cell的jQuery element return ''; }, detailFilter:function(index,row){//当detailView设置为true时,每行启用扩展。返回true并且将启用该行以进行扩展,返回false并禁用该行的扩展。默认函数返回true以启用所有行的扩展。 return true }, ignoreClickToSelectOn:function(element){// 包含一个参数:element: 点击的元素。返回 true 是点击事件会被忽略,返回 false 将会自动选中。该选项只有在 clickToSelect 为 true 时才生效。 return $.inArray(element.tagName, ['A', 'BUTTON'] }, columns: [ {checkbox: false}, {radio: false}, { radio: false,//此列转成radio上面单独领出来是应为有字段显示就不需要它呀 checkbox: false,//此列转成checkbox 单独拎出来同上 field: 'operate', //设置data-field的值 title: __('Operate'),//设置data-field的值 table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate,//单元格格式函数 this上下文是当前列对象 formatter: function (value, row, index,field){}, titleTooltip:'列标题工具提示文本。此选项还支持标题HTML属性', class:'定义列的类名', rowspan:1,//指定单元格应占用的行数。 colspan:1,//指定单元格应占用的列数。 align:'center',//指定如何对齐列数据。可以使用'left','right','center'。 halign:'center',//指定如何对齐表头。可以使用'left','right','center'。 falign:'center',//指示如何对齐表格页脚。可以使用'left','right','center'。 valign:'middle',//指出如何对齐单元格数据。可以使用'top','middle','bottom' width:'10%',//列的宽度。如果未定义,宽度将自动扩展以适合其内容。格式'100px','10%',100,如果想表格保持列自适应并且尺寸太小,则可以忽略这项(通过类等使用min / max-width) sortable:false,//设置为true以允许列可以排序。 order:'asc',//默认排序顺序,只能是'asc'或'desc'。 visible:true,//设置为false以隐藏列项。 cardVisible:true,//设置为false以隐藏card 视图状态中的列项 switchable:true,//设置为false以禁用可切换的列项 clickToSelect:true,//设置为true时 在点击列时可以选择checkbox或radio footerFormatter:function(data){},//当前列对象函数该函数应返回一个字符串,其中包含要在页脚单元格中显示的文本 events::{},//使用格式化函数时的单元事件监听器 四个参数event,value,row,index; html可以这么用 <th .. data-events="operateEvent"> sorter:function(a,b,rowA,rowB){},//用于进行本地排序的自定义字段排序函数(第一个字段值,第二个字段值,第一行,第二行) sortName:'',//提供可自定义的排序名称,而不是标题中的默认排序名称或列的字段名称 cellStyle:function(value,row,index,field){},//单元格样式格式化函数 支持classs和css searchable:true,//设置为true以搜索此列的数据。 searchFormatter:true,//设置为true以搜索使用格式化数据 escape:false,//转义字符串以插入HTML,替换 &, <, >, “, `, and ‘ 字符。 showSelectTitle:false,//设置为true以使用'radio'或'singleSelect''复选框'选项显示列的标题。 } ] }); var operateEvents = { /* 'click .like' 是类名?*/ 'click .like': function (e, value, row, index) {} }
模态框
require.js
require.js作为基本的js来启动所有的js data-main属性指向了一个启动脚本加载过程的文件(一般和require文件同目录)
<script src="/assets/js/require.js" data-main="/assets/js/require-backend.js?v=1551577968"></script>
然后在 data-main指向的js文件中定义模板加载选项 注意data-main里定义加载的文件是异步的哦,如果用了require.js那么就不要在之外定义对require.js里加载的文件有依赖的js
require使用分两步; 基本的require例子
1、define()定义模块(必须返回个对象)
2、调用模块 require(function(){})
//全局配置 require.config({ // 根路径设置,paths下面全部都是根据baseUrl的路径去设置 baseUrl:'./js/',//显式的定义baseUrl;不显式定义的情况下默认是和require.js同一个目录如果定义了data-main则以data-main的路径(path以/开头、以.js结尾、含有https等协议时不会使用baseUrl?) paths:{//显式的映射哪些不是在baseUrl目录路径的文件 // 引入jQuery.js jquery:'plugin/jquery', // 引入bootstrap.js bootstrap:'plugin/bootstrap', //引入其他的js //custom:'cunstom' }, shim:{//为那些没有使用define()来声明依赖关系 想要实际加载指或者涉及的模块仍然需要一个常规的require、define调用,设置shim本身不会触发代码的加载 bootstrap:{ //deps定义依赖的,这里的bootstrap依赖jquery deps:["jquery"], exports:'该依赖没有加载成功输出这段'或者这里也可以是个函数 } }, //map 对于给定的模块前缀,使用一个不同的模块ID来加载该模块 该特性仅适用于那些调用了define()并将其注册为匿名模块的真正AMD模块脚本。并且,请在map配置中仅使用绝对模块ID,“../some/thing”之类的相对ID不能工作。 另外在map中支持“*”,意思是“对于所有的模块加载,使用本map配置”。如果还有更细化的map配置,会优先于“*”配置 //当“some/newmodule”调用了“require('foo')”,它将获取到foo1.2.js //而当“some/oldmodule”调用“`require('foo')”时它将获取到foo1.0.js。 //当调用其它时将获取到fool1.1.js foo1.0.js foo1.1.js foo1.2.js some/ newmodule.js oldmodule.js map: { '*': { 'foo': 'foo1.1' }, 'some/oldmodule': { 'foo': 'foo1.2' }, 'some/oldmodule': { 'foo': 'foo1.0' } } });
urlArgs:RequireJS获取资源时附加在URL后面的额外的query参数。作为浏览器或服务器未正确配置时的“cache bust”手段很有用。使用cache bust配置的一个示例:
urlArgs: "bust=" + (new Date()).getTime()
packages:从CommonJS包(package)中加载模块。参见从包中加载模块。
include:xx
paths:xx
shim:xx
baseUrl:xx
map:xx
waitSeconds:命名一个加载上下文。这允许require.js在同一页面上加载模块的多个版本,如果每个顶层require调用都指定了一个唯一的上下文字符串。想要正确地使用,请参考多版本支持一节
charset:xx
config:常常需要将配置信息传给一个模块。这些配置往往是application级别的信息,需要一个手段将它们向下传递给模块。在RequireJS中,基于requirejs.config()的config配置项来实现。要获取这些信息的模块可以加载特殊的依赖“module”,并调用module.config()
nodeIdCompat: 在放弃加载一个脚本之前等待的秒数。设为0禁用等待超时。默认为7秒。
context: 指定要加载的一个依赖数组。当将require设置为一个config object在加载require.js之前使用时很有用。一旦require.js被定义,这些依赖就已加载。使用deps就像调用require([]),但它在loader处理配置完毕之后就立即生效。它并不阻塞其他的require()调用,它仅是指定某些模块作为config块的一部分而异步加载的手段而已。
deps: 指定要加载的一个依赖数组。当将require设置为一个config object在加载require.js之前使用时很有用。一旦require.js被定义,这些依赖就已加载。使用deps就像调用require([]),但它在loader处理配置完毕之后就立即生效。它并不阻塞其他的require()调用,它仅是指定某些模块作为config块的一部分而异步加载的手段而已。
callback: 在deps加载完毕后执行的函数。当将require设置为一个config object在加载require.js之前使用时很有用,其作为配置的deps数组加载完毕后为require指定的函数。
enforceDefine: 如果设置为true,则当一个脚本不是通过define()定义且不具备可供检查的shim导出字串值时,就会抛出错误。参考在IE中捕获加载错误一节。
xhtml: 如果设置为true,则使用document.createElementNS()去创建script元素。
使用:
1、
require( ['jquery', 'bootstrap'], function ($, undefined) { } );
2、定义模块:具有作用域来避免全局名称空间污染
简单定义:
define({ color: "black", size: "unisize" });
函数式定义:
define(function () { //Do setup work here return { color: "black", size: "unisize" } });
存在依赖的函数式定义:
模块函数以参数"cart"及"inventory"使用这两个以"./cart"及"./inventory"名称指定的模块。在这两个模块加载完毕之前,模块函数不会被调用。
严重不鼓励模块定义全局变量。遵循此处的定义模式,可以使得同一模块的不同版本并存于同一个页面上(参见 高级用法 )。另外,函参的顺序应与依赖顺序保存一致。
返回的object定义了"my/shirt"模块。这种定义模式下,"my/shirt"不作为一个全局变量而存在。
// my/shirt.js现在有一些依赖项,cart和inventory // 假设他们与shirt.js在同一目录中的模块 define(["./cart", "./inventory"], function(cart, inventory) { //返回一个对象来定义"my/shirt"模块。 return { color: "blue", size: "large", addToCart: function() { inventory.decrement(this); cart.add(this); } } } );
将模块定义为一个函数
// foo/title.js中的模块定义。 它使用之前的my/cart 和my/inventory模块, //但由于foo/title.js与"my" 模块位于不同的目录中,因此它使用模块依赖项名称中的"my" 来查找它们。 //名称的"my" 部分可以映射到任何目录,但默认情况下,它被假定相邻"foo"目录。 define(["my/cart", "my/inventory"], function(cart, inventory) { //返回一个函数用来定义"foo/title". //它获取或者设置 window title. return function(title) { return title ? (window.title = title) : inventory.storeName + ' ' + cart.name; } } );
定义一个命名模块
这些常由优化工具生成。你也可以自己显式指定模块名称,但这使模块更不具备移植性——就是说若你将文件移动到其他目录下,你就得重命名。一般最好避免对模块硬编码,而是交给优化工具去生成。优化工具需要生成模块名以将多个模块打成一个包,加快到浏览器的载人速度。
//明确地定义 "foo/title"模块: define("foo/title", ["my/cart", "my/inventory"], function(cart, inventory) { //Define foo/title object in here. } );
当定义的模块依赖太多的模块时
如:
//如: define( ['dep1', 'dep2', 'dep3', 'dep4', 'dep5', 'dep6', 'dep7', 'dep8'], function(dep1, dep2, dep3, dep4, dep5, dep6, dep7, dep8){ ... } ); //可以简化成这样 define( function (require) { var dep1 = require('dep1'), dep2 = require('dep2'), dep3 = require('dep3'), dep4 = require('dep4'), dep5 = require('dep5'), dep6 = require('dep6'), dep7 = require('dep7'), dep8 = require('dep8'); ... } });
注意:
一个文件一个模块
为了能在define()内部使用require的调用可以将require作一个依赖注入到模块中
生成与相对于模块的url
实例:
文件:
<script src="./require.js" data-main="main.js" type="text/javascript" defer async="true"></script>
全局配置文件main.js:
/*全局配置*/ require.config({ baseUrl:'./', paths:{ layer:"plugin/layer", jquery:["https://cdn.bootcss.com/jquery/3.3.1/jquery","plugin/jquery"],//可配置多个地址第一个加载不上加载第二个 bootstrap:"https://cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min", custom1:"js/custom1.0", custom2:"js/custom1.2",//custom1.2.js math:"js/math",//math.js datatable:"datatable",//和baseUrl同一文件下无需在这指定都行(可省略) }, shim:{ 'datatable':{//这个键名为要是载入的目标文件的文件名,不能随便命名。 exports: '_' //exports的值为datatable.js提供的 对外接口的名称??不理解 在其他模块require引入时可以引用它 }, 'datatables':{ 'init':function(){ return{ sayHi: datatable,//键可以随便取名(定义数据的键),值必须和datatables.js里的变量名一致 sayHello: datatableDemo, sayname: name, sayLike: like, } }, 'deps':['jquery','bootstrap'],//设置的依赖只datatable在jquery和bootstrap加载完毕后才会加载 //如果木有init这些参数我们可以简化依赖设置 例如 'datatables':['jquery','bootstrap'] //z注意bootstrap是依赖jqury的所以下面必须填上'bootstrap':['jquery'], }, 'layui':{ }, 'bootstrap':['jquery'], } }); require(['math'], function (math){ //math:为math.js return回来的数据 {add: ƒ, mathAdd: ƒ, controller: {…}} console.log(math.add('1 ',1)); console.log(math.controller); });
模块文件math.js
//不依赖其他模块 //define(function (){ //define([],function (){ //依赖其他模块则第一个参数为数组值为依赖的模块(这里依赖jquey和layui还有datatable), //jqury和layui在main.js显式指定了位置,datatable.js没有在paths里没有指定那么他的路径会默认在baseUrl define(['jquery','layer','datatable','datatables'],function ($,layer,_,tables){ var mathAdd = function (x,y){ console.log(datatable);//这里得到datatable是undefined,非规范化的模块我们需要定义在shim中 console.log(_);//?? console.log(tables); return parseInt($.trim(x))+parseInt($.trim(y)); }; var updateData=function(){ return '需要的代码'; }; var controller={ sex:'男', params:{ id:'1', name:'tom', phone:13132613871 }, index:function(){ }, add:updateData, eidt:function(){ } }; return { add: mathAdd, mathAdd: mathAdd, controller:controller }; });
非规范化模块
datatable。js
var datatable={ showRow:function(index){ return idnex; } };
datatable。js
/*非规范的模块有许多变量对象等情况*/ var datatable={ showRow:function(index){ return idnex; } }; function datatableDemo(){ return 'demo'; } var name='tom'; var like=['sing','jump','drink'];
生成的模板 两表字段 id、name、category_id(关联的多的字段)
add.html
<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action=""> <div class="form-group"> <label class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label> <div class="col-xs-12 col-sm-8"> <input id="c-name" data-rule="required" class="form-control" name="row[name]" type="text"> </div> </div> <div class="form-group layer-footer"> <label class="control-label col-xs-12 col-sm-2"></label> <div class="col-xs-12 col-sm-8"> <button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button><!--确定--> <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button><!--重置--> </div> </div> </form>
index:
<div class="panel panel-default panel-intro"> {:build_heading()} <div class="panel-body"> <div id="myTabContent" class="tab-content"> <div class="tab-pane fade active in" id="one"> <div class="widget-body no-padding"> <div id="toolbar" class="toolbar"> <a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}" ><i class="fa fa-refresh"></i> </a> <a href="javascript:;" class="btn btn-success btn-add {:$auth->check('demo/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a> <a href="javascript:;" class="btn btn-success btn-edit btn-disabled disabled {:$auth->check('demo/edit')?'':'hide'}" title="{:__('Edit')}" ><i class="fa fa-pencil"></i> {:__('Edit')}</a> <a href="javascript:;" class="btn btn-danger btn-del btn-disabled disabled {:$auth->check('demo/del')?'':'hide'}" title="{:__('Delete')}" ><i class="fa fa-trash"></i> {:__('Delete')}</a> <a href="javascript:;" class="btn btn-danger btn-import {:$auth->check('demo/import')?'':'hide'}" title="{:__('Import')}" id="btn-import-file" data-url="ajax/upload" data-mimetype="csv,xls,xlsx" data-multiple="false"><i class="fa fa-upload"></i> {:__('Import')}</a> <div class="dropdown btn-group {:$auth->check('demo/multi')?'':'hide'}"> <a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> {:__('More')}</a> <ul class="dropdown-menu text-left" role="menu"> <li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=normal"><i class="fa fa-eye"></i> {:__('Set to normal')}</a></li> <li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=hidden"><i class="fa fa-eye-slash"></i> {:__('Set to hidden')}</a></li> </ul> </div> </div> <table id="table" class="table table-striped table-bordered table-hover table-nowrap" data-operate-edit="{:$auth->check('demo/edit')}" data-operate-del="{:$auth->check('demo/del')}" width="100%"> </table> </div> </div> </div> </div> </div>
edit.html
<form id="edit-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action=""> <div class="form-group"> <label class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label> <div class="col-xs-12 col-sm-8"> <input id="c-name" data-rule="required" class="form-control" name="row[name]" type="text" value="{$row.name}"> </div> </div> <div class="form-group layer-footer"> <label class="control-label col-xs-12 col-sm-2"></label> <div class="col-xs-12 col-sm-8"> <button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> </div> </div> </form>
关联后的模板
add
<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action=""> <div class="form-group"> <label class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label> <div class="col-xs-12 col-sm-8"> <input id="c-name" data-rule="required" class="form-control" name="row[name]" type="text"> </div> </div> <div class="form-group"> <label class="control-label col-xs-12 col-sm-2">{:__('Category_id')}:</label> <div class="col-xs-12 col-sm-8"> <input id="c-category_id" data-rule="required" data-source="category/selectpage" data-params='{"custom[type]":"dash"}' class="form-control selectpage" name="row[category_id]" type="text" value=""> </div> </div> <div class="form-group layer-footer"> <label class="control-label col-xs-12 col-sm-2"></label> <div class="col-xs-12 col-sm-8"> <button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> </div> </div> </form>
index:
<div class="panel panel-default panel-intro"> {:build_heading()} <div class="panel-body"> <div id="myTabContent" class="tab-content"> <div class="tab-pane fade active in" id="one"> <div class="widget-body no-padding"> <div id="toolbar" class="toolbar"> <a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}" ><i class="fa fa-refresh"></i> </a> <a href="javascript:;" class="btn btn-success btn-add {:$auth->check('dash/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a> <a href="javascript:;" class="btn btn-success btn-edit btn-disabled disabled {:$auth->check('dash/edit')?'':'hide'}" title="{:__('Edit')}" ><i class="fa fa-pencil"></i> {:__('Edit')}</a> <a href="javascript:;" class="btn btn-danger btn-del btn-disabled disabled {:$auth->check('dash/del')?'':'hide'}" title="{:__('Delete')}" ><i class="fa fa-trash"></i> {:__('Delete')}</a> <a href="javascript:;" class="btn btn-danger btn-import {:$auth->check('dash/import')?'':'hide'}" title="{:__('Import')}" id="btn-import-file" data-url="ajax/upload" data-mimetype="csv,xls,xlsx" data-multiple="false"><i class="fa fa-upload"></i> {:__('Import')}</a> <div class="dropdown btn-group {:$auth->check('dash/multi')?'':'hide'}"> <a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> {:__('More')}</a> <ul class="dropdown-menu text-left" role="menu"> <li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=normal"><i class="fa fa-eye"></i> {:__('Set to normal')}</a></li> <li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=hidden"><i class="fa fa-eye-slash"></i> {:__('Set to hidden')}</a></li> </ul> </div> </div> <table id="table" class="table table-striped table-bordered table-hover table-nowrap" data-operate-edit="{:$auth->check('dash/edit')}" data-operate-del="{:$auth->check('dash/del')}" width="100%"> </table> </div> </div> </div> </div> </div>
{:$auth->check('dash/add')?'':'hide'} 检查权限 无权限加hide类隐藏
edit.html
<form id="edit-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action=""> <div class="form-group"> <label class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label> <div class="col-xs-12 col-sm-8"> <input id="c-name" data-rule="required" class="form-control" name="row[name]" type="text" value="{$row.name}"> </div> </div> <div class="form-group"> <label class="control-label col-xs-12 col-sm-2">{:__('Category_id')}:</label> <div class="col-xs-12 col-sm-8"> <input id="c-category_id" data-rule="required" data-source="category/selectpage" data-params='{"custom[type]":"dash"}' class="form-control selectpage" name="row[category_id]" type="text" value="{$row.category_id}"> </div> </div> <div class="form-group layer-footer"> <label class="control-label col-xs-12 col-sm-2"></label> <div class="col-xs-12 col-sm-8"> <button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> </div> </div> </form>
新增输出下拉列表的数据:
在_initialize方法里分配查出来的管理组变量给模板
edit模板
<div class="form-group"> <label class="control-label col-xs-12 col-sm-2">{:__('Group')}:</label> <div class="col-xs-12 col-sm-8"> {:build_select('group[]', $groupdata, null, ['class'=>'form-control selectpicker', 'multiple'=>'', 'data-rule'=>'required'])} </div> </div>
模板的函数解析出来为:
echo build_select('group[]', $groupdata, null, ['class'=>'form-control selectpicker', 'multiple'=>'', 'data-rule'=>'required']);
调用该函数生成一个下拉列表的html(第一个参数是name值,第二个参数是数组或者,分隔的字符串)
<select class="form-control selectpicker" multiple="" name="group[]" tabindex="-98"> <option value="1"> 超级管理组</option> <option value="2"> ├ 二级管理组</option> <option value="3"> │ ├ 三级管理组</option> <option value="5"> │ └ 三级管理组2</option> <option value="4"> └ 二级管理组2</option> </select>
common.php
if (!function_exists('build_select')) { /** * 生成下拉列表 * @param string $name * @param mixed $options * @param mixed $selected * @param mixed $attr * @return string */ function build_select($name, $options, $selected = [], $attr = []) { $options = is_array($options) ? $options : explode(',', $options); $selected = is_array($selected) ? $selected : explode(',', $selected); return Form::select($name, $options, $selected, $attr); } }