A-A+

jquery异步筛选搜索的详解

2016年01月12日 web前端设计 暂无评论 阅读 6 views 次

jquery异步筛选就是通过ajax来实现数据异步传输了,这个问题与ajax用户验证与注册是一样的原理了,只不过搜索会带有条件的,具体如下。

异步筛选搜索(下面简称搜索)是使用ajax发送搜索请求,可追回多个条件,应用的场景很多,比如:百度招聘,逻辑是只有在用户点击相关条件时触发重新请求,只请求内容,从而可以减少http请求和流量。

比如要完成上面百度招聘的搜索功能,先从简单的入手吧~

第一阶段 - 变量

思路是使用js记录下相应的几个变量,然后给元素绑定点击事件,并写入相关的变量,然后发送请求,发送请求的时候带上这些变量,如:

  1. var 月薪 = null;  
  2. var 福利 = null;  
  3. var 地区 = null;  
  4. ...  
  5. // 单选  
  6. $('月薪').on('click', function(){  
  7.     // 让其他同级的类移除高亮className  
  8.     // 给当前点击元素添加高亮className  
  9.     // 让变量等于当前点击元素的参数  
  10.     月薪 = $(thi).data('id');  
  11.     // 发送请求  
  12. });  
  13. // 多选  
  14. $('福利').on('click', function(){  
  15.     // 给当前点击元素toggle高亮className  
  16.     // 查找当前元素所有的同级的高亮元素,并生成一个以参数为值的数组赋予变量  
  17.     var ids = $(this).siblings('.高亮className').map(function(){  
  18.         return $(this).data('id');  
  19.     }).get().join(',');  
  20.     福利 = ids;  
  21.     // 发送请求  
  22. });  
  23. ...  
  24. var 发送请求 = function(){  
  25.     $.ajax({  
  26.         ...  
  27.         data: {  
  28.             福利: 福利,  
  29.             月薪: 月薪,  
  30.             ...  
  31.         }  
  32.     });  
  33. }  

在线demo

第二阶段 - 委托

在第一阶段的基础上考虑到委托事件,声明一个缓存对象cache用来存放异步请求时的数据,给所有筛选条件的可点击元素添加data-param-name=参数名用来写入缓存的key,添加data-param-type用来控制选择的类型,比如单选、多选等,添加data-value为选中值,这样就可以写委托了,比如:

  1. <div id="J-demo">  
  2.     <a href="#" data-value="1000" data-param-name="月薪" data-param-type="单选">1000元</a>  
  3.     <a href="#" data-value="2000" data-param-name="月薪" data-param-type="单选">2000元</a>  
  4. </div>  
  5. var cache = {};  
  6. $('#J-demo').on('click', 'a', function(){  
  7.     var 参数名 = $(this).data('param-name');  
  8.     var 类型 = $(this).data('param-type');  
  9.     if(类型 === '单选'){  
  10.         cache[参数名] = $(this).data('value');    
  11.     }  
  12.     // 操作高亮的类  
  13.     // 发送请求  
  14. });  
  15. var 请求 = function(){  
  16.     $.ajax({  
  17.         data: cache,  
  18.     });  
  19. }  

在线demo

第三阶段 - 插件化

当完成了第二阶段后,发现当筛选的条件越来越多,类型越来越多时,很不好处理,并且还会出现重复请求的bug(当在上一个请求还没有完成又点击触发下一个请求),于是我想把搜索+请求这块写一个公用的方法。。。
搜索插件(暂且这么叫吧)只提供设置数据,删除数据,获取数据,发送请求的功能,然后自己逻辑代码就可以写那些什么多选啊、单选啊、文本框啊、下拉什么的了,可是你会发现逻辑代码要远远的大于搜索插件的代码,是的,但起码思路比较明确了,谁只做谁的事~

完整的例子:

  1. <!DOCTYPE html>  
  2. <html>  
  3. <head>  
  4. <meta charset="UTF-8">  
  5. <meta name="renderer" content="webkit">  
  6. <meta http-equiv="X-UA-Compatible" content="IE=edge">  
  7. <title>搜索 - 插件化</title>  
  8. <link rel="stylesheet" type="text/css" href="./search.css">  
  9. <style type="text/css">  
  10.     .mask-wrap{  
  11.         position: relative;   
  12.         padding: 20px;   
  13.     }  
  14.     .mask{  
  15.         position: absolute;   
  16.         left: 0; top: 0;   
  17.         width: 100%;   
  18.         background: rgba(255,255,255,0.6) url('//github.xuexb.com/static/img/loading-32-32.gif') no-repeat center center;   
  19.         height: 100%;   
  20.         display: none;   
  21.     }  
  22.     .ui-page{  
  23.         font-size: 0;  
  24.         line-height: 24px;  
  25.         padding-top: 10px;   
  26.     }  
  27.     .ui-page a,  
  28.     .ui-page span{  
  29.         display: inline-block;   
  30.         font-size: 12px;   
  31.         padding: 0 10px;   
  32.         border: 1px solid  #ccc;   
  33.         margin-left: 8px;   
  34.         text-decoration: none;   
  35.     }  
  36.     .ui-page a:first-child{  
  37.         margin-left: 0;   
  38.     }  
  39.     .ui-page a:hover,  
  40.     .ui-page .current{  
  41.         background-color: #09f;   
  42.         border-color: #09f;   
  43.         color: #fff;   
  44.     }  
  45.     .ui-page .disabled{  
  46.         background-color: #ccc;   
  47.         color: #999;   
  48.         border-color: #ccc;   
  49.     }  
  50.     .ui-list li{  
  51.         border-top: 1px solid  #ddd;   
  52.         padding: 10px 0;   
  53.     }  
  54.     .ui-list li:first-child{  
  55.         border-top: none;   
  56.     }  
  57.     .ui-list-index{  
  58.         display: inline-block;   
  59.         background-color: #ccc;   
  60.         color: #333;   
  61.         padding: 0 4px;   
  62.          height: 16px; line-height: 16px; text-align: center;   
  63.         font-size: 12px;   
  64.         margin-right: 8px;   
  65.         vertical-align: middle;   
  66.     }  
  67.     #J-btn{  
  68.         display: inline-block;   
  69.         width: 100px;   
  70.         height: 30px;   
  71.         color: #fff;   
  72.         background-color: #09f;   
  73.         border: none;   
  74.         margin-top: 30px;   
  75.     }  
  76. </style>  
  77. </head>  
  78. <body>  
  79.     <div id="J-demo">  
  80.         <dl>  
  81.             <dt>  
  82.                 名称(单选):  
  83.             </dt>  
  84.             <dd>  
  85.                 <ul class="J-param">  
  86.                     <li data-type="name" class="current">默认</li>  
  87.                     <li data-type="name" data-id="baidu">百度</li>  
  88.                     <li data-type="name" data-id="360">360</li>  
  89.                     <li data-type="name" data-id="google">谷歌</li>  
  90.                     <li data-type="name" data-id="facebook">非死不可</li>  
  91.                     <li data-type="name" data-id="facebook">推特</li>  
  92.                 </ul>  
  93.             </dd>  
  94.             <dt>  
  95.                 排序(多选):  
  96.             </dt>  
  97.             <dd>  
  98.                 <ul class="J-params">  
  99.                     <li data-type="order" class="current">默认</li>  
  100.                     <li data-type="order" data-id="time">时间</li>  
  101.                     <li data-type="order" data-id="id">id</li>  
  102.                     <li data-type="order" data-id="name">名称</li>  
  103.                 </ul>  
  104.             </dd>  
  105.             <dt>  
  106.                 视图(单选):  
  107.             </dt>  
  108.             <dd>  
  109.                 <ul class="J-param">  
  110.                     <li data-type="view" class="current">默认</li>  
  111.                     <li data-type="view" data-id="code">代码</li>  
  112.                     <li data-type="view" data-id="full">全屏</li>  
  113.                     <li data-type="view" data-id="test">测试</li>  
  114.                 </ul>  
  115.             </dd>  
  116.             <dt>  
  117.                 分页大小:  
  118.             </dt>  
  119.             <dd>  
  120.                 <select name="" id="J-page_size">  
  121.                     <option value="10" selected>10条</option>  
  122.                     <option value="20">20条</option>  
  123.                     <option value="30">30条</option>  
  124.                     <option value="46">46条</option>  
  125.                 </select>  
  126.             </dd>  
  127.             <dt>  
  128.                 后端返回多少条(模拟分页):  
  129.             </dt>  
  130.             <dd>  
  131.                 <select name="" id="J-total">  
  132.                     <option value="100" selected>100条</option>  
  133.                     <option value="200">200条</option>  
  134.                     <option value="300">300条</option>  
  135.                     <option value="518">518条</option>  
  136.                 </select>  
  137.             </dd>  
  138.             <dt>  
  139.                 关键词:  
  140.             </dt>  
  141.             <dd>  
  142.                 <input type="text" id="J-query">  
  143.             </dd>  
  144.               
  145.             <dt>快速跳页:</dt>  
  146.             <dd>  
  147.                 <input type="text" id="J-quick-page"><button id="J-quick-btn">跳转</button>  
  148.             </dd>  
  149.             <dd>  
  150.                 <button id="J-btn">搜索</button>  
  151.             </dd>  
  152.         </dl>  
  153.     </div>  
  154.     <hr>  
  155.     <h2>结果:</h2>  
  156.     <div class="mask-wrap">  
  157.         <div id="J-write">请点击...为了测试响应,故意让后端响应时间为1500ms</div>  
  158.         <div class="mask"></div>  
  159.     </div>  
  160.   
  161.     <script type="text/javascript" src="//code.jquery.com/jquery-1.11.3.js"></script>  
  162.     <script type="text/javascript" src="search.js"></script>  
  163.     <script type="text/javascript">  
  164.         var renderTpl = function(res){  
  165.             var html = '';  
  166.             resres.items = res.items || [];  
  167.             if(res.items.length){  
  168.                 $.each(res.items, function(){  
  169.                     html += '<li><span class="ui-list-index">'+ this.index +'</span>'+ this.content +'</li>';  
  170.                 });  
  171.                 if(XXOO.get('query')){  
  172.                     htmlhtml = html.replace(new RegExp(XXOO.get('query'), 'g'), function($0){  
  173.                         return '<mark>'+ $0 +'</mark>';  
  174.                     });  
  175.                 }  
  176.             } else {  
  177.                 html = '<li>真空~</li>';  
  178.             }  
  179.             return '<ul class="ui-list">'+ html + '</ul>';  
  180.         }  
  181.         var renderPage = function(res){  
  182.             var page_size = parseInt(XXOO.get('page_size'), 10) || 10;  
  183.             var pageCount = Math.ceil(res.total / page_size);  
  184.             var page = parseInt(XXOO.get('page'), 10) || 1;  
  185.             var str = '';  
  186.             var i = 1;  
  187.             if (pageCount > 1 && page <= pageCount) {  
  188.                 if (page > 1) {  
  189.                     str += '<a href="#" data-page="' + (page - 1) + '">上一页</a>';  
  190.                 } else {  
  191.                     str += '<span class="disabled">上一页</span>';  
  192.                 }  
  193.                 if (pageCount < 7) {  
  194.                     for (i; i <= pageCount; i++) {  
  195.                         if (page === i) {  
  196.                             str += '<span class="current">' + i + '</span>';  
  197.                         } else {  
  198.                             str += '<a href="#" data-page="' + (i) + '">' + i + '</a>';  
  199.                         }  
  200.                     }  
  201.                 } else {  
  202.                     var start, end;  
  203.                     if (page === 1) {  
  204.                         str += '<span class="current">1</span>';  
  205.                     } else {  
  206.                         str += '<a href="#" data-page="' + (1) + '">1</a>';  
  207.                     }  
  208.                     if (page > 4) {  
  209.                         str += '<span class="dot">...</span>';  
  210.                     }  
  211.                     if (page < 5) {  
  212.                         start = 1;  
  213.                     } else {  
  214.                         start = page - 2;  
  215.                     }  
  216.                     if (page > (pageCount - 4)) {  
  217.                         end = pageCount;  
  218.                     } else {  
  219.                         end = page + 3;  
  220.                     }  
  221.                     for (var i2 = start; i2 < end; i2++) {  
  222.                         if (i2 !== 1 && i2 !== pageCount) { //避免重复输出1和最后一页  
  223.                             if (i2 === page) {  
  224.                                 str += '<span class="current">' + i2 + '</span>';  
  225.                             } else {  
  226.                                 str += '<a href="#" data-page="' + (i2) + '">' + i2 + '</a>';  
  227.                             }  
  228.                         }  
  229.                     }  
  230.                     if (page < (pageCount - 4)) {  
  231.                         str += '<span class="dot">...</span>';  
  232.                     }  
  233.                     if (page === pageCount) {  
  234.                         str += '<span class="current">' + pageCount + '</span>';  
  235.                     } else {  
  236.                         str += '<a href="#" data-page="' + (pageCount) + '">' + pageCount + '</a>';  
  237.                     }  
  238.                     start = end = null;  
  239.                 }  
  240.                 if (page < pageCount) {  
  241.                     str += '<a href="#" data-page="' + (page + 1) + '">下一页</a>';  
  242.                 } else {  
  243.                     str += '<span class="disabled">下一页</span>';  
  244.                 }  
  245.   
  246.                 str = '<div class="ui-page">' + str + '</div>';  
  247.             }  
  248.             return str;  
  249.         }  
  250.         var XXOO = new Search({  
  251.             url: '/api/search/index',  
  252.             success: function(res){  
  253.                 var html = '';  
  254.                 html += renderTpl(res);  
  255.                 html += renderPage(res);  
  256.                 $('#J-write').html(html);  
  257.             },  
  258.             error: function(){  
  259.                 $('#J-write').text('出错了');  
  260.             },  
  261.             beforeSend: function(){  
  262.                 $('.mask').stop().fadeIn();  
  263.             },  
  264.             complete: function(){  
  265.                 $('.mask').stop().fadeOut();  
  266.             }  
  267.         });  
  268.         // 单选  
  269.         $('.J-param').on('click', 'li', function(){  
  270.             var id = $(this).data('id');  
  271.             var type = $(this).data('type');  
  272.             $(this).addClass('current').siblings().removeClass('current');  
  273.             if(!id){  
  274.                 XXOO.del(type);  
  275.             } else {  
  276.                 XXOO.set(type, id);  
  277.             }  
  278.             XXOO.request();  
  279.         });  
  280.         // 多选  
  281.         $('.J-params').on('click', 'li', function(){  
  282.             var id = $(this).data('id');  
  283.             var type = $(this).data('type');  
  284.             var ids;  
  285.             // 处理是否点击的默认,如果是默认则清除其他的  
  286.             // 不是默认  
  287.             if(id){  
  288.                 $(this).toggleClass('current');  
  289.                 ids = $(this).parent().children('.current').map(function(){  
  290.                     return $(this).data('id');  
  291.                 }).get().join(',');  
  292.                 // 如果一个高亮的标签也没有  
  293.                 if(!ids){  
  294.                     $(this).parent().children().eq(0).addClass('current');  
  295.                     XXOO.del(type);  
  296.                 } else {  
  297.                     $(this).parent().children().eq(0).removeClass('current');  
  298.                     XXOO.set(type, ids);  
  299.                 }  
  300.             } else {  
  301.                 XXOO.del(type);  
  302.                 $(this).addClass('current').siblings().removeClass('current');  
  303.             }  
  304.             XXOO.request();  
  305.         });  
  306.         // 分页大小  
  307.         $('#J-page_size').on('change', function(){  
  308.             XXOO.set('page_size', this.value).set('page', 1).request();  
  309.         });  
  310.         // 总数  
  311.         $('#J-total').on('change', function(){  
  312.             XXOO.set('total', this.value).set('page', 1).request();  
  313.         });  
  314.         // 关键词  
  315.         $('#J-query').on('blur', function(){  
  316.             XXOO.set('query', this.value);  
  317.         });  
  318.         // 搜索  
  319.         $('#J-btn').on('click', function(){  
  320.             XXOO.request();  
  321.         });  
  322.         // 分页  
  323.         $('#J-write').on('click', '.ui-page a', function(){  
  324.             XXOO.set('page', this.getAttribute('data-page')).request();  
  325.             return false;  
  326.         });  
  327.         // 快速跳页  
  328.         var $quickPage = $('#J-quick-page');  
  329.         $('#J-quick-btn').on('click', function(){  
  330.             var value = $quickPage.val();  
  331.             if(!value){  
  332.                 $quickPage.focus();  
  333.             } else if(!/^\d+$/.test(value)){  
  334.                 $quickPage.focus().select();  
  335.             } else {  
  336.                 value = parseInt(value, 10) || 1;  
  337.                 XXOO.set('page', value).request();  
  338.             }  
  339.         });  
  340.     </script>  
  341. </body>  
  342. </html>  

上面没有提供php处理脚本这个非常的简单就不介绍了。

标签:

给我留言