美文网首页JavaScript前端那些事儿Web前端之路
2017百度前端技术学院-自定义右键菜单

2017百度前端技术学院-自定义右键菜单

作者: 起这么长的名字根本没有用 | 来源:发表于2017-02-24 19:48 被阅读1368次

    效果预览
    源码地址

    一、事件流

    1、冒泡

    • 什么是事件冒泡
      官方的定义就是从最特定的事件目标到最不特定的事件目标。
      意思就是说,假如用户单击了一个元素,该元素拥有一个click事件,那么同样的事件也将会被它的祖先触发,这个事件从该元素开始一直冒泡到DOM树的最上层,这一过程称为事件冒泡

    示例:

    html:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>自定义右键菜单</title>
    </head>
    <body>
        <ul id='menu'>
            <li>menu item 1</li>
            <li>menu item 2</li>
        </ul>
    </body>
    </html>
    

    js

    document.oncontextmenu =function (){
        alert('触发了);
    }
    

    效果

    2、捕获

    • 什么是事件捕获
      事件捕获和事件是相反的,也就是说,当用户触发了一个事件的时候,这个事件是从DOM树的最上层开始触发一直到捕获到事件源.

    标准的监听事件方式(标准浏览器都可使用,IE9以上)

        element.addEventListener(eventType, fn, false) 
    
    说明:
    • 第一个参数: eventType:事件类型
    • 第二个参数:fn 触发的回调函数
    • 第三个参数:一个布尔值,表示冒泡还是捕获。false表示冒泡,true表示捕获

    IE下的监听事件方式(IE专有)

    ·attachEvent(eventType,fn)· IE专有。

    说明:

    此种监听方式只有冒泡没有捕获。

    注意:
    • 标准监听方式不需加on
         document.addEventlistener('contextmenu',function (){
         alert('我是标准的我不需要on')
       },false)
    
    • IE监听事件方式必须加on
        document.attachEvent('oncontextmenu',function(){
                 alert('我是IE的我需要on')
        })
    

    一般使用标准即可,如果兼容IE 8以下再考虑第二种,做兼容方式的书写。

    二、oncontextmenu

    属于鼠标事件,鼠标右键点击即触发。

    用法:

    我在document上绑定了此事件,通过事件冒泡机制触发。

    document.oncontextmenu =function (){
        alert('触发了);
    }
    

    3、事件对象event

    概念:

    Event 对象代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态。
    事件通常与函数结合使用,函数不会在事件发生前被执行

    • 标准浏览器中作为事件回调函数的第一个参数
            document.addEventlistener('contextmenu',function(ev){
                 alert(ev)
        })
    
    • 低版本的IE作为window对象的一个属性
            document.attachEvent('onc ontextmenu',function(){
                 alert(window.event)
        })
    

    一般如果不兼容ie 8以下,用标准下的event即可

    4、取消默认行为

    event.preventDefault()

    5、阻止冒泡

    event.stopPropagation()

    说明:

    return false既可以阻止默认行为,也可以阻止冒泡

    6、获取滚动距离

    • chrome:

    document.body.scrollTop(scrollLeft)

    • 非chrome:

    document.documentElement.scrollTop(scrollLeft)

    • 兼容写法:
          var scrollTop = document.documentElement.scrollTop||document.body.scrollTop,
            var scrollLeft = document.documentElement.scrollLeft||document.body.scrollLeft,
    

    7、clientX(Y)

    它提供事件发生时的应用客户端区域的水平坐标 (与页面坐标不同)。例如,当你点击客户端区域的左上角时,鼠标事件的 clientX 值为 0 ,这一值与页面是否有水平滚动无关

    也就是说到浏览器可视窗口的距离(不包括浏览器的工具栏)

    8、 获取元素具体尺寸

    • offsetHeight/offsetWidth

    通常,元素的offsetHeight是一种衡量标准,包括元素的边框、垂直(水平)内边距和元素的水平(垂直)滚动条(如果存在且渲染的话)和元素的CSS高度(宽度)

    注意:

    clientWidth/clientHeight的区别是,`clientWidth/clientHeight 不包括边框,和垂直(水平)滚动条的宽度(高度)

    9、获取浏览器视口的尺寸

        var   browserHeight = document.documentElement.clientHeight,//浏览器视口的高度
                        browserWidth = document.documentElement.clientWidth; 
    
    注意:

    一开始使用了window.innerWidth/window.innerHeight 来获取视口尺寸,结果在极限情况下被滚动条覆盖一部分,后来找到原因是:window.innerWidth/window.innerHeight 是把滚动条也算在内的

    10、类数组转换成数组

    Array.prototype.slice.call(类数组,0)

    11、自定义右键菜单实现思路

    1、让自定义菜单相对于浏览器视口做绝对定位通过改变left/top值来改变每次菜单的位置
    2、取消原来的右键菜单默认行为
    3、考虑极限情况,判断event.clientX+菜单的offsetWidth/event.clientY+offsetHeight是否大于等于 document.documentElement.clientWidth/document.documemtElement.clientHeight ,如果大于等于,则把left/top赋值为event.clientX-菜单的offsetWidth/event.clientY-菜单的offsetHeight,否则赋值为event.clientX/event.clientY

    js代码:
        window.onload = function (){
      var oClick = document.getElementById('click_region'),
          oMenu = document.getElementById('menu'),
          aLi = oMenu.getElementsByTagName('li'),
          browserHeight = document.documentElement.clientHeight,//浏览器视口的高度
          browserWidth = document.documentElement.clientWidth; //浏览器视口的快读,不包括垂直滚动天的宽度
    
      document.oncontextmenu = function (ev){
        oMenu.style.display = 'block';
        var ev = ev||window.event,
            scrollTop = document.documentElement.scrollTop||document.body.scrollTop,
            scrollLeft = document.documentElement.scrollLeft||document.body.scrollLeft,
            clientX = ev.clientX,
            clientY = ev.clientY,
            // 注意:只有在隐藏的元素变成display:block的状态才能获取他的宽度和高度
            offsetWidth = oMenu.offsetWidth,
            offsetHeight = oMenu.offsetHeight,
            top,
            left;
    
        if(clientY+offsetHeight>=browserHeight){
           top = clientY-offsetHeight
        }else{
          top = clientY
        }
    
        if(clientX+offsetWidth>=browserWidth){
          left = clientX-offsetWidth
          console.log(left);
        }else{
          left = clientX
        }
    
        oMenu.style.left = left+'px';
        oMenu.style.top =scrollTop+top+'px';
        return false//阻止默认行为,并且阻止冒泡
      }
    
      // 取消自定义菜单
      document.onclick = function (){
          oMenu.style.display = 'none';
      }
    
        var lis = Array.prototype.slice.call(aLi,0); //类数组转成数组
    
    
        //遍历数组
        lis.forEach(function (item,index,arr){
          aLi[index].onclick = function (event){
            alert(this.innerHTML)
             event.stopPropagation();
          }
        })
    
    }
    

    相关文章

      网友评论

      • _理想的现实主义者:你这极限值判断的是不是有点问题,稍微解释一下:relieved:
        _理想的现实主义者:@起这么长的名字根本没有用 没,是我自己刚才没理解,等我改天自己照着敲敲
        起这么长的名字根本没有用:@馒头家的花卷 哦不好意思,我后来代码改了,文中用了innerWidth …我代码是对的,上面说明有点问题我改一下哈。上一条评论回复那个也是对的
        起这么长的名字根本没有用:鼠标坐标和元素真实大小相加的和与浏览器可见视口做比较,如果大于了就换方向。 如有不对,请指教

      本文标题:2017百度前端技术学院-自定义右键菜单

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