easyui的datagrid的使用记录
datagrid是在 table的基础上变化而来的, 而不是在div的基础上来的。 从div来变成 datagrid,样式的设置还是是比较麻烦的。
dg=datagrid 的标题 来源于 columns 属性, 其内容 来源于 url属性。 关键是, 一定要设置这样的属性, 才能给你显示标题和内容, 否则即使你写了 tr等都不会显示
dg的url 最后输出的内容 必须是 json格式: 如果是php的, 则要用echo, 如果是 其他文件,就要用 json数据
最重要的是: dg的前端 和 后台 服务器之间的 通信 , 都是 通过 ajax的方式 来 实现的。 如果在 php中 有 sleep语句的话, 会看到 加载loading...等待的效果。 ajax提交动作 发生在 每次你在前台 点击 下一页等按钮的时候, 前台需要在ajax提交的时候, 向后台服务器 传送数据; 后台需要 返回 json格式的 数据 给 前台。
而且ajax的方式好像都是 post方式。
比如: 分页, 前端 需要 向 后台 传递数据: 一个是page(当前页码,即是第几页?), 一个是 pageSize(一页多少条数据)。 然后后台post获取到 页码和页数, 在 mysql的查询语句中 ,用 limit start rowsCount, 来规范限定 返回的数据。
而且, 后台 除了返回 当前页面需要的部分 rows数据外, 还要返回一个 total总页数。
最后的 返回结果 要写成 json格式的: 这种 类型: {"total": $total, "rows": .....}
dg的主要内容:
一个是加载 dg的内容, 并完成分页;
二个是, 排序,可以只做 初始化的时候 排序;
三是: 设置dg的样式, 有striped, rowNumbers, singSelected为true等等.
只要是ajax服务器端有echo内容的, 即使在前端没有处理、使用 这些数据的代码,比如没有什么alert的, 也是可以看到服务器返回的数据的, 使用firebug的 network的 param, 和response,就可以查看,而且这个其实是查看得很详细很全面 的。
关于isset和 empty在 查询按钮使用时的区别?
isset是判断 $_POST的某个 变量名 是否设置了的, 主要是 用来 判断 按钮 是否被 单击了的, 主要是 防止 页面刷新时 执行代码;
而 !empty 是判断 \(_POST的变量名的值是否为空, 主要是用来判断搜索框中是否有输入 内容的, 常用的判断就是:
`if(isset(\)_POST['name']) && !empty($_POST['name'])){...}`
php中变量的两边使用 大括号?
主要有三种情形:
- 一是避免 变量 和变量后面的字符串 连在一起 , 从而引起混淆和错误;
- 二是 在 变量的外面两边 使用 大括号, 可以在 单引号中 也可以输出变量的值, 避免使用 点号来连接 字符串的麻烦
- 三是, 在 变量的名称后 使用大括号, 比如
$str{5}
可以输出字符串中的 第n 个字符。常用来判断字符串的长度:if(!isset($str{5})){...}
==============================================
写代码的一个重要方法, 不是从上到下挨着挨着的写, 而是先写结构, 像if...else这些结构, 然后写简单的分支,最后才写重要的最复杂的分支
- dg的 增删改 编辑操作, 类似于百度网盘, 工具栏上 各种操作按钮, 然后在一个 obj={...}的各种 成员变量和成员方法中 来实现这些功能.
- show 和hide方法, 可以同时针对多个 匹配的元素, 比如: 多个按钮 可以同时一次性的 show 或 hide:
$('#btn1, #btn2'). show(); $('#btn1, #btn2'). hide();
关于datagrid的主要内容有:
- 就是dg的内容载入, 通常是通过js的方式, 并且要分页;
- 就是对内容进行 排序, 一般实现初始化的时候排序就好了
- 是设置dg的内容的一些样式, 比如: striped, rowNumbers, singleSelect(但是如果要增删改的话, 通常还不能设为单选择), 列宽自适应等fitColmns. 在列宽自适应的时候, 要同时设置每一列的宽度为100(这个100是百分比)
- 设置工具栏, 增删改的按钮, 以及 实现查找功能. 工具栏 还是 使用 id#tb的方式. 查询的时候, 可能有多个查询条件, 使用 And. 还要注意在查询/查找 /过滤的情况下, 分页功能仍然要是正确的和可用的
要注意查询/ (以及后面的 增删改等操作) 的过程基本上 都是3步走 : 在obj对应的 方法函数中, 先调用 dg的 load方法, 向服务器 传递 查询条件的 键值对; 然后服务器端 接受查询条件,在数据库中进行 处理, 并返回结果; 然后 再在客户端 用 ajax 处理接收到的数据. - 5/6/7章 是进行增删改操作的: 第五章是进行增加操作的 前台处理和数据准备和ajax提交; 第六章是进行删除和修改前台处理和数据准备等; 第七章是讲 增删改的后台服务器操作的
而有些操作是, 共同的: 比如 开始编辑的操作是: beginEdit, 结束编辑的操作是: endEdit.
==========================================
dg的数据加载?
- columns属性是 两个中括号, 每个对象的属性可以有: field, title, checkbox, sortable, width, 数据的对齐方式align/valign, 跨列/行 rowspan, colspan等
- 列的内容, 只能从 url属性中 通过 ajax 远程加载, 要注意的是, url的内容, 是一个 json格式的数组, 数组元素是 json格式的对象 . 如果是从数据库取数据, 必须进行json 格式处理.即:
[{"id": 1, "name": "foo"}, .....]
的形式. 如果 php返回的格式 不是这样的, 将不会加载数据 进来.
比如
public function dgcontent(){
$sort = I('post.sort');
$order = I('post.order');
$page = I('post.page');
$pageSize = I('post.rows');
$from = $pageSize*($page-1);
$dg = M('dg');
$total = $dg -> count();
$result = $dg->field('id, dept, class, name')->order("$sort $order")->limit($from,$pageSize)->select();
$json="";
for($i=0, $j=count($result); $i<$j; $i++){
$json .= json_encode($result[$i]).',';
}
$json ='{"total":'.$total.',"rows":['. substr($json, 0 , -1).']}';
echo $json;
}
==========================================
strip和stripe的区别?
- strip [ strip] : 的意思, 名词时表示: 条, 带, 狭长地带, 带子, 布带的意思, 动词, 则是 '剥夺'; '分割成条带"
- stripe [straip] 的意思 , 是 各种 条纹! 比如 斑马身上的条纹, 横条纹, 竖条纹, 测试压力的复杂条纹之类的.
MySQL按照字段的 汉字的拼音排序,怎么和常规的想象不一样啊?
按照汉字的拼音排序,用的比较多是在人名的排序中,按照姓氏的拼音字母,从A到Z排序; 如果存储姓名的字段采用的是GBK字符集,那就好办了,因为GBK内码编码时本身就采用了拼音排序的方法(常用一级汉字3755个采用拼音排序,二级汉字就不是了,但考虑到人名等都是常用汉字,因此只是针对一级汉字能正确排序也够用了)。 直接在查询语句后面 添加 order by name asc; 查询结果按照姓氏的升序排序; 如果存储姓名的字段采用的是 utf8字符集,需要在排序的时候对字段进行转码;对于的代码是 order by convert(name using gbk) asc; 同样,查询的结果也是按照姓氏的升序排序(所以, 如果存储的是utf8字符集, 因为有一个转码的过程, 所以看到的排序和想象中的不一样.
count(1) 是什么意思?
count(1),其实就是计算一共有多少符合条件的行。
1并不是表示第一个字段,而是表示一个固定值。
其实就可以想成表中有这么一个字段,这个字段就是固定值1,count(1),就是计算一共有多少个1.
同理,count(2),也可以,得到的值完全一样,count('x'),count('y')都是可以的。一样的理解方式。在你这个语句理都可以使用,返回的值完全是一样的。就是计数。
count(*),执行时会把星号翻译成字段的具体名字,效果也是一样的,不过多了一个翻译的动作,比固定值的方式效率稍微低一些。
=====================================
到底用margin还是用top?
主要还是从 语义和你的用途上来区分,虽然都能实现相同的效果。
何时应当使用margin:
- 不需要在border外侧添加空白时。
- 空白处不需要背景(色)时。
- 上下相连的两个盒子之间的空白,需要相互抵消时。如15px + 20px的margin,将得到20px的空白。
何时应当时用padding:
- 需要在border内测添加空白时。
- 空白处需要背景(色)时。
- 上下相连的两个盒子之间的空白,希望等于两者之和时。如15px + 20px的padding,将得到35px的空白。
::: margin是用来隔开元素与元素的间距;padding是用来隔开元素与内容的间隔。
margin用于布局分开元素使元素与元素互不相干;“老死不相往来” 是两家人
padding用于元素与内容之间的间隔,让内容(文字)与(包裹)元素之间有一段“呼吸距离”。 是一家人
======================================
关于js字面对象的定义:
/*在js中定义变量,并不是必须加var的! 而且, 不加var表示的是 "全局变量", 是顶级对象window的成员变量
- 直接定义的对象字面变量, 不像用function定义的类, 可以用var什么的, {}内部只能是 key: val形式的键值对(无序)集合,所以, 即使是
定义成员变量, 也只能用 var_name: some_value的形式来定义, 而不能用 分号语句的形式. 同时, 所有的键值对之间 要用 逗号隔开
*/
//这里的obj没有加var, 就是全局对象window的属性
obj={
rowEdit : undefined,
search: function(){
},
add: function(){
},
update: function(){
},
remove: function(){
},
save:function(){
},
};
js中的几种 假值和 空值? (参考: https://blog.csdn.net/u012739535/article/details/17621247
, https://www.cnblogs.com/yangzhx/p/4019073.html
)
包括: undefined, '', 0, null, false. 这些都叫 假值或空值, 在 if判断中都是假. 但是它们还是有区别的:
-
它们的类型不同:
typeof( var_name)
可以知道: undefined 的类型是: undefined, 0 的类型是: number, '' 的类型是string, null的类型是: object, 也就是说 null是对象的空值; false是boolean类型的. -
这些空值相互之间 用 == 判断 , 的结果 是 : 0, false , ''', 三者之间是相等的: 即 0 == false == '' 的结果是true的. 可以认为这三个是 " 假值". 而 undefined==null , 可以认为它们是空值. 但是 undefined和 null 跟 数字相加的结果是不同的: 比如: 10+null =10, 10+undefined = NaN.
所有的假值 用 == 和 空值 比较的 结果 都是 false.
假值 , 有一个实际的对象, 所以 可以用 .toString() 方法.
而空值, 连对象都没有, 所以 不能用 .toString 方法, 否则将抛出异常 -
再就是它们 强制类型转换 : String(var_name) 后的结果不同: 转换成 字符串的时候, 结果分别 跟它们的 "原型字面字符串". 这在字符串拼接 累加的时候要注意.
-
undefined表示 无效对象, 当定义一个变量未被初始化时, 就是undefined, 而 null是已经被初始化 为空对象. 但是所有的空值和假值 用 === 判断 都是false.
js中(包括其他任何 面向对象的语言) 都是一样的, 如果 要在对象中, (即对象内部) , 引用对象的成员变量, 都应该 加上对象本身的引用this, 否则凡是不加this的变量, 都认为是全局变量 而不是对象本身的成员变量, 这样就会报引用错误! 当然, 如果是在对象的外部, 引用对象的成员, 就要用对象的类名了, 比如: obj.rowEdit.
obj={
rowEdit : undefined,
search: function(){
....
add: function(){
if(!this.rowEdit){ // 这里要加this
$('#save, #cancel').show();
$('#box').datagrid('insertRow',{
index: 0,
row: { }
});
datagrid如何禁止编辑某一行, 某一列或某一个 单元格?
参考 : https://www.cnblogs.com/langhua/p/3672820.html
- 禁止行编辑: 先获取到某一行, 然后根据条件, 不调用beginEdit方法, 直接返回, 其他则调用 beginEdit方法
- 禁止某一列编辑, 要么直接就不用设置 列的 editor属性; 如果设置了editor属性, 则调用 getColumnOption, 返回列的属性op, 然后设置 op.editor={} 为空
- 禁止某一个单元格编辑...
=================================================
dg中, tp中, 凡是从控制器传递到 模板的变量, 比如: $this ->foo = 'foo',
- 那么在 模板中, {\(foo}是可以直接解析的! 根本就不需要 再在 {\)foo} 的两边再 考虑什么引号了, 不管是单引号, 还是 双引号都不再需要了! 特别是再 href传递变量的时候 加上 引号等 反而会出错. 比如:
url: "{:U('xscontent')}"+'/?class={$class}',
就好了. - 但是 , 如果是 在 alert 等 语句中, 要 使用 模板变量的话, 你就还是需要 加上 引号了, 因为 直接解析模板变量后, 就是 一个 "字符序列", 不是 字符串! 而报错!
dg的后台是如何返回数据, 来填充前台的记录行的?
/*datagrid的返回结果, 来填充 前台的 数据行,必须严格要求json格式, 而且json的格式和属性名必须是:
* "rows:": json_object_array, 即必须是rows, 后面的数据必须是数组, 每个数组元素必须是json格式的对象
* echo '{"total":"11","rows":[{"id":"100", "class":"A_class", "name":"the_Name", "account":"the_account"}]}';
*/
==============================================
一个很重要的注意问题: 在ajax中, 如果 url的目标地址, target是空的字符串时, 该次 ajax 将提交给 "当前页面"! 从而也会得到 ajax 成功success的 结果! 而事实上 这在很多应用场景下 是 不允许的. 所以 你要 判断 一下 你的 ajax url 目标地址 是否为空
比如: 在 dg的 onAfterEdit事件中, 就要判断 url 是否为空, 然后才去调用 ajax.
onAfterEdit: function(rowIndex, rowData, changes){
var inserted = $('#box').datagrid('getChanges', 'inserted');
var updated = $('#box').datagrid('getChanges', 'updated');
var url=info='';
if(inserted.length>0){
url='{:U("add")}';
info='新增';
}
if(updated.length>0){
url='{:U("update")}';
info='修改';
}
/*
这里很重要 , 要判断一下 url是否为空, 否则 即使任意地 双击 一行记录, 再去 双击另外一行记录, 即使没有和数据库进行 修改操作, 也会提示 ajax的success提示信息 , 然而这个时错误的!
*/
if(url!='' && info != ''){
$.ajax({
type: 'post',
url: url,
data: {row: rowData,},
beforeSend: function(){
$('#box').datagrid('loading');
},
success: function(data){
if(data !== false){
$('#box').datagrid('loaded');
$('#box').datagrid('load');
$('#box').datagrid('unselectAll');
$.messager.show({
title: '消息',
msg: '1个班级 '+ info +' 成功',
showType: 'slide',
timeout: 3000
});
obj.rowEdit = undefined;
}
},
});
===================================================
如何禁用datagrid的某一行被 单击选中或 被 双击选中? 参考: https://blog.csdn.net/Dzq_Boyka/article/details/78531217
主要思想是, 在 onClickRow 和 onDblClickRow 事件中 , 必须显示的调用 $('#box').datagrid('unselectRow', rowIndex)
方法, 不能只是 简单地 返回 return.
-
要想使dg 在 新增的时候, 不能选择行或 双击行 操作, 那么 可以设置一个 标识变量: isAdded , 当 每次 新增的时候, 都重新设置 isAdded = false, 然后, 判断 onClickRow 和 onDblClickRow 事件中 的 isAdded是否 为false, 或者 true
-
但是又要保证 初次载入 datagrid的时候, 如果不点击 新增的时候, 要能够 选择单行, 或 双击单行操作, 就要 初始化 obj的 isAdded 为true.
obj={
rowEdit : undefined,
isAdded: true, // 这里是 关键!
add: function(){
// 一旦增加的时候, 就要重新初始化isAdded为false, 因为只要保存/取消一次后, isAdded就失效了
this.isAdded=false;
....
}
onDblClickRow: function(rowIndex, rowData){
// 在新增记录的时候, 禁止单击选行 和 双击选行
if(!obj.isAdded){
$('#box').datagrid('unselectRow', rowIndex);
return;
}
// 双击某一行的时候, 首先要关闭之前可能被修改的行
if(obj.rowEdit != undefined){
$('#box').datagrid('endEdit', obj.rowEdit);
obj.rowEdit = undefined;
}
............
},
onClickRow: function(rowIndex, rowData){
if(!obj.isAdded){
$('#box').datagrid('unselectRow', rowIndex);
return;
}
},
=====================================================
分页器: pagination的ajax事件? 参考: https://blog.csdn.net/H12KJGJ/article/details/53672096
- 分页器的分页list , 不是固定的, 也不是什么 倍数, 你可以任意的自由的 设置 任意数值:
pageList 类型array 用法: 用户能改变页面尺寸。pageList 属性定义了能改成多大的尺寸。
代码实例:
$('#pp').pagination({
pageList: [10,20,50,100]
});
-
分页器中 的一个 页面 由两个 因素来决定: 一个是: pageSize( 每一个页面的最大尺寸), pageNumber(页数), 所以 每一页的第一条数据的索引值就是: pageSize*(pageNumber-1);
这个就是用来 做 数据库的limit的 依据的:
因此 : onSelectPage 事件, 就是 当重新改变了pageSize , 重新选择了 pageNumber后所得到的页面. -
总共有4个 ajax事件: onSelectPage, onBeforeRefresh, onRefresh, onChangePageSize... 因此, 在dg中改变分页尺寸的事件是 : onChangePageSize的回调函数中写
===========================================
关于bootstrap中的 table中的单元格内容 水平居中和 垂直居中? 参考: https://blog.csdn.net/peng_hong_fu/article/details/70662979
- 水平居中是: 写 text-center类, 而垂直居中, 则是 写 stye的 vertical-align: middle
- 要注意的是: th的水平居中, 要写在 th单元格内 , 不能写在th的父元素 tr中; 普通的td的水平居中可以写在父元素 tr中
而垂直居中 , 不能简单的写: tbody tr td的样式, 而是要 写 .table tbody tr td. 因为后者的 css优先级为 10+1+1+1 =13, 而前者的css优先级是: 1+1+1=3. 所以 要 优先执行 后者的css. 而后者的css正是在 bootstrap中定义的, 默认为top. 所以 你简单的写 tbody tr td是改变不了的, 要被 bs的所覆盖, 要想在 style 标签中 " 覆盖" bs的默认设置的话, 需要写 完整: .table tbody tr td - 总之, 选择符越详细越具体, 它的css优先级 值就越大. 优先级 就越高
css的优先级? 参考 https://blog.csdn.net/amyleeYMY/article/details/63685330
由四位数字 组成:
!important =1000,
id的优先级=100,
类, 伪类, 属性的优先级 =10,
元素, 伪元素的优先级=1
这些优先级, 不管层次, 只要有一个就 加上相应的 优先级 数值. 最后 算 总和.
但是要注意:
-
伪元素 只有四个, 即 :before, :after, : first-letter, :first-line , 主要是表示位置的
伪类 有更多, 只要是表示 "状态"的, 比如 :link, :active, :visited, :hover, :focus, :first-child 等 -
如果有多个 相互冲突的 css规则 同时作用在同一个 元素上, 则最终 起作用的是: 以 定义这些类样式的先后顺序为准, 后定义的样式 会 覆盖 先前定义的样式, 即 后定义的样式 最终 将起作用. 而跟 该元素上 , 多个类样式 书写的先后顺序无关.
easyui的消息框 是异步的, 如何理解?
-
异步, 表示 它是 "非模态的", 虽然有 "遮照" 样式, 但是 它并不会阻止 该消息框 后续的代码的执行. 相反, 在执行 消息框的 回调函数时, 主函数的 剩余代码 已经执行完毕了! 所以这就是 为什么主函数中 无法获取 回调函数的 返回值的原因
-
那么 要想实现 模态 框的 效果, 想要 某些代码 在 点击 "确定" 后, 再执行, 就要把 这些代码 放在 消息框的 回调函数中, 因为 回调函数 总数在 用户 单击 "确定" 按钮后 才执行.