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上去了。结果和上面一样的。

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

  • 相关阅读:
    hadoop再次集群搭建(3)-如何选择相应的hadoop版本
    48. Rotate Image
    352. Data Stream as Disjoint Interval
    163. Missing Ranges
    228. Summary Ranges
    147. Insertion Sort List
    324. Wiggle Sort II
    215. Kth Largest Element in an Array
    快速排序
    280. Wiggle Sort
  • 原文地址:https://www.cnblogs.com/tengri/p/5668347.html
Copyright © 2011-2022 走看看