前端獲取元素定位位置的法寶


box chrome

在前端開發中,我們經常需要定位一個元素。如tooltip、popover或者modal等,或許是我們需要將它們定位在依賴元素的周圍或屏幕滾動屏幕中心位置。這對於前端開發的碼農來說並不是難事。算出和依賴元素的offset,設置元素的left、right。對於稍復雜的場景我們可能需要考慮被positioned的祖先元素。

但往往不是所有的事情都是這么簡單的。筆者最新在項目開發中就遇見這樣一個問題:這里的HTML是嵌入的,其來自jpedal商業軟件從PDF文件自動生成的;為了展示的樣式,jpedal統一使用了 position:absolute和relative來定位PDF元素。然而由於業務的需求,我們需要操作這類HTML。其中一個需求就是需要在每段文字附近顯示操作工具條。

對於這類未知的DOM定位,那么我們就需要遍歷它的DOM樹來計算它的相對位置了。行為下面的這段代碼:

    function isStaticPositioned(element) {
      return (getStyle(element, 'position') || 'static' ) === 'static';
    }

    var parentOffsetEl = function(element) {
      var docDomEl = $document[0];
      var offsetParent = element.offsetParent || docDomEl;
      while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent) ) {
        offsetParent = offsetParent.offsetParent;
      }
      return offsetParent || docDomEl;
    };

在這里,我們會根據元素遞歸查詢它所在的的DOM樹中被positioned的最接近的祖先元素,然后才計算它們的相對位置。

這是一段來自Angular-UI bootstrap的$position服務的源碼。這也是本文將要提到的獲取定位元素位置的法寶。其源碼位置在https://github.com/angular-ui/bootstrap/blob/master/src/position/position.js

在$position服務中為我們提供了3個有用的位置服務:position、offset和positionElements。position是計算具體元素的定位位置,返回一個帶有width、height、top、left的對象;positionElements則是返回某元素相對於其依賴容器元素的定位位置,一個帶有top、left的對象。

筆者為了測試這寫API,在jsbin中寫了一個特定的指令:

JavaScript:

angular.module("com.ngbook.demo", ['ui.bootstrap.position'])
.directive('position', ['$position', function($position){
    return {
        restrict: 'EA',
        templateUrl: '/position.html',
        scope:{
            title:"@"
        },
        link:function(scope, elm, iAttrs){
        scope.data =  $position.position(elm);
       }
    };
}]);

HTML:

<script type="text/ng-template" id="/position.html">
   <table class="table">
       <thead>
           <th colspan="2">{{title}}</th>
       </thead>
    <tbody>
       <tr ng-repeat="field in ['width', 'height', 'left', 'top']">
       <td>{{field}}</td>
       <td>{{data[field]}}</td>
     </tr>
    </tbody>
   </table>
 </script>

所以我們可以如下測試這類API:

<position title ="no positioned parent"></position>

<div style="position: relative;padding:50px;">
    <position title ="relative parent"></position>

     <div style="position: absolute;top:250px; padding:50px;">
         <position title="relative->absolute parent"></position>
     </div>
 </div>

 <div style="position: absolute;top:0px;left:250px; padding:50px;">
         <position title="absolute parent"></position>
 </div>

其效果可以在jsbin demo:

$position demo

同樣你也可以在官方的文檔中看見對它的測試: https://github.com/angular-ui/bootstrap/blob/master/src/position/test/test.html

簡單的說:如果我們需要獲取某個元素的定位信息,則我們可以用 $position.position(element);獲取相對於固定元素的定位,則可以使用$position.positionElements(hostEl, targetEl, positionStr, appendToBody)。其中positionStr是一個橫向和縱向的字符串,如:”top-left”、”bottom-left”。其默認值為center。如筆者項目所期望的在某文字段落的左上角顯示工具條:

$position.after($toolbar);
var elPosition = $position.positionElements($paragraph, $toolbar, “top-left”);
$toolbar.css({left: elPosition.left + 'px', top: elPosition.top + 'px'});

當然也不要忘記為toolbar元素設置position: absolute;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM