美文网首页
电商菜单去抖技术(debounce技术)

电商菜单去抖技术(debounce技术)

作者: 郝特么冷 | 来源:发表于2018-09-26 16:28 被阅读67次

目的: 实现下图的效果.

效果展示
京东.PNG
  • 基本思路
    左边创建一个列表
    右边创建响应的弹出框
    鼠标给到mouseenter事件对应的展示右边的弹出框
代码如下:

HTML代码:

<div class="section" id="news">
    <!--菜单-->
    <div class="menu">
        <ul>
            <li class="item_top" data-id="item"><a href="javascript:void(0);"><i class="icon"></i><span>行业分类</span></a></li>
            <li data-id="item1"><a href="javascript:void(0);"><i class="icon"></i><span>工业机械</span></a></li>
            <li data-id="item2"><a href="javascript:void(0);"><i class="icon"></i><span>洗衣机</span></a></li>
            <li data-id="item3"><a href="javascript:void(0);"><i class="icon"></i><span>家用电器</span></a></li>
            <li data-id="item4"><a href="javascript:void(0);"><i class="icon"></i><span>工业</span></a></li>
            <li data-id="item5"><a href="javascript:void(0);"><i class="icon"></i><span>化工</span></a></li>
            <li data-id="item6"><a href="javascript:void(0);"><i class="icon"></i><span>电动车</span></a></li>
            <li data-id="item7"><a href="javascript:void(0);"><i class="icon"></i><span>洗衣机</span></a></li>
            <li data-id="item8"><a href="javascript:void(0);"><i class="icon"></i><span>工程</span></a></li>
            <li class="item_bottom" data-id="item"><a href="javascript:void(0);"><i class="icon"></i><span>定制</span></a></li>
        </ul>
        <!--弹出框-->
        <div class="menu_pop">
            <!--排序a-z-->
            <div class="industy_sort"></div>
            <a href=""><i class="icon multiple"></i></a>
            <!--模块切换-->
            <div class="industy_part" id="part_item1">0</div>
            <div class="industy_part" id="part_item2">1</div>
            <div class="industy_part" id="part_item3">2</div>
            <div class="industy_part" id="part_item4">3</div>
            <div class="industy_part" id="part_item5">4</div>
            <div class="industy_part" id="part_item6">5</div>
            <div class="industy_part" id="part_item7">6</div>
            <div class="industy_part" id="part_item8">7</div>
            <!--多选的时候下面的确定按钮-->
            <div class="confirm"> </div>
            <!--行业专家-->
            <div class="industy_people" id="people_item1">0</div>
            <div class="industy_people" id="people_item2">1</div>
            <div class="industy_people" id="people_item3">2</div>
            <div class="industy_people" id="people_item4">3</div>
            <div class="industy_people" id="people_item5">4</div>
            <div class="industy_people" id="people_item6">5</div>
            <div class="industy_people" id="people_item7">6</div>
            <div class="industy_people" id="people_item8">7</div>
        </div>
    </div>
    <div class="right_wrap">
        
    </div>
</div>

CSS代码:

#news{
    background: #ffffff;
    width: 100%;
    max-width: 1024px;
    margin: auto;
    position: relative;
    z-index: 2;
    margin-top: -5px;
}

/*左侧菜单模块*/
#news>.menu{
    width: 180px;
    display: inline-block;
    box-sizing: border-box;
    position: relative;
    box-shadow: 2px 2px 6px 2px rgb(0,0,0);
    box-shadow: 2px 2px 6px 2px rgba(0,0,0,0.08);
    -webkit-box-shadow: 2px 2px 6px 2px rgba(0,0,0,0.08);
}

#news>.menu>ul{
    width: 100%;
}

#news>.menu>ul li{
    padding-left: 14px;
    line-height: 56px;
    height: 56px;
}

#news>.menu>ul li.active{
    background: #F03800;
}

#news>.menu>ul li.active a{
    text-decoration: none;
}

#news>.menu>ul li.active a span{
    color: #FFFFFF;
}

#news>.menu>ul li a{
    display: block;
    padding-left: 3px;
    border-bottom: 1px solid #F0F0F0;
    width: 100%;
}

#news>.menu>ul li a i {
    display: inline-block;
    width: 15px;
    height: 18px;
    vertical-align: middle;
    margin-right: 15px; 
    background: red;
}

#news>.menu li.item_top{
    line-height: 50px;
    height: 50px;
    
}

#news>.msg_menu>ul li a span{
    color: #666666;
    font-size: 18px;
    max-width: 130px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: inline-block;
    vertical-align: middle;
}

#news>.menu>.menu_pop{
    width: 850px;
    height: 555px;
    background: #FFFFFF;
    position: absolute;
    left: 181px;
    top: 0px;
    z-index: 5;
    box-shadow: 0px 0px 12px 6px rgba(0,0,0,0.1);
    overflow: hidden;
    border-bottom-left-radius: 10px;
    border-bottom-right-radius: 10px;
    display: none;
}

/*#news>.menu>.menu_pop.active{*/
    /*display: block;*/
    /*visibility: visible;*/
/*}*/

#news>.menu>.menu_pop>.industy_part,
#news>.menu>.menu_pop>.industy_people{
    display: none;
}

#news>.menu>.menu_pop>.industy_part.active {
    display: block;
}

#news>.menu>.menu_pop>.industy_people.active {
    display: block;
}

问题1
当我们想将鼠标移入到右侧菜单中,鼠标必须保持在当前的小块中,否则就会造成右侧的弹出框改变。用户在使用的时候经常会出现鼠标不小心移入了其他的模块,导致右边展示内容变化,得不到用户希望的结果。

  • 解决方法

我们利用setTimeout这个函数来给一个延迟,这里我给的是300毫秒。延迟判断鼠标的位置,这样即便用户移入到左侧菜单的其他模块中短时间内也不会影响右侧菜单的展示。

问题2
如果我们给到了延迟,延迟也会给我们造成一些问题,如果用户并不打算往右侧的菜单中移入,只是想简单的切换左侧菜单的选项,我们给出延迟函数就会造成右侧弹出框的延迟展示,严重影响用户的体验。

  • 解决办法

这里我们引出了去抖技术,这个也是目前电商网站普遍运用的技术之一。

去抖技术

什么是去抖技术?
我个人的理解就是通过对用户可能做的行为进行预测,合理运用setTimeout这个函数,进而做出不同的处理,最大程度的提高用户体验度。
下面我就拿我做的项目举例:
下面是我们需要展示给用户的菜单。


jd.PNG
用户行为判断:
  1. 用户可能要从当前菜单移入到具体的弹出菜单。
  2. 用户打算切换当前菜单。
  • 情况1分析
jd1.png

用户当前的鼠标是A点,如果用户希望切换到右侧菜单那么用户鼠标的移动轨迹必定会经过三角形ABC,也就是说鼠标的下一个点一定会在三角形内部。就如同上图,我们假设下一个点是P点。那么我们就可以说只要P在三角形ABC内部那么用户目的就是为了切换到右侧菜单。此时我们给用户延迟,避免切换菜单时候造成问题。

  • 情况2分析
    如果用户想切换左边的菜单选项,那么用户鼠标移入的方向主要是上下移动,绝对不会朝着右侧移动,所以我们可以判断如果P不在三角形ABC内部时候,那么用户目的是切换左侧选项。

所以说判断P点在不在三角形ABC内部就显得很关键。
我们这里用到了大学的判断方法,即通过向量判断,如果向量PA、向量PB的叉乘和向量PB、向量PC的叉乘以及向量PC、向量PA的叉乘最后的符号是否一致,如果符号一致那么说明P点在三角形内部。

下面是具体代码:

//向量
function vector(a,b) {
    return {
        x: b.x - a.x,
        y: b.y - a.y
    }
}
//向量的叉乘
function vectorProductor(v1,v2) {
    var res = v1.x*v2.y-v2.x*v1.y;
    return res;
}
//判断P是否在三角形ABC内部
function isPointInTrangle(p,a,b,c) {
    var pa = vector(p, a);
    var pb = vector(p, b);
    var pc = vector(p, c);

    var t1 = vectorProductor(pa, pb);
    var t2 = vectorProductor(pb, pc);
    var t3 = vectorProductor(pc, pa);

    return sameSign(t1, t2) && sameSign(t2, t3);
}

//判断符号是否相同
function sameSign(a,b) {
    return (a ^ b) >= 0
}

最后把代码整合一下就是最终的JS代码

//这里运用了debounce技术来处理菜单的移入移出问题
$(document).ready(function() {
    var activeRow,
        activeMenu,
        activeIndusty,
        timer,
        mouseInSub = false,
        mouseTrack = [],
        moveHandler;

    $(".menu_pop").mouseenter(function () {
        mouseInSub = true;
    }).mouseleave(function () {
        mouseInSub = false;
    });

    moveHandler = function(e) {
        mouseTrack.push({
            x: e.pageX,
            y: e.pageY
        })

        if (mouseTrack.length > 3) {
            mouseTrack.shift();
        }
    }


    $(".menu").mouseenter(function () {
        $(".menu_pop").show();
        $(document).bind('mousemove',moveHandler);
    }).mouseleave(function () {
        $(".menu_pop").hide();

        if (activeRow) {
            activeRow.removeClass('active');
            activeRow = null;
        }

        if (activeMenu) {
            activeMenu.hide();
            activeMenu = null;
        }

        if (activeIndusty) {
            activeIndusty.hide();
            activeIndusty = null;
        }

        $(document).unbind('mousemove',moveHandler);//解绑
    })

    $(".menu ul li").mouseenter(function () {
        if (!activeRow) {
            activeRow = $(this).addClass("active");
            activeMenu = $('#part_' + $(this).attr("data-id"));
            activeIndusty = $("#people_" + $(this).attr("data-id"));
            activeMenu.show();
            activeIndusty.show();
            return;
        }

        var that = $(this);

        if (timer) {
            clearTimeout(timer);
        }

        var currMousePos = mouseTrack[mouseTrack.length - 1];
        var leftCorner = mouseTrack[mouseTrack.length - 2];
        var delay = needDelay($(".menu_pop"),leftCorner,currMousePos);

        if (delay) {
            timer = setTimeout(function () {

                if (mouseInSub) {
                    return;//如果在子菜单中立即返回
                }

                activeRow.removeClass('active');
                activeMenu.hide();
                activeIndusty.hide();

                activeRow = that;
                activeRow.addClass('active');
                activeMenu = $('#part_' + that.attr("data-id"));
                activeMenu.show();
                activeIndusty = $("#people_" + that.attr("data-id"));
                activeIndusty.show();
            },300);
        } else {
            var preActiveRow = activeRow;
            var preActiveMenu = activeMenu;
            var preActiveIndusty = activeIndusty;

            activeRow = that;
            activeMenu = $('#part_' + that.attr("data-id"));
            activeIndusty = $("#people_" + that.attr("data-id"));

            preActiveRow.removeClass('active');
            preActiveMenu.hide();
            preActiveIndusty.hide();

            activeRow.addClass('active');
            activeMenu.show();
            activeIndusty.show();
        }

    });




});

//向量
function vector(a,b) {
    return {
        x: b.x - a.x,
        y: b.y - a.y
    }
}
//向量的叉乘
function vectorProductor(v1,v2) {
    var res = v1.x*v2.y-v2.x*v1.y;
    return res;
}

function isPointInTrangle(p,a,b,c) {
    var pa = vector(p, a);
    var pb = vector(p, b);
    var pc = vector(p, c);

    var t1 = vectorProductor(pa, pb);
    var t2 = vectorProductor(pb, pc);
    var t3 = vectorProductor(pc, pa);

    return sameSign(t1, t2) && sameSign(t2, t3);
}

//判断符号是否相同
function sameSign(a,b) {
    return (a ^ b) >= 0
}

//是否需要延迟
function needDelay(elem,leftCorner,currMousePos) {
    var offset = elem.offset();
    var leftCorner = leftCorner;
    var currMousePos = currMousePos;

    var topLeft = {
        x: offset.left,
        y: offset.top
    }

    var bottomLeft = {
        x: offset.left,
        y: offset.top + elem.height()
    }

    return isPointInTrangle(currMousePos,leftCorner,topLeft,bottomLeft);
}

相关文章

  • 电商菜单去抖技术(debounce技术)

    目的: 实现下图的效果. 效果展示 基本思路左边创建一个列表右边创建响应的弹出框鼠标给到mouseenter事件...

  • 节流与防抖

    使用防抖和节流技术的意义:节约资源,提升用户体验。 防抖(debounce) 防抖:触发高频事件后n秒内函数只会执...

  • 2019-01-03

    想想也是,如果搞电商培训的,如果他们把电商技术,搞的麻溜溜的,哪个还需要开培训班来赚钱啊, 他们的电商技术,我们也...

  • throttle-debounce

    函数节流 throttle 和 函数 去抖 debounce 下载 npm i throttle-debounce...

  • JavaScript防抖和节流

    前言 debounce(防抖)和throttle(节流)是两个相似的技术,都是为了减少一个函数无用的触发次数,以便...

  • 觅宝首页改版解决方案-- - 草稿

    以溯源技术支持的电商平台首页设计,主要特点是产品溯源,主要功能是电商服务,主要合作对象是品控市场。 用溯源技术为电...

  • 千万级调用量微服务架构实践

    作者:黄哲铿,著有《技术管理之巅》,前1号店技术总监、海尔农业电商CTO来自:养码场 微服务架构在大型电商中的运用...

  • 防抖和节流的理解以及应用场景

    Debounce and Throttle 防抖和节流是两种类似的技术,用于控制函数在一段时间内的执行次数。 De...

  • js函数防抖与函数节流

    1.函数防抖(debounce) 函数防抖,debounce。其概念其实是从机械开关和继电器的“去弹跳”(debo...

  • 美团网现任技术委员会主席对于美团架构从技术细节分享

    很多人认为,电商都没有什么技术含量,电商没有什么门槛,入门的门槛并不高,电商很痛苦,需要不停地去扫街,不停地去拜访...

网友评论

      本文标题:电商菜单去抖技术(debounce技术)

      本文链接:https://www.haomeiwen.com/subject/eqfjoftx.html