8.2 实战过程

首先,看到题目的要求是制作一个列表管理,将它分为3部分:顶部的操作按钮和筛选条件、中间的列表内容、底部的分页码。

刚开始的时候,本来想只用一个table里的thead、tbody、tfoot实现这3个部分,但是后来在将第一列的checkbox居中对齐的时候,发现会对thead和tfoot有影响,所以就换成了panel组件、table以及list-group组件的组合了。示例代码如下:

  1. <div class="panel panel-default ">
  2. <div class="panel-heading">
  3. 这里是head区
  4. </div>
  5. <table class="table table-bordered table-hover">
  6. <thead></thead>
  7. <tbody></tbody>
  8. <tfoot></tfoot>
  9. </table>
  10. <ul class="list-group">
  11. <li class="list-group-item">
  12. 这里放分页码
  13. </li>
  14. </ul>
  15. </div>

panel里有3部分,panel-heading里放置操作按钮和筛选条件,中间放表格,并且在表格上应用了table-bordered样式,以便都有边框,另外还加了一个鼠标移动变化tr背景色的功能,显得富有动感。底部的list-group用于放置分页码,这里用list-group是因为该组件和panel一起用的时候,可以很好地处理横线和底部边框的效果,具体可以参考该组件的详细使用方法。上述代码的效果如图8-2所示。

8.2 实战过程 - 图1 图8-2 pannel里设置表格显示

表格设计得很不错。下一步,因为我很喜欢分页码,所以先处理这一块,把相关代码放到list-group-item样式元素里。代码如下:

  1. <li class="list-group-item">
  2. <ul class="pagination ">
  3. <li class="disabled"><span>Prev</span></li>
  4. <li class="active"><a href="#">1 <span class="sr-only">(current)
  5. </span></a></li>
  6. <li><a href="#">2</a></li>
  7. <li><a href="#">3</a></li>
  8. <li><a href="#">4</a></li>
  9. <li class="disabled"><span>...</span></li>
  10. <li><a href="#">14</a></li>
  11. <li><a href="#">15</a></li>
  12. <li><a href="#">16</a></li>
  13. <li><a href="#">17</a></li>
  14. <li><a href="#">Next</a></li>
  15. </ul>
  16. </li>

这里先设置第一页为当前页,那么上一页(prev)就得被禁用掉。另外,在分页码很多的情况下,中间经常要省略一部分页面,所以在它上面也使用了disabled样式,运行效果如图8-3所示。

8.2 实战过程 - 图2 图8-3 分页组件效果

分页显示不是很好看,上下边距太大了,而且我想让每个页码都单独分开,这样显得更有个性。那么就来改造一下pagination样式。由于不能影响原有的分页功能,所以我们按照再附加一个square样式的情况进行改造,主要是要改造上下边距,以及每个li元素的外边距。代码如下:

  1. .pagination.square {
  2. margin: 0;/* 去除外边距 */
  3. }
  4.  
  5. .pagination.square > li > a,
  6. .pagination.square > li > span {
  7. margin: 0 5px;
  8. border: 1px solid #dddddd; /* 设置所有的边框都为1像素 */
  9. }
  10.  
  11. .pagination.square > li:first-child > a,
  12. .pagination.square > li:first-child > span,
  13. .pagination.square > li:last-child > a,
  14. .pagination.square > li:last-child > span {
  15. margin-left: 0px;
  16. padding-left: 10px;
  17. padding-right: 10px;
  18. border-radius: 0px; /* 取消圆角 */
  19. }

不仅把外边边距都调整了,还把前后元素的圆角也都去除了,形成一个很干净的方形效果,如图8-4所示。

8.2 实战过程 - 图3 图8-4 分页数字方框间隔显示

现在可以处理head头部的内容了。在这里想将它分为左右两部分,左边放功能按钮,右边放筛选和排序选择菜单,所以加了两个div,分别是pull-left和pull-right,来实现左右浮动。代码如下:

  1. <div class="panel-heading">
  2. <div class="pull-right">
  3. 左边区域
  4. </div>
  5. <div class="pull-left">
  6. 右边区域
  7. </div>
  8. </div>

运行看效果,发现效果变形了(和table重叠了),原因是没有清除浮动。记得Bootstrap里有清除浮动的样式,查了一下手册,找到了clearfix,将该样式应用到panel-heading上即可,效果如图8-5所示。

8.2 实战过程 - 图4 图8-5 将pannel头部分为左右两部分

左边的按钮很简单,在里面直接放3个button元素即可,然后用颜色样式稍微修饰一下。

  1. <div class="pull-left">
  2. <button class="btn btn-success">New</button>
  3. <button class="btn btn-warning">Disable</button>
  4. <button class="btn btn-danger">Delete</button>
  5. </div>

右边的排序和筛选条件就比较复杂了。刚开始的时候,想直接用select元素就可以了,但是该元素在不同的操作系统和浏览器下显示效果不一样,而且想体现一下对Bootstrap的了解,所以就用了下拉菜单(Dropdown)组件。排序和筛选分别用两个下拉菜单,其外部用按钮组(btn-group)样式包住,这样就差不多了。代码如下:

  1. <div class="pull-right">
  2. <div class="btn-group">
  3. <button type="button" class="btn btn-default
  4. dropdown-toggle active" data-toggle="dropdown">
  5. Filter By Disabled <span class="caret"></span>
  6. </button>
  7. <ul class="dropdown-menu" role="menu">
  8. <li><a href="#">Filter by Account Status</a></li>
  9. <li><a href="#">Filter by Department</a></li>
  10. <li class="divider"></li>
  11. <li><a href="#">Reset</a></li>
  12. </ul>
  13. </div>
  14.  
  15. <div class="btn-group">
  16. <button type="button" class="btn btn-default
  17. dropdown-toggle" data-toggle="dropdown">
  18. Sort By FirstName <span class="caret"></span>
  19. </button>
  20. <ul class="dropdown-menu pull-right" role="menu">
  21. <li><a href="#">Sort by FirstName</a></li>
  22. <li><a href="#">Sort by Email</a></li>
  23. <li class="divider"></li>
  24. <li><a href="#">Reset</a></li>
  25. </ul>
  26. </div>
  27. </div>

看到两段代码有点一样了吧,筛选条件下拉菜单里,我将button的样式多加了一个active样式,主要是告诉后端集成的开发人员,如果他想把(已经选择的条件)作为高亮显示就加active样式就可以了,如果没有选择条件,就不用加active样式。

另外一个排序下拉菜单,我多用了一个pull-right,这是因为,刚开始预览的时候发现,如果下拉菜单里的文字太长,就会超出屏幕右侧(溢出了),加了pull-right样式后就可以让它右对齐了,效果如图8-6所示。

8.2 实战过程 - 图5 图8-6 在Pannel头部添加操作按钮和筛选条件

有点做前端开发的感觉了。看看再增加点什么?最后一列的按钮还没做,应该可以做至少3个按钮:查看详细信息、查看该用户的角色、更多操作(再弹出一个下拉菜单)。还要选择合适的颜色(由于使用默认的btn样式会增加行高,所以使用了超小型按钮)。代码如下:

  1. <button class="btn btn-xs btn-info">Info</button>
  2. <button class="btn btn-xs btn-success">Role</button>
  3. <div class="btn-group">
  4. <button type="button" class="btn btn-xs btn-primary dropdown-toggle"
  5. data-toggle="dropdown">
  6. More <span class="caret"></span>
  7. </button>
  8. <ul class="dropdown-menu" role="menu">
  9. <li><a href="#">Projects</a></li>
  10. <li><a href="#">Tasks</a></li>
  11. <li><a href="#">Timesheet</a></li>
  12. <li class="divider"></li>
  13. <li><a href="#">Others</a></li>
  14. </ul>
  15. </div>

上述示例的运行效果如图8-7所示。

8.2 实战过程 - 图6 图8-7 表格行数据里的操作按钮显示

图8-7所示的效果看起来还行,但是稍微有点单调。添加一个小图标icon试试怎么样,示例如下:

  1. <button class="btn btn-xs btn-info">
  2. <span class="glyphicon glyphicon-list"> </span>Info
  3. </button>
  4. <button class="btn btn-xs btn-success">
  5. <span class="glyphicon glyphicon-user"> </span>Role
  6. </button>

添加完图标以后,发现小图标和文字靠在一起了,所以又重新定义了一下小图标的右外边距。代码如下:

  1. .btn > .glyphicon {
  2. margin-right: 3px;
  3. }

这样,完成以后,发现运行效果真的比之前好太多了,效果如图8-8所示。

8.2 实战过程 - 图7 图8-8 综合显示效果

应该能给自己打80分了。但还有问题。第一列的全选按钮checkbox忘记加了,而且ID也没有居中对齐。

于是在第一列和第二列的所有的td上都加了一个text-center样式,但是发现这种方式添加,样式重复出现的次数太多了,为了用最少的代码实现最多的功能,决定使用CSS的选择器来实现(虽然还不太熟),试验了很多次才搞定(看来CSS3还得再强化才行)。代码如下:

  1. thead > tr:not(:first-child) > td:nth-child(1),
  2. thead > tr:not(:first-child) > td:nth-child(2),
  3. tbody > tr > td:nth-child(1),
  4. tbody > tr > td:nth-child(2) {
  5. text-align: center;
  6. }

平时犯懒的时候肯定就只用一个样式,在所有的td上附加,但这次是竞赛,为了体现我还是懂一点CSS3的,所以使用了nth-child、first-child、not这样的选择器条件,保存刷新,效果如图8-9所示。

看着这样的效果,我自己都觉得挺满意了。但是时间还有1个多小时呢,应该再多做一点东西。想一下还要体现哪些能力。对了,弹窗还没用过,这个页面好多地方都可以用到弹窗,比如单击Info按钮的时候查看用户信息,单击Role按钮的时候查看角色信息,单击New按钮时也可以添加新用户。

由于Info按钮和Role按钮都是显示信息,所以我做了一个固定的弹窗,所有的单击事件都调用这一个弹窗(以后开发人员开发的时候再换id就行了)。首先,在所有的Role按钮上都添加了data-toggle和data-target,以便在单击的时候可以找到对应的id。代码如下:

8.2 实战过程 - 图8 图8-9 复选框显示效果

  1. <button class="btn btn-xs btn-info" data-toggle="modal"
  2. data-target="#rolePopUp"> </button>

然后按照Modal插件的要求,设置了一个隐藏的div,并在其中modal-body里设置角色列表,最后还提供一个“关闭”按钮。代码如下:

  1. <div class="modal fade" id="rolePopUp">
  2. <div class="modal-dialog">
  3. <div class="modal-content">
  4. <div class="modal-header">
  5. <button type="button" class="close" data-dismiss="modal"
  6. aria-hidden="true">×</button>
  7. <h4 class="modal-title" id="myModalLabel">Roles of Tom Xu</h4>
  8. </div>
  9. <div class="modal-body">
  10. <table class="table table-hover"></table>
  11. </div>
  12. <div class="modal-footer">
  13. <button type="button" class="btn btn-default"data-dismiss=
  14. "modal">Close</button>
  15. </div>
  16. </div>
  17. </div>
  18. </div>

上述示例的运行效果如图8-10所示。

同样的道理,在New按钮上也绑定一个弹窗,id为newPopup,只不过这一次弹窗的内容变成了表单。对于表单的字段,不用做太多工作,所以只用了email、password、Username这3个字段和一个复选框,但是按钮没有少,提供了3个,分别用于保存、重置和取消操作。表单的代码如下:

8.2 实战过程 - 图9 图8-10 弹窗显示效果

  1. <form class="form-horizontal" role="form">
  2. <div class="form-group">
  3. <label for="inputEmail3" class="col-sm-2 control-label">Email</label>
  4. <div class="col-sm-10">
  5. <input type="email" class="form-control" id="Email"
  6. placeholder="Email">
  7. </div>
  8. </div>
  9. <div class="form-group">
  10. <label for="inputPassword3" class="col-sm-2 control-label">Password</label>
  11. <div class="col-sm-10">
  12. <input type="password" class="form-control" id="Password"
  13. placeholder="Password">
  14. </div>
  15. </div>
  16. <div class="form-group">
  17. <label for="inputPassword3" class="col-sm-2 control-label">Username</label>
  18. <div class="col-sm-10">
  19. <input type="text" class="form-control" id="Username"
  20. placeholder="Username">
  21. </div>
  22. </div>
  23. <div class="form-group">
  24. <div class="col-sm-offset-2 col-sm-10">
  25. <div class="checkbox"><label><input type="checkbox">Enable
  26. </label></div>
  27. </div>
  28. </div>
  29. </form>

运行效果如图8-11所示。但是又发现鼠标单击灰色区域的时候,弹窗就关闭了,这说明缺少禁用这个事件了。于是又在New按钮上加了一个data-backdrop="static"属性,这样就没问题了。

8.2 实战过程 - 图10 图8-11 带表单的弹窗显示效果

做到这时候,时间还余半个小时,突然想起来,对JavaScript方面的能力还没有体现过呢。正好Modal插件提供了好几个事件回调可以使用。

首先,我想在单击Create按钮的时候对表单进行验证,所以我引入了jQuery的validate插件。在定义JS代码的时候,引入validate库以后,首先进行了设置,然后对单击事件进行监控。代码如下:

  1. $('#newPopUp').find('#btnCreate').on('click', function (e) {
  2. $('#newPopUp').find("form").validate({
  3. submitHandler: function (form) {
  4. // 处理内容
  5. }
  6. });
  7. })

发现这样做一点儿用都没有,弄了10多分钟也没找出问题,后来只有10多分钟了。所以我就放弃了。但是还有最后5分钟的时候突然发现,可以先使用popover插件伪造一个验证效果代码如下:

  1. $('#Username').popover({
  2. title: "Alert",
  3. content: "Username must be input.",
  4. placement: "bottom",
  5. trigger: "manual"
  6. })
  7.  
  8. $('#newPopUp').find('#btnCreate').on('click', function (e) {
  9. $('#Username').popover("show");
  10. })

这样在单击按钮的时候,会弹出提示,说用户输入不合法。这样做的目的只是给客户展示我想实现这样的效果(只不过不完善而已)。

最后又发现了一个问题,popover信息提示以后关闭不了,所以我就在input的focus上添加了一个回调,手动关闭整个信息提示。代码如下:

  1. $('#Username').focus(function () {
  2. $('#Username').popover("hide");
  3. });

就这样,总算完成了。最后在评奖的时候,我居然是全公司的第一名,是做得最好的。其他同事大部分都只完成一半,很多人都抱怨说,仅全选、反选的JavaScript代码都浪费了很长时间。我当初没有做这个就是怕代码麻烦,其实说实话,我也没有好的办法哦。