zoukankan      html  css  js  c++  java
  • 弹出控件的位置该如何计算?

          近段时间在写组件,页面有一个输入框,点击输入框,弹出一个国家控件或者是城市控件。但是这个控件的位置该如何放一直是一个头疼的问题。可能是开始没有沉下心来想,总觉得这是个技术难题,还在网上和群里 向很多高手请教,他们给出的答案也并不是我想要的。最后不得不自己想想该如何解决这个问题了,现在把自己的一些思考写出来,一来防止忘记,二来也算个分享。

    思路:

    前提条件:只能拿到一个输入框对象。

    1、position的取值:absolute、relative和fixed三种。relative是相对定位,很明显不适合,因为在实际操作中,根本不确定input是否有父节点,以及父节点的定位是什么,那么相对定位,相对的对象是不可知的,所以可以排除relative。其次是固定定位fixed,这个也是不可行的。举个简单的例子,如果把控件定位到(100,100)的位置,那么如果有滚动条,该控件不会跟着页面滚动,要是还是不明白,想想博客园页面上回到顶部的功能就应该明白了。

    2、经过以上思考,至少可以确定,控件的position一定是absolute了,那么它的left值和top值该怎么计算呢?肯定要先从input输入框入手。

    3、由于在开发中用的jquery库,那么首先想到的就是$.offset()方法,查看API得知,offset是用于设置或返回当前匹配元素相对于当前文档的偏移,也就是相对于当前文档的坐标,说白了就是获取当前元素的绝对位置。且该位置是相对于当前文档(页面)的。既然是这样,控件的left就应该是当前元素的left值,控件的top就应该是当前元素的top值加上当前元素的自身高度了。为了验证,立马写了一个例子:

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title></title>
        <script type="text/javascript" src="demo/jquery-1.9.1.js" ></script>
        <style type="text/css">
            .layer{width:400px; height:300px; background:red;position: absolute;}
        </style>
        </head>
        <body style="height:2000px;">
            <input type="text" id="input1" placeholder="请选择 "  style="margin-top:100px;" onclick="addLayer();"/>
        </body>
    </html>
    <script type="text/javascript">
        function addLayer(){
            var pointer = $("#input1").offset();
            var $div = $("<div class='layer'></div>");
            $div.css({left:pointer.left, top:pointer.top+$("#input1").height()});
            $("body").append($div);
        }
    </script>

    运行正常,也不会随着滚动条的变动而变动位置,很不错。

    4、然而由于我的整个项目是用的angular的路由来控制的,左边是导航,右边是内容区,发现异常了,控件和input输入框分离了,找了半天原因,也没找到,开始怀疑自己写的控件有问题,亦或计算位置的思路不正确?纠结了半天,没找到问题的原因,最后不得不用那万能的排除法了。

    5、怎么排除呢?首先在网上找了一个日历控件(My97 datepicker),引用进来,发现还是存在这个问题。非常开心,看来不是控件写的有问题,那到底是啥原因呢?继续找。。。。。

    6、然后各种实验,最后终于找到原因了:滚动条的问题,如果不是body的滚动条或者是iframe的滚动条,就会遇到这个问题。其实沉下心来想想,很容易就想通,因为offset是根据document计算的相对偏移量,虽然input框所在的区域包含滚动条,但是这个滚动条不是属于document的,所以在滚动的时候,input会随着走,而控件始终留在相对于document的位置。另外,input会跟着动,是因为input并不是根据document来定位的。也就是说,我控件的位置是根据input相对于document的偏移量来获取的,但是并不代表input的位置就是按照这个偏移量来设置的。

     1 <!DOCTYPE html>
     2 <html>
     3     <head>
     4         <meta charset="UTF-8">
     5         <title></title>
     6     <script type="text/javascript" src="demo/jquery-1.9.1.js" ></script>
     7     <style type="text/css">
     8         .layer{width:400px; height:300px; background:red;position: absolute;}
     9         .wrap{height:500px;overflow: auto;}
    10         .inner{height:1000px;}
    11     </style>
    12     </head>
    13     <body style="height:2000px;">
    14         <div class="wrap">
    15             <div class="inner">
    16                     <input type="text" id="input1" placeholder="请选择 "  style="margin-top:100px;" onclick="addLayer();"/>
    17             </div>
    18         </div>
    19     </body>
    20 </html>
    21 <script type="text/javascript">
    22     function addLayer(){
    23         var pointer = $("#input1").offset();
    24         var $div = $("<div class='layer'></div>");
    25         $div.css({left:pointer.left, top:pointer.top+$("#input1").height()});
    26         $("body").append($div);
    27     }
    28 </script>

    7、看来这个问题真是没办法解决了,真的没有办法呢?不死心,接着想。。。。。

    8、一不小心,又发现了jquery的position()方法,那就用这个方法试试,思路是先用position()方法获取input相对父元素的偏移量,然后给控件设置位置。另外用递归查找input的所有父元素中第一个position为relative的的父元素,把控件append上去。实验表明,如果input的父节点直接是relative的,没有问题,但是要是input的所有父节点都没有,最后还是找到body上去了。结果和上面一样的。

    最后结论:最初的方法应该就是正确的方法。所以有时候真的没有必要把问题想的太复杂了,否则进入死巷子出不来。

  • 相关阅读:
    随机图片
    单页网站
    最安全的聊天工具——Cryptocat
    一个游戏——小黑屋
    SAO Utils – SAO风格启动菜单
    对话框实现
    抖动文字
    Leetcode: 22. Generate Parentheses
    Leetcode: 21. Merge Two Sorted Lists
    Leetcode: 20. Valid Parentheses
  • 原文地址:https://www.cnblogs.com/tengri/p/5668347.html
Copyright © 2011-2022 走看看