jquery异步筛选搜索的详解

作者:袖梨 2022-06-25


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

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

第一阶段 - 变量

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

var 月薪 = null;
var 福利 = null;
var 地区 = null;

...

// 单选
$('月薪').on('click', function(){
// 让其他同级的类移除高亮className
// 给当前点击元素添加高亮className

// 让变量等于当前点击元素的参数
月薪 = $(thi).data('id');

// 发送请求
});

// 多选
$('福利').on('click', function(){
// 给当前点击元素toggle高亮className

// 查找当前元素所有的同级的高亮元素,并生成一个以参数为值的数组赋予变量
var ids = $(this).siblings('.高亮className').map(function(){
return $(this).data('id');
}).get().join(',');

福利 = ids;

// 发送请求
});

...

var 发送请求 = function(){
$.ajax({
...
data: {
福利: 福利,
月薪: 月薪,
...
}
});
}
在线demo

第二阶段 - 委托

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





var cache = {};
$('#J-demo').on('click', 'a', function(){
var 参数名 = $(this).data('param-name');
var 类型 = $(this).data('param-type');
if(类型 === '单选'){
cache[参数名] = $(this).data('value');
}

// 操作高亮的类
// 发送请求
});

var 请求 = function(){
$.ajax({
data: cache,
});
}
在线demo

第三阶段 - 插件化

当完成了第二阶段后,发现当筛选的条件越来越多,类型越来越多时,很不好处理,并且还会出现重复请求的bug(当在上一个请求还没有完成又点击触发下一个请求),于是我想把搜索+请求这块写一个公用的方法。。。

搜索插件(暂且这么叫吧)只提供设置数据,删除数据,获取数据,发送请求的功能,然后自己逻辑代码就可以写那些什么多选啊、单选啊、文本框啊、下拉什么的了,可是你会发现逻辑代码要远远的大于搜索插件的代码,是的,但起码思路比较明确了,谁只做谁的事~

完整的例子








搜索 - 插件化
css" href="./search.css">




名称(单选):



  • 默认

  • 百度

  • 360

  • 谷歌

  • 非死不可

  • 推特




排序(多选):



  • 默认

  • 时间

  • id

  • 名称




视图(单选):



  • 默认

  • 代码

  • 全屏

  • 测试




分页大小:


select name="" id="J-page_size">






后端返回多少条(模拟分页):




关键词:





快速跳页:









结果:


请点击...为了测试响应,故意让后端响应时间为1500ms



res.items = res.items || [];

if(res.items.length){
$.each(res.items, function(){
html += '

  • '+ this.index +''+ this.content +'
  • ';
    });

    if(XXOO.get('query')){
    html = html.replace(new RegExp(XXOO.get('query'), 'g'), function($0){
    return ''+ $0 +'';
    });
    }
    } else {
    html = '

  • 真空~
  • ';
    }

    return '

      '+ html + '
    ';
    }

    var renderPage = function(res){
    var page_size = parseInt(XXOO.get('page_size'), 10) || 10;
    var pageCount = Math.ceil(res.total / page_size);
    var page = parseInt(XXOO.get('page'), 10) || 1;
    var str = '';
    var i = 1;

    if (pageCount > 1 && page

    if (page > 1) {
    str += '';
    } else {
    str += '上一页';
    }

    if (pageCount for (i; i if (page === i) {
    str += '' + i + '';
    } else {
    str += '';
    }
    }
    } else {
    var start, end;
    if (page === 1) {
    str += '1';
    } else {
    str += '';
    }
    if (page > 4) {
    str += '...';
    }
    if (page start = 1;
    } else {
    start = page - 2;
    }

    if (page > (pageCount - 4)) {
    end = pageCount;
    } else {
    end = page + 3;
    }
    for (var i2 = start; i2 if (i2 !== 1 && i2 !== pageCount) { //避免重复输出1和最后一页
    if (i2 === page) {
    str += '' + i2 + '';
    } else {
    str += '';
    }
    }
    }
    if (page str += '...';
    }
    if (page === pageCount) {
    str += '' + pageCount + '';
    } else {
    str += '';
    }
    start = end = null;
    }

    if (page str += '';
    } else {
    str += '下一页';
    }


    str = '

    ' + str + '
    ';
    }

    return str;
    }

    var XXOO = new Search({
    url: '/api/search/index',
    success: function(res){
    var html = '';

    html += renderTpl(res);

    html += renderPage(res);

    $('#J-write').html(html);
    },
    error: function(){
    $('#J-write').text('出错了');
    },
    beforeSend: function(){
    $('.mask').stop().fadeIn();
    },
    complete: function(){
    $('.mask').stop().fadeOut();
    }

    });

    // 单选
    $('.J-param').on('click', 'li', function(){
    var id = $(this).data('id');
    var type = $(this).data('type');

    $(this).addClass('current').siblings().removeClass('current');

    if(!id){
    XXOO.del(type);
    } else {
    XXOO.set(type, id);
    }

    XXOO.request();
    });

    // 多选
    $('.J-params').on('click', 'li', function(){
    var id = $(this).data('id');
    var type = $(this).data('type');
    var ids;

    // 处理是否点击的默认,如果是默认则清除其他的
    // 不是默认
    if(id){
    $(this).toggleClass('current');
    ids = $(this).parent().children('.current').map(function(){
    return $(this).data('id');
    }).get().join(',');

    // 如果一个高亮的标签也没有
    if(!ids){
    $(this).parent().children().eq(0).addClass('current');
    XXOO.del(type);
    } else {
    $(this).parent().children().eq(0).removeClass('current');
    XXOO.set(type, ids);
    }
    } else {
    XXOO.del(type);
    $(this).addClass('current').siblings().removeClass('current');
    }

    XXOO.request();
    });

    // 分页大小
    $('#J-page_size').on('change', function(){
    XXOO.set('page_size', this.value).set('page', 1).request();
    });

    // 总数
    $('#J-total').on('change', function(){
    XXOO.set('total', this.value).set('page', 1).request();
    });

    // 关键词
    $('#J-query').on('blur', function(){
    XXOO.set('query', this.value);
    });

    // 搜索
    $('#J-btn').on('click', function(){
    XXOO.request();
    });

    // 分页
    $('#J-write').on('click', '.ui-page a', function(){
    XXOO.set('page', this.getAttribute('data-page')).request();
    return false;
    });

    // 快速跳页
    var $quickPage = $('#J-quick-page');
    $('#J-quick-btn').on('click', function(){
    var value = $quickPage.val();
    if(!value){
    $quickPage.focus();
    } else if(!/^d+$/.test(value)){
    $quickPage.focus().select();
    } else {
    value = parseInt(value, 10) || 1;
    XXOO.set('page', value).request();
    }
    });


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

    相关文章

    精彩推荐