详解MVC如何使用开源分页插件(shenniu.pager.js)


Posted in Javascript onDecember 16, 2016

最近比较忙,前期忙公司手机端接口项目,各种开发+调试+发布现在几乎上线无问题了;虽然公司项目忙不过在期间抽空做了两件个人觉得有意义的事情,一者使用aspnetcore开发了个人线上项目(要说线上其实只能ip访问,没有域名哈哈),其架构组成由:aspnetcore1.0.0+redis+ postgressql+TaskMainForm服务,这个项目在后期会开源出来供大家分享学习,站点地址点这里心声网;一者是目前正在做的后台管理框架一叶子,现目前刚好吧js分页插件shenniu.pager.js写完,个人觉得还是可以的,这也是本章将要和大家分享的内容;那么开始今天的分享内容,希望各位多多扫码支持:

  • 为什么采用js分页及效果图
  • 在view中如何使用及分享个后台方法
  • 开发者视角阅读shenniu.pager.js代码

下面一步一个脚印的来分享:

. 为什么采用js分页及效果图

首先,咋们来了解下市面上mvc两种常用的分页方式:跳转分页和ajax分页;跳转分页意思就是页面重定向到指定的页面并通过传递分页需要的参数,从而获取数据后通过Modal来绑定数据,这个每次都会刷下页面体验上不是很好;ajax分页通过异步js请求某个接口,然后从接口获取到数据后,再赋值到展示的界面上,这种方式是不会刷新页面,从而保证了用户体验;

下面来看下这次分享的js分页插件效果图:

图一:

详解MVC如何使用开源分页插件(shenniu.pager.js)

图二:

详解MVC如何使用开源分页插件(shenniu.pager.js)

图三:

详解MVC如何使用开源分页插件(shenniu.pager.js)

看效果图好像看不出来什么东西,我只能说没办法,以后争取弄个gif动态图片吧,后面代码才是关键

. 在view中如何使用及分享个后台方法

首先,为了页面样式好看我使用了bootstrap+ace样式框架,样式效果就是如上面几张图所示(这里是样式和js文件);由于该插件是采用jquery格式书写的所以需要引用jquery.js,如上面图所示使用到了日期选择框,因为我采用的样式都是基于h5的设计所以这里引用的日期选择插件bootstrap-datepicker.min.js和她的样式bootstrap-datepicker3.min.css;该实例需要的引用文件都好了,下面看下截图:

详解MVC如何使用开源分页插件(shenniu.pager.js)

再来,咋们就开始使用shenniu.pager.js,我们需要在点击“查询”按钮的时候去调用这个插件,然后通过插件去获取后台接口返回的数据,并绑定到页面展示出来,所以有了如下代码:

var snTool = new shenniuTool();
 $("button[id='btnSearch']").on("click", function () {
 var data = {
 txtName: $("input[name='txtName']").val(),
 nStatus: $("select option:selected").val(),
 dOperateTime: $("input[name='dOperateTime']").val()
 };
 snTool.listFun({
 showId: "divShowResult", //内容显示的div的Id
 url: "/Menu/Search",
 data: data,
 pageSize: 2, //每页N条
 headText: [
 { nickName: "全选", name: "Id", colType: "checkbox" },
 { nickName: "名称", name: "Name", colType: "label", isModalHeadText: true },
 { nickName: "链接", name: "Link" },
 { nickName: "状态", name: "EnableDes" },
 { nickName: "操作人", name: "OperatorDes" },
 { nickName: "操作时间", name: "OperateTime", format: "yyyy-MM-dd" },
 { nickName: "操作", name: "Id", colType: "operate" }
 ],
 editeOption: {
 url: "/Menu/Edit",
 title: "编辑",
 height: 500
 },
 viewOption: {
 url: "/Menu/Details",
 title: "查看",
 height: 500
 },
 delOption: {
 url: "/Menu/Delete",
 title: "删除",
 height: 500
 },
 modalExt: modalExt
 });
 });

注意参数url: "/Menu/Search",这个指向的就是后台接口,那么咋们来看下我后台咋们写的:

[HttpGet]
 public JsonResult Search()
 {
 var moPageResult = new StageModel.MoPageResult<dynamic>();
 try
 {
 var txtName = Request.Params["txtName"];
 var nStatus = string.IsNullOrWhiteSpace(Request.Params["nStatus"]) ? -1 : Convert.ToInt32(Request.Params["nStatus"]);
 var dOperateTime = string.IsNullOrWhiteSpace(Request.Params["dOperateTime"]) ? Convert.ToDateTime("1991-01-01") : Convert.ToDateTime(Request.Params["dOperateTime"]);
 var data = db.MoMenus.AsQueryable();
 if (!string.IsNullOrWhiteSpace(txtName))
 {
 data = data.Where(b => b.Name.Contains(txtName));
 }
 if (nStatus >= 0)
 {
 data = data.Where(b => b.IsEnable == (nStatus == (int)StageEnumHelper.ComStatus.启用));
 }
 if (dOperateTime > Convert.ToDateTime("1991-01-01"))
 {
 data = data.Where(b => b.OperateTime >= dOperateTime && b.OperateTime < dOperateTime.AddDays(1));
 }
 moPageResult.MoPageContent(
 data,
 b => b.OperateTime,
 b => new
 {
 Id = b.Id,
 Name = b.Name,
 Link = b.Link,
 Des = b.Des,
 IsEnable = b.IsEnable,
 Operator = b.Operator,

 OperatorDes = b.MoUserInfo.NickName,
 EnableDes = b.IsEnable ? "启用" : "禁用",
 OperateTime = b.OperateTime
 });
 }
 catch (Exception ex)
 {
 }
 return Json(moPageResult, JsonRequestBehavior.AllowGet);
 }

后台接口Request.Params获取的几个参数就是从前端

var data = {
 txtName: $("input[name='txtName']").val(),
 nStatus: $("select option:selected").val(),
 dOperateTime: $("input[name='dOperateTime']").val()
 };

传递过来的,分别代码了视图中的名称,状态,操作时间等查询条件;下面来看下,后台这儿没有看到获取类似分页的当前页数和分页记录数的操作,是封装到了MoPageResult类中的MoPageContent()中,来看下MoPageResult类代码如:

#region 分页数据返回
 public class MoPageResult<TResult> where TResult : class, new()
 {
 public MoPageResult()
 {
 }
 public IQueryable<TResult> MoResult;
 /// <summary>
 /// 总页数
 /// </summary>
 public int PageTotal { get; set; }
 /// <summary>
 /// 当前页数
 /// </summary>
 public int CurrentPage { get; set; }
 /// <summary>
 /// 分页记录数
 /// </summary>
 public int PageSize { get; set; }
 /// <summary>
 /// 分页方法
 /// </summary>
 /// <typeparam name="TKey"></typeparam>
 /// <param name="query"></param>
 /// <param name="order_desc"></param>
 public void MoPageContent<T, TKey>(IQueryable<T> query, Expression<Func<T, TKey>> desc, Expression<Func<T, TResult>> selector = null, bool isDesc = true) where T : class,new()
 {
 if (HttpContext.Current == null) { return; }
 var Request = HttpContext.Current.Request;
 this.PageSize = string.IsNullOrWhiteSpace(Request.Params["pageSize"]) ? 15 : Convert.ToInt32(Request.Params["pageSize"]);
 this.CurrentPage = string.IsNullOrWhiteSpace(Request.Params["currentPage"]) ? 1 : Convert.ToInt32(Request.Params["currentPage"]);
 var nTotal = query.Count();
 this.PageTotal = nTotal / this.PageSize + (nTotal % this.PageSize > 0 ? 1 : 0);
 if (selector != null)
 {
 if (isDesc)
 {
 query = query.OrderByDescending(desc);
 }
 else
 {
 query = query.OrderBy(desc);
 }
 this.MoResult = query.
 Skip((this.CurrentPage - 1) * this.PageSize).
 Take(this.PageSize).
 Select(selector);
 }
 }
 }
#endregion

MoPageContent()中默认是获取了pagesize,currentpage参数,这样减少了用户操作性,并且此方法承担了计算总页数和执行分页语句的角色,注意最后查询语句Select(selector),selector是Expression<Func<T, TResult>>类型,这个T有条件约束where T : class,new();我在调用该分页类的使用传递的T是dynamic,因为赖人如我觉得匿名类更方便;唯一遗憾的是select输出暂时无法直接对某个属性直接使用方法;

最后,插件使用还需要注意一个地方,就是时间,如果后台不处理时间直接DateTime的json格式化,那么在插件获取出来的时间格式如:

详解MVC如何使用开源分页插件(shenniu.pager.js)

这个时候就需要在使用shenniu.pager.js插件时候在属性headText中,指定时间列的格式如:

{ nickName: "操作时间", name: "OperateTime", format: "yyyy-MM-dd" }

使用format格式化时间格式,这个插件兼容的给有:yyyy,MM,dd,HH,mm,ss,相信满足大家需要了;

. 开发者视角阅读shenniu.pager.js代码

首先,我们从上而下,映入眼帘的是插件属性:

var defOption = {
 showId: "divShowResult", //内容显示的div
 url: "", //ajax数据来源地址
 headText: [
 { nickName: "A", colType: "checkbox", name: "Id" },
 { nickName: "B", colType: "label", name: "Name", isModalHeadText: true } //isModalHeadText:是否是模式窗体头部显示的信息
 ],
 data: {}, //查询条件
 editeOption: {
 url: "",
 title: "编辑",
 width: 500,
 height: 500
 }, //编辑地址,不包括id
 viewOption: {
 url: "",
 title: "查看",
 width: 500,
 height: 500
 }, //查看地址
 delOption: {
 url: "",
 title: "删除",
 width: 500,
 height: 500
 }, //删除地址
 currentPage: 1, //当前页数
 pageSize: 15, //分页记录数
 showPageTab: 6, //展示6个页数
 modalExt: null, //模式窗体对象
 //可忽略
 callback: function () { }, //回调函数
 tabId: "tab001",
 loading: "努力加载中,等会吧...", //可以直接写出<img src=''/>
 sucFun: function (data) { },
 befFun: function () { },
 errFun: function () { },
 comFun: function () { },
 timeout: 60000 //超时60S
 };
$.extend(defOption, option);

里面已经包括了注释说明,看起来应该不是问题; $.extend(defOption, option); 这段代码意思是吧用户传递进来的参数和插件里面默认的参数合并,用户大于插件直接可以覆盖相同属性的值;

再来,看请求后台的方法:

//请求后台
 function ajaxFun(option) {
 if (option) {
 $.extend(defOption, option);
 }
 //获取分页参数
 var hidPageSize = defOption.pageSize;
 var hidCurrentPage = defOption.currentPage;
 if ($("form input[name='pageSize']").val()) {
 hidPageSize = $("form input[name='pageSize']").val();
 }
 if ($("form input[name='currentPage']").val()) {
 hidCurrentPage = $("form input[name='currentPage']").val();
 }
 //合并用户查询条件和分页参数条件
 var searchData = {
 pageSize: hidPageSize,
 currentPage: hidCurrentPage
 };
 $.extend(searchData, defOption.data);
 //请求后台数据
 $.ajax({
 url: defOption.url,
 type: "get",
 data: searchData,
 dataType: "json",
 timeout: defOption.timeout,
 async: true,
 beforeSend: defOption.befFun,
 success: defOption.sucFun,
 });
 }

这个方法就是请求接口获取数据的方法,里面默认获取了页面中的pageSize,currentPage两个分页所需要的参数,这里采用的是get方式来请求,当然可以写成post,不过需要后台支持post就行了;

我们再看查询列表方法:

//查询列表
 listFun: function (option) {
 if (option) {
 $.extend(defOption, option);
 }
 //默认格式
 var tab = [];
 tab.push('<table id="' + defOption.tabId + '" class="table table-bordered table-hover">');
 tab.push('<thead><tr role="row">');
 for (var i in defOption.headText) {
 var head = defOption.headText[i];
 if (head.colType == "label") {
 tab.push('<th class="center" tabindex="0" rowspan="1" colspan="1">' + head.nickName + '</th>');
 } else if (head.colType == "checkbox") {
 tab.push('<th class="center " rowspan="1" colspan="1" aria-label="">');
 tab.push(' <label class="pos-rel">');
 tab.push(' <input type="checkbox" name="cbAll" class="ace">');
 tab.push(' <span class="lbl">' + head.nickName + '</span>');
 tab.push(' </label>');
 tab.push('</th>');
 } else {
 tab.push('<th class="center" tabindex="0" rowspan="1" colspan="1">' + head.nickName + '</th>');
 }
 }
 tab.push('</tr></thead>');
 tab.push('<tbody><tr><td class="text-center" colspan="' + defOption.headText.length + '">' + defOption.loading + '</td></tr></tbody>');
 tab.push('</table>');
 tab.push('<div id="divPager" class="text-center"></div>');
 $("#" + defOption.showId).html(tab.join(''));
 //全选事件
 $("input[type='checkbox'][name='cbAll']").on("click", function () {
 var cbStatus = $(this).is(":checked");
 if (cbStatus) {
 $("input[name='cb']:checkbox").prop("checked", true);
 } else {
 $("input[name='cb']:checkbox").prop("checked", false);
 }
 });
 //数据返回成功处理
 defOption.sucFun = function (data) {
 var head = $("table[id='" + defOption.tabId + "'] tbody");
 if (data) {
 if (data.MoResult) {
 //遍历table展示的数据
 var rows = [];
 $.each(data.MoResult, function (i, item) {
 rows.push('<tr>');
 var modalHeadText = "";
 for (var h_i in defOption.headText) {
 var head = defOption.headText[h_i];
 var item_val = item[head.name];
 if (item_val && typeof (item_val) != "undefined") { } else { item_val = ""; }
 //时间格式化
 if (head.format && item_val.length > 0) {
 console.log(item_val);
 var date = new Date(parseInt(item_val.replace("/Date(", "").replace(")/", ""), 10));
 item_val = head.format.
 replace("yyyy", date.getFullYear()).
 replace("MM", date.getMonth() + 1).
 replace("dd", date.getDate()).
 replace("HH", date.getHours()).
 replace("mm", date.getMinutes()).
 replace("ss", date.getMilliseconds());
 }
 //获取模式窗体头部信息
 if (modalHeadText.length <= 0) { modalHeadText = head.isModalHeadText ? item_val : "" };
 if (head.colType == "label") {
 rows.push('<td class="center">' + item_val + '</td>');
 } else if (head.colType == "checkbox") {
 rows.push('<td class="center">');
 rows.push(' <label class="pos-rel">');
 rows.push(' <input type="checkbox" name="cb" value="' + item_val + '" class="ace">');
 rows.push(' <span class="lbl"></span>');
 rows.push(' </label>');
 rows.push('</td>');
 } else if (head.colType == "operate") {
 rows.push('<td class="center"><div class="hidden-sm hidden-xs action-buttons">');
 if (defOption.editeOption.url.length > 0) {
 var editOption = $.extend({}, defOption.editeOption);
 editOption.url += "/" + item_val;
 editOption.title += modalHeadText.length > 0 ? "-" + modalHeadText : "";
 var op = JSON.stringify(editOption);
 rows.push('<a class="blue" data-item=\'' + op + '\' href="javascript:;"><i class="ace-icon fa fa-pencil bigger-130"></i></a>');
 }
 if (defOption.viewOption.url.length > 0) {
 var viewOption = $.extend({}, defOption.viewOption);
 viewOption.url += "/" + item_val;
 viewOption.title += modalHeadText.length > 0 ? "-" + modalHeadText : "";
 var op = JSON.stringify(viewOption);
 rows.push('<a class="blue" data-item=\'' + op + '\' href="javascript:;"><i class="ace-icon fa fa-search-plus bigger-130"></i></a>');
 }
 if (defOption.delOption.url.length > 0) {
 var delOption = $.extend({}, defOption.delOption);
 delOption.url += "/" + item_val;
 delOption.title += modalHeadText.length > 0 ? "-" + modalHeadText : "";
 var op = JSON.stringify(delOption);
 rows.push('<a class="blue" data-item=\'' + op + '\' href="javascript:;"><i class="ace-icon fa fa-trash-o bigger-130"></i></a>');
 }
 rows.push('</div></td>');
 }
 else {
 rows.push('<td class="center">' + item_val + '</td>');
 }
 }
 rows.push('</tr>');
 });
 //页数展示
 if (data.MoResult.length > 0) {
 var pager = [];
 pager.push('<div class="text-center">');
 pager.push(' <ul class="pagination" style="margin-top:0px">');
 var nPager = defOption.showPageTab;//每次展示6个分页
 //上一页
 var nprev = (data.CurrentPage - 1 >= 1 ? data.CurrentPage - 1 : 1);
 pager.push(' <li class="paginate_button previous" aria-controls="dynamic-table" tabindex="0" id="dynamic-table_previous">');
 pager.push(' <a href="javascript:;" name="npager" data-page="' + nprev + '">上一页</a>');
 pager.push(' </li>');
 //当前页之前页码
 var preTotal = data.CurrentPage - nPager >= 1 ? data.CurrentPage - nPager : 1;
 for (var i = preTotal; i < data.CurrentPage ; i++) {
 pager.push(' <li class="paginate_button ' + (i == data.CurrentPage ? "active disabled" : "") + '" aria-controls="dynamic-table">');
 pager.push(' <a href="javascript:;" name="npager" data-page="' + i + '">' + i + '</a>');
 pager.push(' </li>');
 }
 //当前页
 pager.push(' <li class="paginate_button active disabled" aria-controls="dynamic-table">');
 pager.push(' <a href="javascript:;" name="npager" data-page="' + data.CurrentPage + '">' + data.CurrentPage + '</a>');
 pager.push(' </li>');
 //当前页以后页码
 var nextTotal = data.CurrentPage + nPager > data.PageTotal ? data.PageTotal : data.CurrentPage + nPager;
 for (var i = data.CurrentPage + 1; i <= nextTotal; i++) {
 pager.push(' <li class="paginate_button ' + (i == data.CurrentPage ? "active disabled" : "") + '" aria-controls="dynamic-table">');
 pager.push(' <a href="javascript:;" name="npager" data-page="' + i + '">' + i + '</a>');
 pager.push(' </li>');
 }
 //下一页
 var nnext = (data.PageTotal < data.CurrentPage + 1 ? data.PageTotal : data.CurrentPage + 1);
 pager.push(' <li class="paginate_button next" aria-controls="dynamic-table" tabindex="0" id="dynamic-table_next">');
 pager.push(' <a href="javascript:;" name="npager" data-page="' + nnext + '">下一页</a>');
 pager.push(' </li>');
 pager.push(' </ul>');
 //分页查询条件
 pager.push('<div style="display:none">');
 pager.push(' <form>');
 pager.push(' <input type="hidden" name="pageSize" value="' + defOption.pageSize + '"/>');
 pager.push(' <input type="hidden" name="currentPage" value="' + defOption.currentPage + '"/>');
 pager.push(' </form>');
 pager.push('</div>');
 pager.push('</div>');
 //移除加载中
 //head.html("");
 //添加结果
 head.html(rows.join(''));
 $("div[id='divPager']").html(pager.join(''));
 //操作按钮事件
 $("a[data-item]").on("click", function () {
 var data_Item = $(this).attr("data-item");
 if (data_Item) {
 var data_Item_Obj = JSON.parse(data_Item);
 defOption.modalExt.modalFun({
 width: data_Item_Obj.width,
 height: data_Item_Obj.height,
 url: data_Item_Obj.url,
 title: data_Item_Obj.title,
 callback: defOption.callback
 });
 }
 });
 //绑定分页按钮事件
 $("a[name='npager']").on("click", function () {
 var nPager = $(this).attr("data-page");
 if (nPager.length <= 0) { return; }
 $("form input[name='currentPage']").val(nPager);
 //执行请求后台
 ajaxFun(defOption);
 });
 } else {
 head.html("<tr><td class=\"text-center\" colspan=\"" + defOption.headText.length + "\">未能查询到数据!</td></tr>");
 $("div[id='divPager']").html("");
 }
 } else {
 head.html("<tr><td class=\"text-center\" colspan=\"" + defOption.headText.length + "\">未能查询到数据。</td></tr>");
 $("div[id='divPager']").html("");
 }
 } else {
 head.html("<tr><td class=\"text-center\" colspan=\"" + defOption.headText.length + "\">未能查询到数据</td></tr>");
 $("div[id='divPager']").html("");
 }
 };
 if (option) {
 $.extend(defOption, option);
 }
 //执行请求后台
 ajaxFun(defOption);
 }

这个方法体挺长的,主要操作是:

默认格式展示列表头部并呈现出加载中的提示=》绑定复选框全选事件=》创建数据返回成功函数sucFun()=》调用请求后台方法ajaxFun();

再来看函数sucFun()等到数据返回后执行的操作是:

遍历json返回数据展示到table中(其中包括了时间格式化的处理,复选框,label及操作按钮类型operate的初始化)=》页数展示及事件绑定(目前只有上一页,当前页之前页码,当前页,当前页以后页码,下一页的效果展示,分页查询条件(生成pagesize和currentPage隐藏控件),绑定分页按钮事件)

以上就是shenniu.pager.js整个插件内容,不多且清晰,感觉分享给大家挺高兴,下面贴出示例中用到的js文件和css文件可以在这里下载:http://xiazai.3water.com/201612/yuanma/shenniu.pager_3water.rar

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

Javascript 相关文章推荐
javascript 贪吃蛇实现代码
Nov 22 Javascript
JavaScript入门教程(1) 什么是JS
Jan 31 Javascript
通过继承IHttpHandle实现JS插件的组织与管理
Jul 13 Javascript
jquery购物车实时结算特效实现思路
Sep 23 Javascript
js实现绿白相间竖向网页百叶窗动画切换效果
Mar 02 Javascript
javascript实现详细时间提醒信息效果的方法
Mar 11 Javascript
Jquery操作cookie记住用户名
Mar 29 Javascript
JS实现购物车特效
Feb 02 Javascript
JavaScript函数节流和函数防抖之间的区别
Feb 15 Javascript
webpack写jquery插件的环境配置
Dec 21 jQuery
小程序图片长按识别功能的实现方法
Aug 30 Javascript
JavaScript find()方法及返回数据实例
Apr 30 Javascript
js继承实现方法详解
Dec 16 #Javascript
详解jQuery简单的表格应用
Dec 16 #Javascript
JS中parseInt()和map()用法分析
Dec 16 #Javascript
HTML5canvas 绘制一个圆环形的进度表示实例
Dec 16 #Javascript
JS数字千分位格式化实现方法总结
Dec 16 #Javascript
jquery插件锦集【推荐】
Dec 16 #Javascript
jQuery Easyui 下拉树组件combotree
Dec 16 #Javascript
You might like
如何在PHP中使用Oracle数据库(2)
2006/10/09 PHP
比较好用的PHP防注入漏洞过滤函数代码
2012/04/11 PHP
CI框架装载器Loader.php源码分析
2014/11/04 PHP
如何利用预加载优化Laravel Model查询详解
2017/08/11 PHP
PHP设计模式概论【概念、分类、原则等】
2020/05/01 PHP
jquery post方式传递多个参数值后台以数组的方式进行接收
2013/01/11 Javascript
js中事件的处理与浏览器对象示例介绍
2013/11/29 Javascript
详解JavaScript中undefined与null的区别
2014/03/29 Javascript
Angularjs基础知识及示例汇总
2015/01/22 Javascript
详细介绍jQuery.outerWidth() 函数具体用法
2015/07/20 Javascript
JS获取数组最大值、最小值及长度的方法
2015/11/24 Javascript
微信小程序 wxapp视图容器 view详解
2016/10/31 Javascript
从零开始学习Node.js系列教程三:图片上传和显示方法示例
2017/04/13 Javascript
Angular2环境搭建具体操作步骤(推荐)
2017/08/04 Javascript
Angular在模板驱动表单中自定义校验器的方法
2017/08/09 Javascript
Node.js使用Express.Router的方法
2017/11/14 Javascript
vue axios 表单提交上传图片的实例
2018/03/16 Javascript
基于Vue2-Calendar改进的日历组件(含中文使用说明)
2019/04/14 Javascript
Element MessageBox弹框的具体使用
2020/07/27 Javascript
Vue封装Axios请求和拦截器的步骤
2020/09/16 Javascript
jQuery实现tab栏切换效果
2020/12/22 jQuery
React中使用Vditor自定义图片详解
2020/12/25 Javascript
python模块之StringIO使用示例
2015/04/08 Python
Python中函数的多种格式和使用实例及小技巧
2015/04/13 Python
浅谈python 线程池threadpool之实现
2017/11/17 Python
Python二维数组实现求出3*3矩阵对角线元素的和示例
2019/11/29 Python
10张动图学会python循环与递归问题
2021/02/06 Python
python中使用asyncio实现异步IO实例分析
2021/02/26 Python
利用CSS3实现自定义滚动条代码分享
2016/08/18 HTML / CSS
节约用水演讲稿
2014/05/21 职场文书
大专生自荐书范文
2014/06/22 职场文书
上班时间打瞌睡检讨书
2014/09/26 职场文书
考研复习计划
2015/01/19 职场文书
市场部岗位职责范本
2015/04/15 职场文书
学前教育见习总结
2015/06/23 职场文书
mysql中between的边界,范围说明
2021/06/08 MySQL